diff --git a/dialect/sql/builder_test.go b/dialect/sql/builder_test.go index e0545e852..f640fe5a0 100644 --- a/dialect/sql/builder_test.go +++ b/dialect/sql/builder_test.go @@ -1711,8 +1711,8 @@ func TestInsert_OnConflict(t *testing.T) { t.Run("Postgres", func(t *testing.T) { // And SQLite. query, args := Dialect(dialect.Postgres). Insert("users"). - Columns("id", "email"). - Values("1", "user@example.com"). + Columns("id", "email", "creation_time"). + Values("1", "user@example.com", 1633279231). OnConflict( ConflictColumns("email"), ConflictWhere(EQ("name", "Ariel")), @@ -1720,13 +1720,14 @@ func TestInsert_OnConflict(t *testing.T) { // Update all new values excepts id field. ResolveWith(func(u *UpdateSet) { u.SetIgnore("id") + u.SetIgnore("creation_time") u.Add("version", 1) }), UpdateWhere(NEQ("updated_at", 0)), ). Query() - require.Equal(t, `INSERT INTO "users" ("id", "email") VALUES ($1, $2) ON CONFLICT ("email") WHERE "name" = $3 DO UPDATE SET "id" = "users"."id", "email" = "excluded"."email", "version" = COALESCE("users"."version", 0) + $4 WHERE "updated_at" <> $5`, query) - require.Equal(t, []interface{}{"1", "user@example.com", "Ariel", 1, 0}, args) + require.Equal(t, `INSERT INTO "users" ("id", "email", "creation_time") VALUES ($1, $2, $3) ON CONFLICT ("email") WHERE "name" = $4 DO UPDATE SET "id" = "users"."id", "email" = "excluded"."email", "creation_time" = "users"."creation_time", "version" = COALESCE("users"."version", 0) + $5 WHERE "updated_at" <> $6`, query) + require.Equal(t, []interface{}{"1", "user@example.com", 1633279231, "Ariel", 1, 0}, args) query, args = Dialect(dialect.Postgres). Insert("users"). diff --git a/entc/gen/bench_test.go b/entc/gen/bench_test.go index bf3cd9bce..cafd6e983 100644 --- a/entc/gen/bench_test.go +++ b/entc/gen/bench_test.go @@ -16,7 +16,6 @@ import ( ) func BenchmarkGraph_Gen(b *testing.B) { - b.ReportAllocs() target := filepath.Join(os.TempDir(), "ent") require.NoError(b, os.MkdirAll(target, os.ModePerm), "creating tmpdir") defer os.RemoveAll(target) diff --git a/entc/gen/template/dialect/sql/feature/upsert.tmpl b/entc/gen/template/dialect/sql/feature/upsert.tmpl index 12bf12b3f..210ccd17e 100644 --- a/entc/gen/template/dialect/sql/feature/upsert.tmpl +++ b/entc/gen/template/dialect/sql/feature/upsert.tmpl @@ -143,7 +143,7 @@ type ( {{ end }} -// UpdateNewValues updates the fields using the new values that were set on create{{ if $.ID.UserDefined }} except the ID field{{ end }}. +// UpdateNewValues updates the mutable fields using the new values that were set on create{{ if $.ID.UserDefined }} except the ID field{{ end }}. // Using this option is equivalent to using: // // client.{{ $.Name }}.Create(). @@ -159,11 +159,18 @@ type ( // func (u *{{ $upsertOne }}) UpdateNewValues() *{{ $upsertOne }} { u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) - {{- if $.ID.UserDefined }} + {{- if or $.ID.UserDefined $.ImmutableFields }} u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { - if _, exists := u.create.mutation.ID(); exists { - s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }}) - } + {{- if $.ID.UserDefined }} + if _, exists := u.create.mutation.ID(); exists { + s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }}) + } + {{- end }} + {{- range $f := $.ImmutableFields }} + if _, exists := u.create.mutation.{{ $f.MutationGet }}(); exists { + s.SetIgnore({{ $.Package }}.{{ $f.Constant }}) + } + {{- end }} })) {{- end }} return u @@ -306,7 +313,7 @@ type {{ $upsertBulk }} struct { } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.{{ $.Name }}.Create(). @@ -322,13 +329,20 @@ type {{ $upsertBulk }} struct { // func (u *{{ $upsertBulk }}) UpdateNewValues() *{{ $upsertBulk }} { u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) - {{- if $.ID.UserDefined }} + {{- if or $.ID.UserDefined $.ImmutableFields }} u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { for _, b := range u.create.builders { - if _, exists := b.mutation.ID(); exists { - s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }}) - return - } + {{- if $.ID.UserDefined }} + if _, exists := b.mutation.ID(); exists { + s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }}) + return + } + {{- end }} + {{- range $f := $.ImmutableFields }} + if _, exists := b.mutation.{{ $f.MutationGet }}(); exists { + s.SetIgnore({{ $.Package }}.{{ $f.Constant }}) + } + {{- end }} } })) {{- end }} @@ -429,4 +443,4 @@ func (u *{{ $upsertBulk }}) ExecX(ctx context.Context) { } {{ end }} {{ end }} -{{ end }} \ No newline at end of file +{{ end }} diff --git a/entc/gen/type.go b/entc/gen/type.go index cd8d51493..97ca9e1d5 100644 --- a/entc/gen/type.go +++ b/entc/gen/type.go @@ -459,6 +459,17 @@ func (t Type) MutableFields() []*Field { return fields } +// ImmutableFields returns all type fields that are immutable (for update). +func (t Type) ImmutableFields() []*Field { + fields := make([]*Field, 0, len(t.Fields)) + for _, f := range t.Fields { + if f.Immutable { + fields = append(fields, f) + } + } + return fields +} + // MutationFields returns all the fields that are available on the typed-mutation. func (t Type) MutationFields() []*Field { fields := make([]*Field, 0, len(t.Fields)) @@ -864,7 +875,7 @@ func (f Field) UpdateDefaultName() string { return "Update" + f.DefaultName() } func (f Field) DefaultValue() interface{} { return f.def.DefaultValue } // DefaultFunc returns a bool stating if the default value is a func. Invoked by the template. -func (f Field) DefaultFunc() interface{} { return f.def.DefaultKind == reflect.Func } +func (f Field) DefaultFunc() bool { return f.def.DefaultKind == reflect.Func } // BuilderField returns the struct member of the field in the builder. func (f Field) BuilderField() string { diff --git a/entc/integration/customid/ent/blob_create.go b/entc/integration/customid/ent/blob_create.go index 1cd183f65..e7d1ccfbd 100644 --- a/entc/integration/customid/ent/blob_create.go +++ b/entc/integration/customid/ent/blob_create.go @@ -352,7 +352,7 @@ func (u *BlobUpsert) AddCount(v int) *BlobUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Blob.Create(). @@ -600,7 +600,7 @@ type BlobUpsertBulk struct { create *BlobCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Blob.Create(). diff --git a/entc/integration/customid/ent/car_create.go b/entc/integration/customid/ent/car_create.go index 8e3200707..0e6255ec6 100644 --- a/entc/integration/customid/ent/car_create.go +++ b/entc/integration/customid/ent/car_create.go @@ -365,7 +365,7 @@ func (u *CarUpsert) UpdateModel() *CarUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Car.Create(). @@ -646,7 +646,7 @@ type CarUpsertBulk struct { create *CarCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Car.Create(). diff --git a/entc/integration/customid/ent/device_create.go b/entc/integration/customid/ent/device_create.go index 964f06965..de2cc85e8 100644 --- a/entc/integration/customid/ent/device_create.go +++ b/entc/integration/customid/ent/device_create.go @@ -272,7 +272,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Device.Create(). @@ -480,7 +480,7 @@ type DeviceUpsertBulk struct { create *DeviceCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Device.Create(). diff --git a/entc/integration/customid/ent/doc_create.go b/entc/integration/customid/ent/doc_create.go index 284fdc836..429523fd4 100644 --- a/entc/integration/customid/ent/doc_create.go +++ b/entc/integration/customid/ent/doc_create.go @@ -325,7 +325,7 @@ func (u *DocUpsert) ClearText() *DocUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Doc.Create(). @@ -559,7 +559,7 @@ type DocUpsertBulk struct { create *DocCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Doc.Create(). diff --git a/entc/integration/customid/ent/group_create.go b/entc/integration/customid/ent/group_create.go index 767095fca..39fa4a172 100644 --- a/entc/integration/customid/ent/group_create.go +++ b/entc/integration/customid/ent/group_create.go @@ -218,7 +218,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Group.Create(). @@ -424,7 +424,7 @@ type GroupUpsertBulk struct { create *GroupCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Group.Create(). diff --git a/entc/integration/customid/ent/mixinid_create.go b/entc/integration/customid/ent/mixinid_create.go index 56d5d6012..6ba4117d0 100644 --- a/entc/integration/customid/ent/mixinid_create.go +++ b/entc/integration/customid/ent/mixinid_create.go @@ -257,7 +257,7 @@ func (u *MixinIDUpsert) UpdateMixinField() *MixinIDUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.MixinID.Create(). @@ -498,7 +498,7 @@ type MixinIDUpsertBulk struct { create *MixinIDCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.MixinID.Create(). diff --git a/entc/integration/customid/ent/note_create.go b/entc/integration/customid/ent/note_create.go index d5e09dde2..1fc2018ad 100644 --- a/entc/integration/customid/ent/note_create.go +++ b/entc/integration/customid/ent/note_create.go @@ -325,7 +325,7 @@ func (u *NoteUpsert) ClearText() *NoteUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Note.Create(). @@ -559,7 +559,7 @@ type NoteUpsertBulk struct { create *NoteCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Note.Create(). diff --git a/entc/integration/customid/ent/pet_create.go b/entc/integration/customid/ent/pet_create.go index f6df07b9a..ebf9360c1 100644 --- a/entc/integration/customid/ent/pet_create.go +++ b/entc/integration/customid/ent/pet_create.go @@ -353,7 +353,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Pet.Create(). @@ -561,7 +561,7 @@ type PetUpsertBulk struct { create *PetCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Pet.Create(). diff --git a/entc/integration/customid/ent/session_create.go b/entc/integration/customid/ent/session_create.go index 288eb4223..063bbb19b 100644 --- a/entc/integration/customid/ent/session_create.go +++ b/entc/integration/customid/ent/session_create.go @@ -238,7 +238,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Session.Create(). @@ -446,7 +446,7 @@ type SessionUpsertBulk struct { create *SessionCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Session.Create(). diff --git a/entc/integration/customid/ent/user_create.go b/entc/integration/customid/ent/user_create.go index 9d1cd9127..44a65336a 100644 --- a/entc/integration/customid/ent/user_create.go +++ b/entc/integration/customid/ent/user_create.go @@ -326,7 +326,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.User.Create(). @@ -532,7 +532,7 @@ type UserUpsertBulk struct { create *UserCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.User.Create(). diff --git a/entc/integration/ent/card_create.go b/entc/integration/ent/card_create.go index cf0ea4713..5d193bd6e 100644 --- a/entc/integration/ent/card_create.go +++ b/entc/integration/ent/card_create.go @@ -466,7 +466,7 @@ func (u *CardUpsert) ClearName() *CardUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Card.Create(). @@ -477,6 +477,14 @@ func (u *CardUpsert) ClearName() *CardUpsert { // func (u *CardUpsertOne) UpdateNewValues() *CardUpsertOne { u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + if _, exists := u.create.mutation.CreateTime(); exists { + s.SetIgnore(card.FieldCreateTime) + } + if _, exists := u.create.mutation.Number(); exists { + s.SetIgnore(card.FieldNumber) + } + })) return u } @@ -754,7 +762,7 @@ type CardUpsertBulk struct { create *CardCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Card.Create(). @@ -765,6 +773,16 @@ type CardUpsertBulk struct { // func (u *CardUpsertBulk) UpdateNewValues() *CardUpsertBulk { u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + for _, b := range u.create.builders { + if _, exists := b.mutation.CreateTime(); exists { + s.SetIgnore(card.FieldCreateTime) + } + if _, exists := b.mutation.Number(); exists { + s.SetIgnore(card.FieldNumber) + } + } + })) return u } diff --git a/entc/integration/ent/card_update.go b/entc/integration/ent/card_update.go index 6045e00d6..27c28a9ae 100644 --- a/entc/integration/ent/card_update.go +++ b/entc/integration/ent/card_update.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" @@ -33,6 +34,12 @@ func (cu *CardUpdate) Where(ps ...predicate.Card) *CardUpdate { return cu } +// SetUpdateTime sets the "update_time" field. +func (cu *CardUpdate) SetUpdateTime(t time.Time) *CardUpdate { + cu.mutation.SetUpdateTime(t) + return cu +} + // SetBalance sets the "balance" field. func (cu *CardUpdate) SetBalance(f float64) *CardUpdate { cu.mutation.ResetBalance() @@ -379,6 +386,12 @@ type CardUpdateOne struct { mutation *CardMutation } +// SetUpdateTime sets the "update_time" field. +func (cuo *CardUpdateOne) SetUpdateTime(t time.Time) *CardUpdateOne { + cuo.mutation.SetUpdateTime(t) + return cuo +} + // SetBalance sets the "balance" field. func (cuo *CardUpdateOne) SetBalance(f float64) *CardUpdateOne { cuo.mutation.ResetBalance() diff --git a/entc/integration/ent/comment_create.go b/entc/integration/ent/comment_create.go index 39ddcadde..b4cb9b907 100644 --- a/entc/integration/ent/comment_create.go +++ b/entc/integration/ent/comment_create.go @@ -293,7 +293,7 @@ func (u *CommentUpsert) ClearNillableInt() *CommentUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Comment.Create(). @@ -566,7 +566,7 @@ type CommentUpsertBulk struct { create *CommentCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Comment.Create(). diff --git a/entc/integration/ent/fieldtype_create.go b/entc/integration/ent/fieldtype_create.go index d32314658..02f271c34 100644 --- a/entc/integration/ent/fieldtype_create.go +++ b/entc/integration/ent/fieldtype_create.go @@ -2781,7 +2781,7 @@ func (u *FieldTypeUpsert) ClearPasswordOther() *FieldTypeUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.FieldType.Create(). @@ -4455,7 +4455,7 @@ type FieldTypeUpsertBulk struct { create *FieldTypeCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.FieldType.Create(). diff --git a/entc/integration/ent/file_create.go b/entc/integration/ent/file_create.go index 459e848e7..a500a928f 100644 --- a/entc/integration/ent/file_create.go +++ b/entc/integration/ent/file_create.go @@ -498,7 +498,7 @@ func (u *FileUpsert) ClearOp() *FileUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.File.Create(). @@ -800,7 +800,7 @@ type FileUpsertBulk struct { create *FileCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.File.Create(). diff --git a/entc/integration/ent/filetype_create.go b/entc/integration/ent/filetype_create.go index 5fee89ecd..3b3f1a8b4 100644 --- a/entc/integration/ent/filetype_create.go +++ b/entc/integration/ent/filetype_create.go @@ -338,7 +338,7 @@ func (u *FileTypeUpsert) UpdateState() *FileTypeUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.FileType.Create(). @@ -584,7 +584,7 @@ type FileTypeUpsertBulk struct { create *FileTypeCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.FileType.Create(). diff --git a/entc/integration/ent/goods_create.go b/entc/integration/ent/goods_create.go index 34c3e67f6..d8945b849 100644 --- a/entc/integration/ent/goods_create.go +++ b/entc/integration/ent/goods_create.go @@ -171,7 +171,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Goods.Create(). @@ -369,7 +369,7 @@ type GoodsUpsertBulk struct { create *GoodsCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Goods.Create(). diff --git a/entc/integration/ent/group_create.go b/entc/integration/ent/group_create.go index a160b8649..b295a3771 100644 --- a/entc/integration/ent/group_create.go +++ b/entc/integration/ent/group_create.go @@ -526,7 +526,7 @@ func (u *GroupUpsert) UpdateName() *GroupUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Group.Create(). @@ -821,7 +821,7 @@ type GroupUpsertBulk struct { create *GroupCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Group.Create(). diff --git a/entc/integration/ent/groupinfo_create.go b/entc/integration/ent/groupinfo_create.go index 57f52740a..ba5a43530 100644 --- a/entc/integration/ent/groupinfo_create.go +++ b/entc/integration/ent/groupinfo_create.go @@ -293,7 +293,7 @@ func (u *GroupInfoUpsert) AddMaxUsers(v int) *GroupInfoUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.GroupInfo.Create(). @@ -532,7 +532,7 @@ type GroupInfoUpsertBulk struct { create *GroupInfoCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.GroupInfo.Create(). diff --git a/entc/integration/ent/item_create.go b/entc/integration/ent/item_create.go index a4c777732..c5c23be3a 100644 --- a/entc/integration/ent/item_create.go +++ b/entc/integration/ent/item_create.go @@ -256,7 +256,7 @@ func (u *ItemUpsert) ClearText() *ItemUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create except the ID field. +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // // client.Item.Create(). @@ -490,7 +490,7 @@ type ItemUpsertBulk struct { create *ItemCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Item.Create(). diff --git a/entc/integration/ent/migrate/schema.go b/entc/integration/ent/migrate/schema.go index 68198cbb0..863b0fc18 100644 --- a/entc/integration/ent/migrate/schema.go +++ b/entc/integration/ent/migrate/schema.go @@ -44,7 +44,7 @@ var ( }, { Name: "card_number", - Unique: false, + Unique: true, Columns: []*schema.Column{CardsColumns[4]}, }, { diff --git a/entc/integration/ent/node_create.go b/entc/integration/ent/node_create.go index 2f7a074e6..823d99d7f 100644 --- a/entc/integration/ent/node_create.go +++ b/entc/integration/ent/node_create.go @@ -300,7 +300,7 @@ func (u *NodeUpsert) ClearValue() *NodeUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Node.Create(). @@ -531,7 +531,7 @@ type NodeUpsertBulk struct { create *NodeCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Node.Create(). diff --git a/entc/integration/ent/pet_create.go b/entc/integration/ent/pet_create.go index c5869fd7f..986ae236d 100644 --- a/entc/integration/ent/pet_create.go +++ b/entc/integration/ent/pet_create.go @@ -410,7 +410,7 @@ func (u *PetUpsert) ClearNickname() *PetUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Pet.Create(). @@ -691,7 +691,7 @@ type PetUpsertBulk struct { create *PetCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Pet.Create(). diff --git a/entc/integration/ent/schema/card.go b/entc/integration/ent/schema/card.go index 7228a05b6..3952aaeea 100644 --- a/entc/integration/ent/schema/card.go +++ b/entc/integration/ent/schema/card.go @@ -94,7 +94,8 @@ func (Card) Edges() []ent.Edge { func (Card) Indexes() []ent.Index { return []ent.Index{ index.Fields("id"), - index.Fields("number"), + index.Fields("number"). + Unique(), index.Fields("id", "name", "number"), } } diff --git a/entc/integration/ent/spec_create.go b/entc/integration/ent/spec_create.go index 032d9b693..cecc5dc8d 100644 --- a/entc/integration/ent/spec_create.go +++ b/entc/integration/ent/spec_create.go @@ -206,7 +206,7 @@ type ( } ) -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Spec.Create(). @@ -404,7 +404,7 @@ type SpecUpsertBulk struct { create *SpecCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Spec.Create(). diff --git a/entc/integration/ent/task_create.go b/entc/integration/ent/task_create.go index c4d9a2b23..80aa322b2 100644 --- a/entc/integration/ent/task_create.go +++ b/entc/integration/ent/task_create.go @@ -235,7 +235,7 @@ func (u *TaskUpsert) AddPriority(v schema.Priority) *TaskUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.Task.Create(). @@ -460,7 +460,7 @@ type TaskUpsertBulk struct { create *TaskCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.Task.Create(). diff --git a/entc/integration/ent/user_create.go b/entc/integration/ent/user_create.go index 195af5e68..4d6d472fb 100644 --- a/entc/integration/ent/user_create.go +++ b/entc/integration/ent/user_create.go @@ -1030,7 +1030,7 @@ func (u *UserUpsert) ClearSSOCert() *UserUpsert { return u } -// UpdateNewValues updates the fields using the new values that were set on create. +// UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // // client.User.Create(). @@ -1444,7 +1444,7 @@ type UserUpsertBulk struct { create *UserCreateBulk } -// UpdateNewValues updates the fields using the new values that +// UpdateNewValues updates the mutable fields using the new values that // were set on create. Using this option is equivalent to using: // // client.User.Create(). diff --git a/entc/integration/gremlin/ent/card_update.go b/entc/integration/gremlin/ent/card_update.go index bac38b81b..08e0b622b 100644 --- a/entc/integration/gremlin/ent/card_update.go +++ b/entc/integration/gremlin/ent/card_update.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/gremlin" "entgo.io/ent/dialect/gremlin/graph/dsl" @@ -35,6 +36,12 @@ func (cu *CardUpdate) Where(ps ...predicate.Card) *CardUpdate { return cu } +// SetUpdateTime sets the "update_time" field. +func (cu *CardUpdate) SetUpdateTime(t time.Time) *CardUpdate { + cu.mutation.SetUpdateTime(t) + return cu +} + // SetBalance sets the "balance" field. func (cu *CardUpdate) SetBalance(f float64) *CardUpdate { cu.mutation.ResetBalance() @@ -309,6 +316,12 @@ type CardUpdateOne struct { mutation *CardMutation } +// SetUpdateTime sets the "update_time" field. +func (cuo *CardUpdateOne) SetUpdateTime(t time.Time) *CardUpdateOne { + cuo.mutation.SetUpdateTime(t) + return cuo +} + // SetBalance sets the "balance" field. func (cuo *CardUpdateOne) SetBalance(f float64) *CardUpdateOne { cuo.mutation.ResetBalance() diff --git a/entc/integration/integration_test.go b/entc/integration/integration_test.go index 4c0c51106..3a0b3ec18 100644 --- a/entc/integration/integration_test.go +++ b/entc/integration/integration_test.go @@ -23,6 +23,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/entc/integration/ent" + "entgo.io/ent/entc/integration/ent/card" "entgo.io/ent/entc/integration/ent/enttest" "entgo.io/ent/entc/integration/ent/file" "entgo.io/ent/entc/integration/ent/filetype" @@ -367,6 +368,20 @@ func Upsert(t *testing.T, client *ent.Client) { ExecX(ctx) require.Equal(t, bid, client.Item.Query().OnlyIDX(ctx)) } + + c1 := client.Card.Create(). + SetNumber("102030"). + SetCreateTime(time.Unix(1623279251, 0)). + SetUpdateTime(time.Unix(1623279251, 0)). + SaveX(ctx) + id = client.Card.Create(). + SetNumber(c1.Number). + OnConflictColumns(card.FieldNumber). + UpdateNewValues(). + IDX(ctx) + c2 := client.Card.GetX(ctx, id) + require.Equal(t, c1.CreateTime.Unix(), c2.CreateTime.Unix()) + require.NotEqual(t, c1.UpdateTime.Unix(), c2.UpdateTime.Unix()) } func Clone(t *testing.T, client *ent.Client) { diff --git a/schema/field/field.go b/schema/field/field.go index 113613b31..f61ab140e 100644 --- a/schema/field/field.go +++ b/schema/field/field.go @@ -345,7 +345,8 @@ func (b *timeBuilder) Optional() *timeBuilder { return b } -// Immutable indicates that this field cannot be updated. +// Immutable fields are fields that can be set only in the creation of the entity. +// i.e., no setters will be generated for the entity updaters (one and many). func (b *timeBuilder) Immutable() *timeBuilder { b.desc.Immutable = true return b diff --git a/schema/mixin/mixin.go b/schema/mixin/mixin.go index 42535f58e..f9c5fa150 100644 --- a/schema/mixin/mixin.go +++ b/schema/mixin/mixin.go @@ -65,8 +65,7 @@ func (UpdateTime) Fields() []ent.Field { return []ent.Field{ field.Time("update_time"). Default(time.Now). - UpdateDefault(time.Now). - Immutable(), + UpdateDefault(time.Now), } } diff --git a/schema/mixin/mixin_test.go b/schema/mixin/mixin_test.go index 5b1722afb..59ab6d60a 100644 --- a/schema/mixin/mixin_test.go +++ b/schema/mixin/mixin_test.go @@ -33,7 +33,6 @@ func TestTimeMixin(t *testing.T) { require.Len(t, fields, 1) desc := fields[0].Descriptor() assert.Equal(t, "update_time", desc.Name) - assert.True(t, desc.Immutable) assert.NotNil(t, desc.Default) assert.NotNil(t, desc.UpdateDefault) })