entc/gen: add support for upsert/on-conflict feature-flag

This commit is contained in:
Ariel Mashraki
2021-08-02 19:19:46 +03:00
committed by Ariel Mashraki
parent a5c931ed13
commit 09c4306378
95 changed files with 9556 additions and 279 deletions

View File

@@ -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)
}
}