mirror of
https://github.com/ent/ent.git
synced 2026-05-28 09:49:08 +03:00
entc/gen: add support for upsert/on-conflict feature-flag
This commit is contained in:
committed by
Ariel Mashraki
parent
a5c931ed13
commit
09c4306378
@@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/entc/integration/ent/schema"
|
||||
"entgo.io/ent/entc/integration/ent/task"
|
||||
@@ -22,6 +23,7 @@ type TaskCreate struct {
|
||||
config
|
||||
mutation *TaskMutation
|
||||
hooks []Hook
|
||||
conflict []sql.ConflictOption
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
@@ -152,6 +154,7 @@ func (tc *TaskCreate) createSpec() (*Task, *sqlgraph.CreateSpec) {
|
||||
},
|
||||
}
|
||||
)
|
||||
_spec.OnConflict = tc.conflict
|
||||
if value, ok := tc.mutation.Priority(); ok {
|
||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
||||
Type: field.TypeInt,
|
||||
@@ -163,10 +166,161 @@ func (tc *TaskCreate) createSpec() (*Task, *sqlgraph.CreateSpec) {
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
|
||||
// of the `INSERT` statement. For example:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// SetPriority(v).
|
||||
// OnConflict(
|
||||
// // Update the row with the new values
|
||||
// // the was proposed for insertion.
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// // Override some of the fields with custom
|
||||
// // update values.
|
||||
// Update(func(u *ent.TaskUpsert) {
|
||||
// SetPriority(v+v).
|
||||
// }).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (tc *TaskCreate) OnConflict(opts ...sql.ConflictOption) *TaskUpsertOne {
|
||||
tc.conflict = opts
|
||||
return &TaskUpsertOne{
|
||||
create: tc,
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflictColumns calls `OnConflict` and configures the columns
|
||||
// as conflict target. Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ConflictColumns(columns...)).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (tc *TaskCreate) OnConflictColumns(columns ...string) *TaskUpsertOne {
|
||||
tc.conflict = append(tc.conflict, sql.ConflictColumns(columns...))
|
||||
return &TaskUpsertOne{
|
||||
create: tc,
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
// TaskUpsertOne is the builder for "upsert"-ing
|
||||
// one Task node.
|
||||
TaskUpsertOne struct {
|
||||
create *TaskCreate
|
||||
}
|
||||
|
||||
// TaskUpsert is the "OnConflict" setter.
|
||||
TaskUpsert struct {
|
||||
*sql.UpdateSet
|
||||
}
|
||||
)
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *TaskUpsert) SetPriority(v schema.Priority) *TaskUpsert {
|
||||
u.Set(task.FieldPriority, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdatePriority sets the "priority" field to the value that was provided on create.
|
||||
func (u *TaskUpsert) UpdatePriority() *TaskUpsert {
|
||||
u.SetExcluded(task.FieldPriority)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the fields using the new values that
|
||||
// were set on create. Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ResolveWithNewValues()).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (u *TaskUpsertOne) UpdateNewValues() *TaskUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
|
||||
return u
|
||||
}
|
||||
|
||||
// Ignore sets each column to itself in case of conflict.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ResolveWithIgnore()).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (u *TaskUpsertOne) Ignore() *TaskUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
|
||||
return u
|
||||
}
|
||||
|
||||
// DoNothing configures the conflict_action to `DO NOTHING`.
|
||||
// Supported only by SQLite and PostgreSQL.
|
||||
func (u *TaskUpsertOne) DoNothing() *TaskUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.DoNothing())
|
||||
return u
|
||||
}
|
||||
|
||||
// Update allows overriding fields `UPDATE` values. See the TaskCreate.OnConflict
|
||||
// documentation for more info.
|
||||
func (u *TaskUpsertOne) Update(set func(*TaskUpsert)) *TaskUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
|
||||
set(&TaskUpsert{UpdateSet: update})
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *TaskUpsertOne) SetPriority(v schema.Priority) *TaskUpsertOne {
|
||||
return u.Update(func(s *TaskUpsert) {
|
||||
s.SetPriority(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdatePriority sets the "priority" field to the value that was provided on create.
|
||||
func (u *TaskUpsertOne) UpdatePriority() *TaskUpsertOne {
|
||||
return u.Update(func(s *TaskUpsert) {
|
||||
s.UpdatePriority()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *TaskUpsertOne) Exec(ctx context.Context) error {
|
||||
if len(u.create.conflict) == 0 {
|
||||
return errors.New("ent: missing options for TaskCreate.OnConflict")
|
||||
}
|
||||
return u.create.Exec(ctx)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (u *TaskUpsertOne) ExecX(ctx context.Context) {
|
||||
if err := u.create.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Exec executes the UPSERT query and returns the inserted/updated ID.
|
||||
func (u *TaskUpsertOne) ID(ctx context.Context) (id int, err error) {
|
||||
node, err := u.create.Save(ctx)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
return node.ID, nil
|
||||
}
|
||||
|
||||
// IDX is like ID, but panics if an error occurs.
|
||||
func (u *TaskUpsertOne) IDX(ctx context.Context) int {
|
||||
id, err := u.ID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// TaskCreateBulk is the builder for creating many Task entities in bulk.
|
||||
type TaskCreateBulk struct {
|
||||
config
|
||||
builders []*TaskCreate
|
||||
conflict []sql.ConflictOption
|
||||
}
|
||||
|
||||
// Save creates the Task entities in the database.
|
||||
@@ -192,8 +346,10 @@ func (tcb *TaskCreateBulk) Save(ctx context.Context) ([]*Task, error) {
|
||||
if i < len(mutators)-1 {
|
||||
_, err = mutators[i+1].Mutate(root, tcb.builders[i+1].mutation)
|
||||
} else {
|
||||
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
||||
spec.OnConflict = tcb.conflict
|
||||
// Invoke the actual operation on the latest mutation in the chain.
|
||||
if err = sqlgraph.BatchCreate(ctx, tcb.driver, &sqlgraph.BatchCreateSpec{Nodes: specs}); err != nil {
|
||||
if err = sqlgraph.BatchCreate(ctx, tcb.driver, spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{err.Error(), err}
|
||||
}
|
||||
@@ -204,8 +360,10 @@ func (tcb *TaskCreateBulk) Save(ctx context.Context) ([]*Task, error) {
|
||||
}
|
||||
mutation.id = &nodes[i].ID
|
||||
mutation.done = true
|
||||
id := specs[i].ID.Value.(int64)
|
||||
nodes[i].ID = int(id)
|
||||
if specs[i].ID.Value != nil {
|
||||
id := specs[i].ID.Value.(int64)
|
||||
nodes[i].ID = int(id)
|
||||
}
|
||||
return nodes[i], nil
|
||||
})
|
||||
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
||||
@@ -243,3 +401,120 @@ func (tcb *TaskCreateBulk) ExecX(ctx context.Context) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
|
||||
// of the `INSERT` statement. For example:
|
||||
//
|
||||
// client.Task.CreateBulk(builders...).
|
||||
// OnConflict(
|
||||
// // Update the row with the new values
|
||||
// // the was proposed for insertion.
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// // Override some of the fields with custom
|
||||
// // update values.
|
||||
// Update(func(u *ent.TaskUpsert) {
|
||||
// SetPriority(v+v).
|
||||
// }).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (tcb *TaskCreateBulk) OnConflict(opts ...sql.ConflictOption) *TaskUpsertBulk {
|
||||
tcb.conflict = opts
|
||||
return &TaskUpsertBulk{
|
||||
create: tcb,
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflictColumns calls `OnConflict` and configures the columns
|
||||
// as conflict target. Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ConflictColumns(columns...)).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (tcb *TaskCreateBulk) OnConflictColumns(columns ...string) *TaskUpsertBulk {
|
||||
tcb.conflict = append(tcb.conflict, sql.ConflictColumns(columns...))
|
||||
return &TaskUpsertBulk{
|
||||
create: tcb,
|
||||
}
|
||||
}
|
||||
|
||||
// TaskUpsertBulk is the builder for "upsert"-ing
|
||||
// a bulk of Task nodes.
|
||||
type TaskUpsertBulk struct {
|
||||
create *TaskCreateBulk
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the fields using the new values that
|
||||
// were set on create. Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ResolveWithNewValues()).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (u *TaskUpsertBulk) UpdateNewValues() *TaskUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
|
||||
return u
|
||||
}
|
||||
|
||||
// Ignore sets each column to itself in case of conflict.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
// client.Task.Create().
|
||||
// OnConflict(sql.ResolveWithIgnore()).
|
||||
// Exec(ctx)
|
||||
//
|
||||
func (u *TaskUpsertBulk) Ignore() *TaskUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
|
||||
return u
|
||||
}
|
||||
|
||||
// DoNothing configures the conflict_action to `DO NOTHING`.
|
||||
// Supported only by SQLite and PostgreSQL.
|
||||
func (u *TaskUpsertBulk) DoNothing() *TaskUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.DoNothing())
|
||||
return u
|
||||
}
|
||||
|
||||
// Update allows overriding fields `UPDATE` values. See the TaskCreateBulk.OnConflict
|
||||
// documentation for more info.
|
||||
func (u *TaskUpsertBulk) Update(set func(*TaskUpsert)) *TaskUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
|
||||
set(&TaskUpsert{UpdateSet: update})
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *TaskUpsertBulk) SetPriority(v schema.Priority) *TaskUpsertBulk {
|
||||
return u.Update(func(s *TaskUpsert) {
|
||||
s.SetPriority(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdatePriority sets the "priority" field to the value that was provided on create.
|
||||
func (u *TaskUpsertBulk) UpdatePriority() *TaskUpsertBulk {
|
||||
return u.Update(func(s *TaskUpsert) {
|
||||
s.UpdatePriority()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *TaskUpsertBulk) Exec(ctx context.Context) error {
|
||||
for i, b := range u.create.builders {
|
||||
if len(b.conflict) != 0 {
|
||||
return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the TaskCreateBulk instead", i)
|
||||
}
|
||||
}
|
||||
if len(u.create.conflict) == 0 {
|
||||
return errors.New("ent: missing options for TaskCreateBulk.OnConflict")
|
||||
}
|
||||
return u.create.Exec(ctx)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (u *TaskUpsertBulk) ExecX(ctx context.Context) {
|
||||
if err := u.create.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user