浏览代码

增加节点客户不回复定时任务

boweniac 9 月之前
父节点
当前提交
14b058c15a

+ 531 - 8
ent/client.go

@@ -16,6 +16,9 @@ import (
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
 	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
 	"github.com/suyuan32/simple-admin-job/ent/task"
 	"github.com/suyuan32/simple-admin-job/ent/tasklog"
 
@@ -29,6 +32,12 @@ type Client struct {
 	Schema *migrate.Schema
 	// MessageRecords is the client for interacting with the MessageRecords builders.
 	MessageRecords *MessageRecordsClient
+	// SopNode is the client for interacting with the SopNode builders.
+	SopNode *SopNodeClient
+	// SopStage is the client for interacting with the SopStage builders.
+	SopStage *SopStageClient
+	// SopTask is the client for interacting with the SopTask builders.
+	SopTask *SopTaskClient
 	// Task is the client for interacting with the Task builders.
 	Task *TaskClient
 	// TaskLog is the client for interacting with the TaskLog builders.
@@ -45,6 +54,9 @@ func NewClient(opts ...Option) *Client {
 func (c *Client) init() {
 	c.Schema = migrate.NewSchema(c.driver)
 	c.MessageRecords = NewMessageRecordsClient(c.config)
+	c.SopNode = NewSopNodeClient(c.config)
+	c.SopStage = NewSopStageClient(c.config)
+	c.SopTask = NewSopTaskClient(c.config)
 	c.Task = NewTaskClient(c.config)
 	c.TaskLog = NewTaskLogClient(c.config)
 }
@@ -140,6 +152,9 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
 		ctx:            ctx,
 		config:         cfg,
 		MessageRecords: NewMessageRecordsClient(cfg),
+		SopNode:        NewSopNodeClient(cfg),
+		SopStage:       NewSopStageClient(cfg),
+		SopTask:        NewSopTaskClient(cfg),
 		Task:           NewTaskClient(cfg),
 		TaskLog:        NewTaskLogClient(cfg),
 	}, nil
@@ -162,6 +177,9 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
 		ctx:            ctx,
 		config:         cfg,
 		MessageRecords: NewMessageRecordsClient(cfg),
+		SopNode:        NewSopNodeClient(cfg),
+		SopStage:       NewSopStageClient(cfg),
+		SopTask:        NewSopTaskClient(cfg),
 		Task:           NewTaskClient(cfg),
 		TaskLog:        NewTaskLogClient(cfg),
 	}, nil
@@ -192,17 +210,21 @@ 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.MessageRecords.Use(hooks...)
-	c.Task.Use(hooks...)
-	c.TaskLog.Use(hooks...)
+	for _, n := range []interface{ Use(...Hook) }{
+		c.MessageRecords, c.SopNode, c.SopStage, c.SopTask, c.Task, c.TaskLog,
+	} {
+		n.Use(hooks...)
+	}
 }
 
 // Intercept adds the query interceptors to all the entity clients.
 // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
 func (c *Client) Intercept(interceptors ...Interceptor) {
-	c.MessageRecords.Intercept(interceptors...)
-	c.Task.Intercept(interceptors...)
-	c.TaskLog.Intercept(interceptors...)
+	for _, n := range []interface{ Intercept(...Interceptor) }{
+		c.MessageRecords, c.SopNode, c.SopStage, c.SopTask, c.Task, c.TaskLog,
+	} {
+		n.Intercept(interceptors...)
+	}
 }
 
 // Mutate implements the ent.Mutator interface.
@@ -210,6 +232,12 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
 	switch m := m.(type) {
 	case *MessageRecordsMutation:
 		return c.MessageRecords.mutate(ctx, m)
+	case *SopNodeMutation:
+		return c.SopNode.mutate(ctx, m)
+	case *SopStageMutation:
+		return c.SopStage.mutate(ctx, m)
+	case *SopTaskMutation:
+		return c.SopTask.mutate(ctx, m)
 	case *TaskMutation:
 		return c.Task.mutate(ctx, m)
 	case *TaskLogMutation:
@@ -352,6 +380,501 @@ func (c *MessageRecordsClient) mutate(ctx context.Context, m *MessageRecordsMuta
 	}
 }
 
+// SopNodeClient is a client for the SopNode schema.
+type SopNodeClient struct {
+	config
+}
+
+// NewSopNodeClient returns a client for the SopNode from the given config.
+func NewSopNodeClient(c config) *SopNodeClient {
+	return &SopNodeClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `sopnode.Hooks(f(g(h())))`.
+func (c *SopNodeClient) Use(hooks ...Hook) {
+	c.hooks.SopNode = append(c.hooks.SopNode, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `sopnode.Intercept(f(g(h())))`.
+func (c *SopNodeClient) Intercept(interceptors ...Interceptor) {
+	c.inters.SopNode = append(c.inters.SopNode, interceptors...)
+}
+
+// Create returns a builder for creating a SopNode entity.
+func (c *SopNodeClient) Create() *SopNodeCreate {
+	mutation := newSopNodeMutation(c.config, OpCreate)
+	return &SopNodeCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of SopNode entities.
+func (c *SopNodeClient) CreateBulk(builders ...*SopNodeCreate) *SopNodeCreateBulk {
+	return &SopNodeCreateBulk{config: c.config, builders: builders}
+}
+
+// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
+// a builder and applies setFunc on it.
+func (c *SopNodeClient) MapCreateBulk(slice any, setFunc func(*SopNodeCreate, int)) *SopNodeCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &SopNodeCreateBulk{err: fmt.Errorf("calling to SopNodeClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*SopNodeCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &SopNodeCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for SopNode.
+func (c *SopNodeClient) Update() *SopNodeUpdate {
+	mutation := newSopNodeMutation(c.config, OpUpdate)
+	return &SopNodeUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *SopNodeClient) UpdateOne(sn *SopNode) *SopNodeUpdateOne {
+	mutation := newSopNodeMutation(c.config, OpUpdateOne, withSopNode(sn))
+	return &SopNodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *SopNodeClient) UpdateOneID(id uint64) *SopNodeUpdateOne {
+	mutation := newSopNodeMutation(c.config, OpUpdateOne, withSopNodeID(id))
+	return &SopNodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for SopNode.
+func (c *SopNodeClient) Delete() *SopNodeDelete {
+	mutation := newSopNodeMutation(c.config, OpDelete)
+	return &SopNodeDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *SopNodeClient) DeleteOne(sn *SopNode) *SopNodeDeleteOne {
+	return c.DeleteOneID(sn.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *SopNodeClient) DeleteOneID(id uint64) *SopNodeDeleteOne {
+	builder := c.Delete().Where(sopnode.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &SopNodeDeleteOne{builder}
+}
+
+// Query returns a query builder for SopNode.
+func (c *SopNodeClient) Query() *SopNodeQuery {
+	return &SopNodeQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeSopNode},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a SopNode entity by its id.
+func (c *SopNodeClient) Get(ctx context.Context, id uint64) (*SopNode, error) {
+	return c.Query().Where(sopnode.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *SopNodeClient) GetX(ctx context.Context, id uint64) *SopNode {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QuerySopStage queries the sop_stage edge of a SopNode.
+func (c *SopNodeClient) QuerySopStage(sn *SopNode) *SopStageQuery {
+	query := (&SopStageClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := sn.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, id),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, sopnode.SopStageTable, sopnode.SopStageColumn),
+		)
+		fromV = sqlgraph.Neighbors(sn.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QueryNodeMessages queries the node_messages edge of a SopNode.
+func (c *SopNodeClient) QueryNodeMessages(sn *SopNode) *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := sn.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, id),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopnode.NodeMessagesTable, sopnode.NodeMessagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(sn.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *SopNodeClient) Hooks() []Hook {
+	return c.hooks.SopNode
+}
+
+// Interceptors returns the client interceptors.
+func (c *SopNodeClient) Interceptors() []Interceptor {
+	return c.inters.SopNode
+}
+
+func (c *SopNodeClient) mutate(ctx context.Context, m *SopNodeMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&SopNodeCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&SopNodeUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&SopNodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&SopNodeDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown SopNode mutation op: %q", m.Op())
+	}
+}
+
+// SopStageClient is a client for the SopStage schema.
+type SopStageClient struct {
+	config
+}
+
+// NewSopStageClient returns a client for the SopStage from the given config.
+func NewSopStageClient(c config) *SopStageClient {
+	return &SopStageClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `sopstage.Hooks(f(g(h())))`.
+func (c *SopStageClient) Use(hooks ...Hook) {
+	c.hooks.SopStage = append(c.hooks.SopStage, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `sopstage.Intercept(f(g(h())))`.
+func (c *SopStageClient) Intercept(interceptors ...Interceptor) {
+	c.inters.SopStage = append(c.inters.SopStage, interceptors...)
+}
+
+// Create returns a builder for creating a SopStage entity.
+func (c *SopStageClient) Create() *SopStageCreate {
+	mutation := newSopStageMutation(c.config, OpCreate)
+	return &SopStageCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of SopStage entities.
+func (c *SopStageClient) CreateBulk(builders ...*SopStageCreate) *SopStageCreateBulk {
+	return &SopStageCreateBulk{config: c.config, builders: builders}
+}
+
+// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
+// a builder and applies setFunc on it.
+func (c *SopStageClient) MapCreateBulk(slice any, setFunc func(*SopStageCreate, int)) *SopStageCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &SopStageCreateBulk{err: fmt.Errorf("calling to SopStageClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*SopStageCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &SopStageCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for SopStage.
+func (c *SopStageClient) Update() *SopStageUpdate {
+	mutation := newSopStageMutation(c.config, OpUpdate)
+	return &SopStageUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *SopStageClient) UpdateOne(ss *SopStage) *SopStageUpdateOne {
+	mutation := newSopStageMutation(c.config, OpUpdateOne, withSopStage(ss))
+	return &SopStageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *SopStageClient) UpdateOneID(id uint64) *SopStageUpdateOne {
+	mutation := newSopStageMutation(c.config, OpUpdateOne, withSopStageID(id))
+	return &SopStageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for SopStage.
+func (c *SopStageClient) Delete() *SopStageDelete {
+	mutation := newSopStageMutation(c.config, OpDelete)
+	return &SopStageDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *SopStageClient) DeleteOne(ss *SopStage) *SopStageDeleteOne {
+	return c.DeleteOneID(ss.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *SopStageClient) DeleteOneID(id uint64) *SopStageDeleteOne {
+	builder := c.Delete().Where(sopstage.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &SopStageDeleteOne{builder}
+}
+
+// Query returns a query builder for SopStage.
+func (c *SopStageClient) Query() *SopStageQuery {
+	return &SopStageQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeSopStage},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a SopStage entity by its id.
+func (c *SopStageClient) Get(ctx context.Context, id uint64) (*SopStage, error) {
+	return c.Query().Where(sopstage.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *SopStageClient) GetX(ctx context.Context, id uint64) *SopStage {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QuerySopTask queries the sop_task edge of a SopStage.
+func (c *SopStageClient) QuerySopTask(ss *SopStage) *SopTaskQuery {
+	query := (&SopTaskClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := ss.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, id),
+			sqlgraph.To(soptask.Table, soptask.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, sopstage.SopTaskTable, sopstage.SopTaskColumn),
+		)
+		fromV = sqlgraph.Neighbors(ss.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QueryStageNodes queries the stage_nodes edge of a SopStage.
+func (c *SopStageClient) QueryStageNodes(ss *SopStage) *SopNodeQuery {
+	query := (&SopNodeClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := ss.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, id),
+			sqlgraph.To(sopnode.Table, sopnode.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageNodesTable, sopstage.StageNodesColumn),
+		)
+		fromV = sqlgraph.Neighbors(ss.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QueryStageMessages queries the stage_messages edge of a SopStage.
+func (c *SopStageClient) QueryStageMessages(ss *SopStage) *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := ss.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, id),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageMessagesTable, sopstage.StageMessagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(ss.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *SopStageClient) Hooks() []Hook {
+	return c.hooks.SopStage
+}
+
+// Interceptors returns the client interceptors.
+func (c *SopStageClient) Interceptors() []Interceptor {
+	return c.inters.SopStage
+}
+
+func (c *SopStageClient) mutate(ctx context.Context, m *SopStageMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&SopStageCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&SopStageUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&SopStageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&SopStageDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown SopStage mutation op: %q", m.Op())
+	}
+}
+
+// SopTaskClient is a client for the SopTask schema.
+type SopTaskClient struct {
+	config
+}
+
+// NewSopTaskClient returns a client for the SopTask from the given config.
+func NewSopTaskClient(c config) *SopTaskClient {
+	return &SopTaskClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `soptask.Hooks(f(g(h())))`.
+func (c *SopTaskClient) Use(hooks ...Hook) {
+	c.hooks.SopTask = append(c.hooks.SopTask, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `soptask.Intercept(f(g(h())))`.
+func (c *SopTaskClient) Intercept(interceptors ...Interceptor) {
+	c.inters.SopTask = append(c.inters.SopTask, interceptors...)
+}
+
+// Create returns a builder for creating a SopTask entity.
+func (c *SopTaskClient) Create() *SopTaskCreate {
+	mutation := newSopTaskMutation(c.config, OpCreate)
+	return &SopTaskCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of SopTask entities.
+func (c *SopTaskClient) CreateBulk(builders ...*SopTaskCreate) *SopTaskCreateBulk {
+	return &SopTaskCreateBulk{config: c.config, builders: builders}
+}
+
+// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
+// a builder and applies setFunc on it.
+func (c *SopTaskClient) MapCreateBulk(slice any, setFunc func(*SopTaskCreate, int)) *SopTaskCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &SopTaskCreateBulk{err: fmt.Errorf("calling to SopTaskClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*SopTaskCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &SopTaskCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for SopTask.
+func (c *SopTaskClient) Update() *SopTaskUpdate {
+	mutation := newSopTaskMutation(c.config, OpUpdate)
+	return &SopTaskUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *SopTaskClient) UpdateOne(st *SopTask) *SopTaskUpdateOne {
+	mutation := newSopTaskMutation(c.config, OpUpdateOne, withSopTask(st))
+	return &SopTaskUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *SopTaskClient) UpdateOneID(id uint64) *SopTaskUpdateOne {
+	mutation := newSopTaskMutation(c.config, OpUpdateOne, withSopTaskID(id))
+	return &SopTaskUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for SopTask.
+func (c *SopTaskClient) Delete() *SopTaskDelete {
+	mutation := newSopTaskMutation(c.config, OpDelete)
+	return &SopTaskDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *SopTaskClient) DeleteOne(st *SopTask) *SopTaskDeleteOne {
+	return c.DeleteOneID(st.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *SopTaskClient) DeleteOneID(id uint64) *SopTaskDeleteOne {
+	builder := c.Delete().Where(soptask.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &SopTaskDeleteOne{builder}
+}
+
+// Query returns a query builder for SopTask.
+func (c *SopTaskClient) Query() *SopTaskQuery {
+	return &SopTaskQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeSopTask},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a SopTask entity by its id.
+func (c *SopTaskClient) Get(ctx context.Context, id uint64) (*SopTask, error) {
+	return c.Query().Where(soptask.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *SopTaskClient) GetX(ctx context.Context, id uint64) *SopTask {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QueryTaskStages queries the task_stages edge of a SopTask.
+func (c *SopTaskClient) QueryTaskStages(st *SopTask) *SopStageQuery {
+	query := (&SopStageClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := st.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(soptask.Table, soptask.FieldID, id),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, soptask.TaskStagesTable, soptask.TaskStagesColumn),
+		)
+		fromV = sqlgraph.Neighbors(st.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *SopTaskClient) Hooks() []Hook {
+	return c.hooks.SopTask
+}
+
+// Interceptors returns the client interceptors.
+func (c *SopTaskClient) Interceptors() []Interceptor {
+	return c.inters.SopTask
+}
+
+func (c *SopTaskClient) mutate(ctx context.Context, m *SopTaskMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&SopTaskCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&SopTaskUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&SopTaskUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&SopTaskDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown SopTask mutation op: %q", m.Op())
+	}
+}
+
 // TaskClient is a client for the Task schema.
 type TaskClient struct {
 	config
@@ -653,10 +1176,10 @@ func (c *TaskLogClient) mutate(ctx context.Context, m *TaskLogMutation) (Value,
 // hooks and interceptors per client, for fast access.
 type (
 	hooks struct {
-		MessageRecords, Task, TaskLog []ent.Hook
+		MessageRecords, SopNode, SopStage, SopTask, Task, TaskLog []ent.Hook
 	}
 	inters struct {
-		MessageRecords, Task, TaskLog []ent.Interceptor
+		MessageRecords, SopNode, SopStage, SopTask, Task, TaskLog []ent.Interceptor
 	}
 )
 

+ 6 - 0
ent/ent.go

@@ -13,6 +13,9 @@ import (
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
 	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
 	"github.com/suyuan32/simple-admin-job/ent/task"
 	"github.com/suyuan32/simple-admin-job/ent/tasklog"
 )
@@ -76,6 +79,9 @@ func checkColumn(table, column string) error {
 	initCheck.Do(func() {
 		columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
 			messagerecords.Table: messagerecords.ValidColumn,
+			sopnode.Table:        sopnode.ValidColumn,
+			sopstage.Table:       sopstage.ValidColumn,
+			soptask.Table:        soptask.ValidColumn,
 			task.Table:           task.ValidColumn,
 			tasklog.Table:        tasklog.ValidColumn,
 		})

+ 36 - 0
ent/hook/hook.go

@@ -21,6 +21,42 @@ func (f MessageRecordsFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Val
 	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MessageRecordsMutation", m)
 }
 
+// The SopNodeFunc type is an adapter to allow the use of ordinary
+// function as SopNode mutator.
+type SopNodeFunc func(context.Context, *ent.SopNodeMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f SopNodeFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.SopNodeMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SopNodeMutation", m)
+}
+
+// The SopStageFunc type is an adapter to allow the use of ordinary
+// function as SopStage mutator.
+type SopStageFunc func(context.Context, *ent.SopStageMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f SopStageFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.SopStageMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SopStageMutation", m)
+}
+
+// The SopTaskFunc type is an adapter to allow the use of ordinary
+// function as SopTask mutator.
+type SopTaskFunc func(context.Context, *ent.SopTaskMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f SopTaskFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.SopTaskMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SopTaskMutation", m)
+}
+
 // The TaskFunc type is an adapter to allow the use of ordinary
 // function as Task mutator.
 type TaskFunc func(context.Context, *ent.TaskMutation) (ent.Value, error)

+ 22 - 2
ent/messagerecords.go

@@ -48,8 +48,10 @@ type MessageRecords struct {
 	// 源 ID
 	SourceID uint64 `json:"source_id,omitempty"`
 	// 次源 ID
-	SubSourceID  uint64 `json:"sub_source_id,omitempty"`
-	selectValues sql.SelectValues
+	SubSourceID              uint64 `json:"sub_source_id,omitempty"`
+	sop_node_node_messages   *uint64
+	sop_stage_stage_messages *uint64
+	selectValues             sql.SelectValues
 }
 
 // scanValues returns the types for scanning values from sql.Rows.
@@ -65,6 +67,10 @@ func (*MessageRecords) scanValues(columns []string) ([]any, error) {
 			values[i] = new(sql.NullString)
 		case messagerecords.FieldCreatedAt, messagerecords.FieldUpdatedAt, messagerecords.FieldSendTime:
 			values[i] = new(sql.NullTime)
+		case messagerecords.ForeignKeys[0]: // sop_node_node_messages
+			values[i] = new(sql.NullInt64)
+		case messagerecords.ForeignKeys[1]: // sop_stage_stage_messages
+			values[i] = new(sql.NullInt64)
 		default:
 			values[i] = new(sql.UnknownType)
 		}
@@ -178,6 +184,20 @@ func (mr *MessageRecords) assignValues(columns []string, values []any) error {
 			} else if value.Valid {
 				mr.SubSourceID = uint64(value.Int64)
 			}
+		case messagerecords.ForeignKeys[0]:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for edge-field sop_node_node_messages", value)
+			} else if value.Valid {
+				mr.sop_node_node_messages = new(uint64)
+				*mr.sop_node_node_messages = uint64(value.Int64)
+			}
+		case messagerecords.ForeignKeys[1]:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for edge-field sop_stage_stage_messages", value)
+			} else if value.Valid {
+				mr.sop_stage_stage_messages = new(uint64)
+				*mr.sop_stage_stage_messages = uint64(value.Int64)
+			}
 		default:
 			mr.selectValues.Set(columns[i], values[i])
 		}

+ 12 - 0
ent/messagerecords/messagerecords.go

@@ -67,6 +67,13 @@ var Columns = []string{
 	FieldSubSourceID,
 }
 
+// ForeignKeys holds the SQL foreign-keys that are owned by the "message_records"
+// table and are not defined as standalone fields in the schema.
+var ForeignKeys = []string{
+	"sop_node_node_messages",
+	"sop_stage_stage_messages",
+}
+
 // ValidColumn reports if the column name is valid (part of the table columns).
 func ValidColumn(column string) bool {
 	for i := range Columns {
@@ -74,6 +81,11 @@ func ValidColumn(column string) bool {
 			return true
 		}
 	}
+	for i := range ForeignKeys {
+		if column == ForeignKeys[i] {
+			return true
+		}
+	}
 	return false
 }
 

+ 7 - 2
ent/messagerecords_query.go

@@ -21,6 +21,7 @@ type MessageRecordsQuery struct {
 	order      []messagerecords.OrderOption
 	inters     []Interceptor
 	predicates []predicate.MessageRecords
+	withFKs    bool
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -331,9 +332,13 @@ func (mrq *MessageRecordsQuery) prepareQuery(ctx context.Context) error {
 
 func (mrq *MessageRecordsQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*MessageRecords, error) {
 	var (
-		nodes = []*MessageRecords{}
-		_spec = mrq.querySpec()
+		nodes   = []*MessageRecords{}
+		withFKs = mrq.withFKs
+		_spec   = mrq.querySpec()
 	)
+	if withFKs {
+		_spec.Node.Columns = append(_spec.Node.Columns, messagerecords.ForeignKeys...)
+	}
 	_spec.ScanValues = func(columns []string) ([]any, error) {
 		return (*MessageRecords).scanValues(nil, columns)
 	}

+ 133 - 0
ent/migrate/schema.go

@@ -27,12 +27,129 @@ var (
 		{Name: "source_type", Type: field.TypeInt, Comment: "源类型 1 点发 2 群发 3 SOP", Default: 1},
 		{Name: "source_id", Type: field.TypeUint64, Nullable: true, Comment: "源 ID", Default: 1},
 		{Name: "sub_source_id", Type: field.TypeUint64, Nullable: true, Comment: "次源 ID", Default: 1},
+		{Name: "sop_node_node_messages", Type: field.TypeUint64, Nullable: true},
+		{Name: "sop_stage_stage_messages", Type: field.TypeUint64, Nullable: true},
 	}
 	// MessageRecordsTable holds the schema information for the "message_records" table.
 	MessageRecordsTable = &schema.Table{
 		Name:       "message_records",
 		Columns:    MessageRecordsColumns,
 		PrimaryKey: []*schema.Column{MessageRecordsColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "message_records_sop_node_node_messages",
+				Columns:    []*schema.Column{MessageRecordsColumns[16]},
+				RefColumns: []*schema.Column{SopNodeColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+			{
+				Symbol:     "message_records_sop_stage_stage_messages",
+				Columns:    []*schema.Column{MessageRecordsColumns[17]},
+				RefColumns: []*schema.Column{SopStageColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+		},
+	}
+	// SopNodeColumns holds the columns for the "sop_node" table.
+	SopNodeColumns = []*schema.Column{
+		{Name: "id", Type: field.TypeUint64, Increment: true},
+		{Name: "created_at", Type: field.TypeTime, Comment: "Create Time | 创建日期"},
+		{Name: "updated_at", Type: field.TypeTime, Comment: "Update Time | 修改日期"},
+		{Name: "status", Type: field.TypeUint8, Nullable: true, Comment: "Status 1: normal 2: ban | 状态 1 正常 2 禁用", Default: 1},
+		{Name: "parent_id", Type: field.TypeUint64, Comment: "父节点 ID"},
+		{Name: "name", Type: field.TypeString, Comment: "节点名称", Default: ""},
+		{Name: "condition_type", Type: field.TypeInt, Comment: "触发条件类型 1 客户回复后触发 2 超时后触发", Default: 1},
+		{Name: "condition_list", Type: field.TypeJSON, Nullable: true, Comment: "触发语义列表 当为空时则代表用户回复任意内容后触发"},
+		{Name: "no_reply_condition", Type: field.TypeUint64, Comment: "超时触发时间(分钟)", Default: 0},
+		{Name: "action_message", Type: field.TypeJSON, Nullable: true, Comment: "命中后发送的消息内容"},
+		{Name: "action_label", Type: field.TypeJSON, Nullable: true, Comment: "命中后需要打的标签"},
+		{Name: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
+		{Name: "stage_id", Type: field.TypeUint64, Comment: "阶段 ID"},
+	}
+	// SopNodeTable holds the schema information for the "sop_node" table.
+	SopNodeTable = &schema.Table{
+		Name:       "sop_node",
+		Columns:    SopNodeColumns,
+		PrimaryKey: []*schema.Column{SopNodeColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "sop_node_sop_stage_stage_nodes",
+				Columns:    []*schema.Column{SopNodeColumns[12]},
+				RefColumns: []*schema.Column{SopStageColumns[0]},
+				OnDelete:   schema.NoAction,
+			},
+		},
+		Indexes: []*schema.Index{
+			{
+				Name:    "sopnode_name",
+				Unique:  false,
+				Columns: []*schema.Column{SopNodeColumns[5]},
+			},
+		},
+	}
+	// SopStageColumns holds the columns for the "sop_stage" table.
+	SopStageColumns = []*schema.Column{
+		{Name: "id", Type: field.TypeUint64, Increment: true},
+		{Name: "created_at", Type: field.TypeTime, Comment: "Create Time | 创建日期"},
+		{Name: "updated_at", Type: field.TypeTime, Comment: "Update Time | 修改日期"},
+		{Name: "status", Type: field.TypeUint8, Nullable: true, Comment: "Status 1: normal 2: ban | 状态 1 正常 2 禁用", Default: 1},
+		{Name: "name", Type: field.TypeString, Comment: "阶段名称", Default: ""},
+		{Name: "condition_type", Type: field.TypeInt, Comment: "客群筛选条件类型  1 按标签筛选 2 按客户基本信息筛选", Default: 1},
+		{Name: "condition_operator", Type: field.TypeInt, Comment: "筛选条件关系  1 满足所有条件(and) 2 满足任意条件(or)", Default: 1},
+		{Name: "condition_list", Type: field.TypeJSON, Comment: "筛选条件列表"},
+		{Name: "action_message", Type: field.TypeJSON, Nullable: true, Comment: "命中后发送的消息内容"},
+		{Name: "action_label", Type: field.TypeJSON, Nullable: true, Comment: "命中后需要打的标签"},
+		{Name: "index_sort", Type: field.TypeInt, Nullable: true, Comment: "阶段顺序", Default: 1},
+		{Name: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
+		{Name: "task_id", Type: field.TypeUint64, Comment: "SOP 任务 ID"},
+	}
+	// SopStageTable holds the schema information for the "sop_stage" table.
+	SopStageTable = &schema.Table{
+		Name:       "sop_stage",
+		Columns:    SopStageColumns,
+		PrimaryKey: []*schema.Column{SopStageColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "sop_stage_sop_task_task_stages",
+				Columns:    []*schema.Column{SopStageColumns[12]},
+				RefColumns: []*schema.Column{SopTaskColumns[0]},
+				OnDelete:   schema.NoAction,
+			},
+		},
+		Indexes: []*schema.Index{
+			{
+				Name:    "sopstage_name",
+				Unique:  false,
+				Columns: []*schema.Column{SopStageColumns[4]},
+			},
+		},
+	}
+	// SopTaskColumns holds the columns for the "sop_task" table.
+	SopTaskColumns = []*schema.Column{
+		{Name: "id", Type: field.TypeUint64, Increment: true},
+		{Name: "created_at", Type: field.TypeTime, Comment: "Create Time | 创建日期"},
+		{Name: "updated_at", Type: field.TypeTime, Comment: "Update Time | 修改日期"},
+		{Name: "status", Type: field.TypeUint8, Nullable: true, Comment: "Status 1: normal 2: ban | 状态 1 正常 2 禁用", Default: 1},
+		{Name: "name", Type: field.TypeString, Comment: "SOP 任务名称"},
+		{Name: "bot_wxid_list", Type: field.TypeJSON, Nullable: true, Comment: "机器人微信 id 列表"},
+		{Name: "type", Type: field.TypeInt, Comment: "标签类型:1好友,2群组,3企业微信联系人", Default: 1},
+		{Name: "plan_start_time", Type: field.TypeTime, Nullable: true, Comment: "任务计划开始时间"},
+		{Name: "plan_end_time", Type: field.TypeTime, Nullable: true, Comment: "任务计划结束时间"},
+		{Name: "creator_id", Type: field.TypeString, Nullable: true, Comment: "创建者 id"},
+		{Name: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
+	}
+	// SopTaskTable holds the schema information for the "sop_task" table.
+	SopTaskTable = &schema.Table{
+		Name:       "sop_task",
+		Columns:    SopTaskColumns,
+		PrimaryKey: []*schema.Column{SopTaskColumns[0]},
+		Indexes: []*schema.Index{
+			{
+				Name:    "soptask_name",
+				Unique:  false,
+				Columns: []*schema.Column{SopTaskColumns[4]},
+			},
+		},
 	}
 	// SysTasksColumns holds the columns for the "sys_tasks" table.
 	SysTasksColumns = []*schema.Column{
@@ -84,15 +201,31 @@ var (
 	// Tables holds all the tables in the schema.
 	Tables = []*schema.Table{
 		MessageRecordsTable,
+		SopNodeTable,
+		SopStageTable,
+		SopTaskTable,
 		SysTasksTable,
 		SysTaskLogsTable,
 	}
 )
 
 func init() {
+	MessageRecordsTable.ForeignKeys[0].RefTable = SopNodeTable
+	MessageRecordsTable.ForeignKeys[1].RefTable = SopStageTable
 	MessageRecordsTable.Annotation = &entsql.Annotation{
 		Table: "message_records",
 	}
+	SopNodeTable.ForeignKeys[0].RefTable = SopStageTable
+	SopNodeTable.Annotation = &entsql.Annotation{
+		Table: "sop_node",
+	}
+	SopStageTable.ForeignKeys[0].RefTable = SopTaskTable
+	SopStageTable.Annotation = &entsql.Annotation{
+		Table: "sop_stage",
+	}
+	SopTaskTable.Annotation = &entsql.Annotation{
+		Table: "sop_task",
+	}
 	SysTasksTable.Annotation = &entsql.Annotation{
 		Table: "sys_tasks",
 	}

+ 3930 - 0
ent/mutation.go

@@ -14,6 +14,9 @@ import (
 	"github.com/suyuan32/simple-admin-job/ent/custom_types"
 	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
 	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
 	"github.com/suyuan32/simple-admin-job/ent/task"
 	"github.com/suyuan32/simple-admin-job/ent/tasklog"
 )
@@ -28,6 +31,9 @@ const (
 
 	// Node types.
 	TypeMessageRecords = "MessageRecords"
+	TypeSopNode        = "SopNode"
+	TypeSopStage       = "SopStage"
+	TypeSopTask        = "SopTask"
 	TypeTask           = "Task"
 	TypeTaskLog        = "TaskLog"
 )
@@ -1475,6 +1481,3930 @@ func (m *MessageRecordsMutation) ResetEdge(name string) error {
 	return fmt.Errorf("unknown MessageRecords edge %s", name)
 }
 
+// SopNodeMutation represents an operation that mutates the SopNode nodes in the graph.
+type SopNodeMutation struct {
+	config
+	op                    Op
+	typ                   string
+	id                    *uint64
+	created_at            *time.Time
+	updated_at            *time.Time
+	status                *uint8
+	addstatus             *int8
+	parent_id             *uint64
+	addparent_id          *int64
+	name                  *string
+	condition_type        *int
+	addcondition_type     *int
+	condition_list        *[]string
+	appendcondition_list  []string
+	no_reply_condition    *uint64
+	addno_reply_condition *int64
+	action_message        *[]custom_types.Action
+	appendaction_message  []custom_types.Action
+	action_label          *[]uint64
+	appendaction_label    []uint64
+	deleted_at            *time.Time
+	clearedFields         map[string]struct{}
+	sop_stage             *uint64
+	clearedsop_stage      bool
+	node_messages         map[uint64]struct{}
+	removednode_messages  map[uint64]struct{}
+	clearednode_messages  bool
+	done                  bool
+	oldValue              func(context.Context) (*SopNode, error)
+	predicates            []predicate.SopNode
+}
+
+var _ ent.Mutation = (*SopNodeMutation)(nil)
+
+// sopnodeOption allows management of the mutation configuration using functional options.
+type sopnodeOption func(*SopNodeMutation)
+
+// newSopNodeMutation creates new mutation for the SopNode entity.
+func newSopNodeMutation(c config, op Op, opts ...sopnodeOption) *SopNodeMutation {
+	m := &SopNodeMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeSopNode,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withSopNodeID sets the ID field of the mutation.
+func withSopNodeID(id uint64) sopnodeOption {
+	return func(m *SopNodeMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *SopNode
+		)
+		m.oldValue = func(ctx context.Context) (*SopNode, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().SopNode.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withSopNode sets the old SopNode of the mutation.
+func withSopNode(node *SopNode) sopnodeOption {
+	return func(m *SopNodeMutation) {
+		m.oldValue = func(context.Context) (*SopNode, 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 SopNodeMutation) 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 SopNodeMutation) 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
+}
+
+// SetID sets the value of the id field. Note that this
+// operation is only accepted on creation of SopNode entities.
+func (m *SopNodeMutation) SetID(id uint64) {
+	m.id = &id
+}
+
+// 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 *SopNodeMutation) ID() (id uint64, 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 *SopNodeMutation) IDs(ctx context.Context) ([]uint64, error) {
+	switch {
+	case m.op.Is(OpUpdateOne | OpDeleteOne):
+		id, exists := m.ID()
+		if exists {
+			return []uint64{id}, nil
+		}
+		fallthrough
+	case m.op.Is(OpUpdate | OpDelete):
+		return m.Client().SopNode.Query().Where(m.predicates...).IDs(ctx)
+	default:
+		return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
+	}
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (m *SopNodeMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *SopNodeMutation) 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 SopNode entity.
+// If the SopNode 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 *SopNodeMutation) 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 *SopNodeMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *SopNodeMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *SopNodeMutation) UpdatedAt() (r time.Time, exists bool) {
+	v := m.updated_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldUpdatedAt returns the old "updated_at" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
+	}
+	return oldValue.UpdatedAt, nil
+}
+
+// ResetUpdatedAt resets all changes to the "updated_at" field.
+func (m *SopNodeMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *SopNodeMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *SopNodeMutation) Status() (r uint8, exists bool) {
+	v := m.status
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStatus returns the old "status" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldStatus(ctx context.Context) (v uint8, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStatus is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStatus requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStatus: %w", err)
+	}
+	return oldValue.Status, nil
+}
+
+// AddStatus adds u to the "status" field.
+func (m *SopNodeMutation) AddStatus(u int8) {
+	if m.addstatus != nil {
+		*m.addstatus += u
+	} else {
+		m.addstatus = &u
+	}
+}
+
+// AddedStatus returns the value that was added to the "status" field in this mutation.
+func (m *SopNodeMutation) AddedStatus() (r int8, exists bool) {
+	v := m.addstatus
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearStatus clears the value of the "status" field.
+func (m *SopNodeMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[sopnode.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *SopNodeMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[sopnode.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *SopNodeMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, sopnode.FieldStatus)
+}
+
+// SetStageID sets the "stage_id" field.
+func (m *SopNodeMutation) SetStageID(u uint64) {
+	m.sop_stage = &u
+}
+
+// StageID returns the value of the "stage_id" field in the mutation.
+func (m *SopNodeMutation) StageID() (r uint64, exists bool) {
+	v := m.sop_stage
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStageID returns the old "stage_id" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldStageID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStageID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStageID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStageID: %w", err)
+	}
+	return oldValue.StageID, nil
+}
+
+// ResetStageID resets all changes to the "stage_id" field.
+func (m *SopNodeMutation) ResetStageID() {
+	m.sop_stage = nil
+}
+
+// SetParentID sets the "parent_id" field.
+func (m *SopNodeMutation) SetParentID(u uint64) {
+	m.parent_id = &u
+	m.addparent_id = nil
+}
+
+// ParentID returns the value of the "parent_id" field in the mutation.
+func (m *SopNodeMutation) ParentID() (r uint64, exists bool) {
+	v := m.parent_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldParentID returns the old "parent_id" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldParentID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldParentID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldParentID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldParentID: %w", err)
+	}
+	return oldValue.ParentID, nil
+}
+
+// AddParentID adds u to the "parent_id" field.
+func (m *SopNodeMutation) AddParentID(u int64) {
+	if m.addparent_id != nil {
+		*m.addparent_id += u
+	} else {
+		m.addparent_id = &u
+	}
+}
+
+// AddedParentID returns the value that was added to the "parent_id" field in this mutation.
+func (m *SopNodeMutation) AddedParentID() (r int64, exists bool) {
+	v := m.addparent_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetParentID resets all changes to the "parent_id" field.
+func (m *SopNodeMutation) ResetParentID() {
+	m.parent_id = nil
+	m.addparent_id = nil
+}
+
+// SetName sets the "name" field.
+func (m *SopNodeMutation) SetName(s string) {
+	m.name = &s
+}
+
+// Name returns the value of the "name" field in the mutation.
+func (m *SopNodeMutation) Name() (r string, exists bool) {
+	v := m.name
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldName returns the old "name" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldName(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldName is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldName requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldName: %w", err)
+	}
+	return oldValue.Name, nil
+}
+
+// ResetName resets all changes to the "name" field.
+func (m *SopNodeMutation) ResetName() {
+	m.name = nil
+}
+
+// SetConditionType sets the "condition_type" field.
+func (m *SopNodeMutation) SetConditionType(i int) {
+	m.condition_type = &i
+	m.addcondition_type = nil
+}
+
+// ConditionType returns the value of the "condition_type" field in the mutation.
+func (m *SopNodeMutation) ConditionType() (r int, exists bool) {
+	v := m.condition_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditionType returns the old "condition_type" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldConditionType(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditionType is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditionType requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditionType: %w", err)
+	}
+	return oldValue.ConditionType, nil
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (m *SopNodeMutation) AddConditionType(i int) {
+	if m.addcondition_type != nil {
+		*m.addcondition_type += i
+	} else {
+		m.addcondition_type = &i
+	}
+}
+
+// AddedConditionType returns the value that was added to the "condition_type" field in this mutation.
+func (m *SopNodeMutation) AddedConditionType() (r int, exists bool) {
+	v := m.addcondition_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetConditionType resets all changes to the "condition_type" field.
+func (m *SopNodeMutation) ResetConditionType() {
+	m.condition_type = nil
+	m.addcondition_type = nil
+}
+
+// SetConditionList sets the "condition_list" field.
+func (m *SopNodeMutation) SetConditionList(s []string) {
+	m.condition_list = &s
+	m.appendcondition_list = nil
+}
+
+// ConditionList returns the value of the "condition_list" field in the mutation.
+func (m *SopNodeMutation) ConditionList() (r []string, exists bool) {
+	v := m.condition_list
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditionList returns the old "condition_list" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldConditionList(ctx context.Context) (v []string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditionList is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditionList requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditionList: %w", err)
+	}
+	return oldValue.ConditionList, nil
+}
+
+// AppendConditionList adds s to the "condition_list" field.
+func (m *SopNodeMutation) AppendConditionList(s []string) {
+	m.appendcondition_list = append(m.appendcondition_list, s...)
+}
+
+// AppendedConditionList returns the list of values that were appended to the "condition_list" field in this mutation.
+func (m *SopNodeMutation) AppendedConditionList() ([]string, bool) {
+	if len(m.appendcondition_list) == 0 {
+		return nil, false
+	}
+	return m.appendcondition_list, true
+}
+
+// ClearConditionList clears the value of the "condition_list" field.
+func (m *SopNodeMutation) ClearConditionList() {
+	m.condition_list = nil
+	m.appendcondition_list = nil
+	m.clearedFields[sopnode.FieldConditionList] = struct{}{}
+}
+
+// ConditionListCleared returns if the "condition_list" field was cleared in this mutation.
+func (m *SopNodeMutation) ConditionListCleared() bool {
+	_, ok := m.clearedFields[sopnode.FieldConditionList]
+	return ok
+}
+
+// ResetConditionList resets all changes to the "condition_list" field.
+func (m *SopNodeMutation) ResetConditionList() {
+	m.condition_list = nil
+	m.appendcondition_list = nil
+	delete(m.clearedFields, sopnode.FieldConditionList)
+}
+
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (m *SopNodeMutation) SetNoReplyCondition(u uint64) {
+	m.no_reply_condition = &u
+	m.addno_reply_condition = nil
+}
+
+// NoReplyCondition returns the value of the "no_reply_condition" field in the mutation.
+func (m *SopNodeMutation) NoReplyCondition() (r uint64, exists bool) {
+	v := m.no_reply_condition
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldNoReplyCondition returns the old "no_reply_condition" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldNoReplyCondition(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldNoReplyCondition is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldNoReplyCondition requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldNoReplyCondition: %w", err)
+	}
+	return oldValue.NoReplyCondition, nil
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (m *SopNodeMutation) AddNoReplyCondition(u int64) {
+	if m.addno_reply_condition != nil {
+		*m.addno_reply_condition += u
+	} else {
+		m.addno_reply_condition = &u
+	}
+}
+
+// AddedNoReplyCondition returns the value that was added to the "no_reply_condition" field in this mutation.
+func (m *SopNodeMutation) AddedNoReplyCondition() (r int64, exists bool) {
+	v := m.addno_reply_condition
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetNoReplyCondition resets all changes to the "no_reply_condition" field.
+func (m *SopNodeMutation) ResetNoReplyCondition() {
+	m.no_reply_condition = nil
+	m.addno_reply_condition = nil
+}
+
+// SetActionMessage sets the "action_message" field.
+func (m *SopNodeMutation) SetActionMessage(ct []custom_types.Action) {
+	m.action_message = &ct
+	m.appendaction_message = nil
+}
+
+// ActionMessage returns the value of the "action_message" field in the mutation.
+func (m *SopNodeMutation) ActionMessage() (r []custom_types.Action, exists bool) {
+	v := m.action_message
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldActionMessage returns the old "action_message" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldActionMessage(ctx context.Context) (v []custom_types.Action, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldActionMessage is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldActionMessage requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldActionMessage: %w", err)
+	}
+	return oldValue.ActionMessage, nil
+}
+
+// AppendActionMessage adds ct to the "action_message" field.
+func (m *SopNodeMutation) AppendActionMessage(ct []custom_types.Action) {
+	m.appendaction_message = append(m.appendaction_message, ct...)
+}
+
+// AppendedActionMessage returns the list of values that were appended to the "action_message" field in this mutation.
+func (m *SopNodeMutation) AppendedActionMessage() ([]custom_types.Action, bool) {
+	if len(m.appendaction_message) == 0 {
+		return nil, false
+	}
+	return m.appendaction_message, true
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (m *SopNodeMutation) ClearActionMessage() {
+	m.action_message = nil
+	m.appendaction_message = nil
+	m.clearedFields[sopnode.FieldActionMessage] = struct{}{}
+}
+
+// ActionMessageCleared returns if the "action_message" field was cleared in this mutation.
+func (m *SopNodeMutation) ActionMessageCleared() bool {
+	_, ok := m.clearedFields[sopnode.FieldActionMessage]
+	return ok
+}
+
+// ResetActionMessage resets all changes to the "action_message" field.
+func (m *SopNodeMutation) ResetActionMessage() {
+	m.action_message = nil
+	m.appendaction_message = nil
+	delete(m.clearedFields, sopnode.FieldActionMessage)
+}
+
+// SetActionLabel sets the "action_label" field.
+func (m *SopNodeMutation) SetActionLabel(u []uint64) {
+	m.action_label = &u
+	m.appendaction_label = nil
+}
+
+// ActionLabel returns the value of the "action_label" field in the mutation.
+func (m *SopNodeMutation) ActionLabel() (r []uint64, exists bool) {
+	v := m.action_label
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldActionLabel returns the old "action_label" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldActionLabel(ctx context.Context) (v []uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldActionLabel is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldActionLabel requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldActionLabel: %w", err)
+	}
+	return oldValue.ActionLabel, nil
+}
+
+// AppendActionLabel adds u to the "action_label" field.
+func (m *SopNodeMutation) AppendActionLabel(u []uint64) {
+	m.appendaction_label = append(m.appendaction_label, u...)
+}
+
+// AppendedActionLabel returns the list of values that were appended to the "action_label" field in this mutation.
+func (m *SopNodeMutation) AppendedActionLabel() ([]uint64, bool) {
+	if len(m.appendaction_label) == 0 {
+		return nil, false
+	}
+	return m.appendaction_label, true
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (m *SopNodeMutation) ClearActionLabel() {
+	m.action_label = nil
+	m.appendaction_label = nil
+	m.clearedFields[sopnode.FieldActionLabel] = struct{}{}
+}
+
+// ActionLabelCleared returns if the "action_label" field was cleared in this mutation.
+func (m *SopNodeMutation) ActionLabelCleared() bool {
+	_, ok := m.clearedFields[sopnode.FieldActionLabel]
+	return ok
+}
+
+// ResetActionLabel resets all changes to the "action_label" field.
+func (m *SopNodeMutation) ResetActionLabel() {
+	m.action_label = nil
+	m.appendaction_label = nil
+	delete(m.clearedFields, sopnode.FieldActionLabel)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *SopNodeMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *SopNodeMutation) DeletedAt() (r time.Time, exists bool) {
+	v := m.deleted_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDeletedAt returns the old "deleted_at" field's value of the SopNode entity.
+// If the SopNode 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 *SopNodeMutation) OldDeletedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDeletedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err)
+	}
+	return oldValue.DeletedAt, nil
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (m *SopNodeMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[sopnode.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *SopNodeMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[sopnode.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *SopNodeMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, sopnode.FieldDeletedAt)
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by id.
+func (m *SopNodeMutation) SetSopStageID(id uint64) {
+	m.sop_stage = &id
+}
+
+// ClearSopStage clears the "sop_stage" edge to the SopStage entity.
+func (m *SopNodeMutation) ClearSopStage() {
+	m.clearedsop_stage = true
+	m.clearedFields[sopnode.FieldStageID] = struct{}{}
+}
+
+// SopStageCleared reports if the "sop_stage" edge to the SopStage entity was cleared.
+func (m *SopNodeMutation) SopStageCleared() bool {
+	return m.clearedsop_stage
+}
+
+// SopStageID returns the "sop_stage" edge ID in the mutation.
+func (m *SopNodeMutation) SopStageID() (id uint64, exists bool) {
+	if m.sop_stage != nil {
+		return *m.sop_stage, true
+	}
+	return
+}
+
+// SopStageIDs returns the "sop_stage" edge IDs in the mutation.
+// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
+// SopStageID instead. It exists only for internal usage by the builders.
+func (m *SopNodeMutation) SopStageIDs() (ids []uint64) {
+	if id := m.sop_stage; id != nil {
+		ids = append(ids, *id)
+	}
+	return
+}
+
+// ResetSopStage resets all changes to the "sop_stage" edge.
+func (m *SopNodeMutation) ResetSopStage() {
+	m.sop_stage = nil
+	m.clearedsop_stage = false
+}
+
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by ids.
+func (m *SopNodeMutation) AddNodeMessageIDs(ids ...uint64) {
+	if m.node_messages == nil {
+		m.node_messages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.node_messages[ids[i]] = struct{}{}
+	}
+}
+
+// ClearNodeMessages clears the "node_messages" edge to the MessageRecords entity.
+func (m *SopNodeMutation) ClearNodeMessages() {
+	m.clearednode_messages = true
+}
+
+// NodeMessagesCleared reports if the "node_messages" edge to the MessageRecords entity was cleared.
+func (m *SopNodeMutation) NodeMessagesCleared() bool {
+	return m.clearednode_messages
+}
+
+// RemoveNodeMessageIDs removes the "node_messages" edge to the MessageRecords entity by IDs.
+func (m *SopNodeMutation) RemoveNodeMessageIDs(ids ...uint64) {
+	if m.removednode_messages == nil {
+		m.removednode_messages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.node_messages, ids[i])
+		m.removednode_messages[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedNodeMessages returns the removed IDs of the "node_messages" edge to the MessageRecords entity.
+func (m *SopNodeMutation) RemovedNodeMessagesIDs() (ids []uint64) {
+	for id := range m.removednode_messages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// NodeMessagesIDs returns the "node_messages" edge IDs in the mutation.
+func (m *SopNodeMutation) NodeMessagesIDs() (ids []uint64) {
+	for id := range m.node_messages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetNodeMessages resets all changes to the "node_messages" edge.
+func (m *SopNodeMutation) ResetNodeMessages() {
+	m.node_messages = nil
+	m.clearednode_messages = false
+	m.removednode_messages = nil
+}
+
+// Where appends a list predicates to the SopNodeMutation builder.
+func (m *SopNodeMutation) Where(ps ...predicate.SopNode) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the SopNodeMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *SopNodeMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.SopNode, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *SopNodeMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *SopNodeMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (SopNode).
+func (m *SopNodeMutation) 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 *SopNodeMutation) Fields() []string {
+	fields := make([]string, 0, 12)
+	if m.created_at != nil {
+		fields = append(fields, sopnode.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, sopnode.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, sopnode.FieldStatus)
+	}
+	if m.sop_stage != nil {
+		fields = append(fields, sopnode.FieldStageID)
+	}
+	if m.parent_id != nil {
+		fields = append(fields, sopnode.FieldParentID)
+	}
+	if m.name != nil {
+		fields = append(fields, sopnode.FieldName)
+	}
+	if m.condition_type != nil {
+		fields = append(fields, sopnode.FieldConditionType)
+	}
+	if m.condition_list != nil {
+		fields = append(fields, sopnode.FieldConditionList)
+	}
+	if m.no_reply_condition != nil {
+		fields = append(fields, sopnode.FieldNoReplyCondition)
+	}
+	if m.action_message != nil {
+		fields = append(fields, sopnode.FieldActionMessage)
+	}
+	if m.action_label != nil {
+		fields = append(fields, sopnode.FieldActionLabel)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, sopnode.FieldDeletedAt)
+	}
+	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 *SopNodeMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case sopnode.FieldCreatedAt:
+		return m.CreatedAt()
+	case sopnode.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case sopnode.FieldStatus:
+		return m.Status()
+	case sopnode.FieldStageID:
+		return m.StageID()
+	case sopnode.FieldParentID:
+		return m.ParentID()
+	case sopnode.FieldName:
+		return m.Name()
+	case sopnode.FieldConditionType:
+		return m.ConditionType()
+	case sopnode.FieldConditionList:
+		return m.ConditionList()
+	case sopnode.FieldNoReplyCondition:
+		return m.NoReplyCondition()
+	case sopnode.FieldActionMessage:
+		return m.ActionMessage()
+	case sopnode.FieldActionLabel:
+		return m.ActionLabel()
+	case sopnode.FieldDeletedAt:
+		return m.DeletedAt()
+	}
+	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 *SopNodeMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case sopnode.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case sopnode.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case sopnode.FieldStatus:
+		return m.OldStatus(ctx)
+	case sopnode.FieldStageID:
+		return m.OldStageID(ctx)
+	case sopnode.FieldParentID:
+		return m.OldParentID(ctx)
+	case sopnode.FieldName:
+		return m.OldName(ctx)
+	case sopnode.FieldConditionType:
+		return m.OldConditionType(ctx)
+	case sopnode.FieldConditionList:
+		return m.OldConditionList(ctx)
+	case sopnode.FieldNoReplyCondition:
+		return m.OldNoReplyCondition(ctx)
+	case sopnode.FieldActionMessage:
+		return m.OldActionMessage(ctx)
+	case sopnode.FieldActionLabel:
+		return m.OldActionLabel(ctx)
+	case sopnode.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	}
+	return nil, fmt.Errorf("unknown SopNode 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 *SopNodeMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case sopnode.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 sopnode.FieldUpdatedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetUpdatedAt(v)
+		return nil
+	case sopnode.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case sopnode.FieldStageID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStageID(v)
+		return nil
+	case sopnode.FieldParentID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetParentID(v)
+		return nil
+	case sopnode.FieldName:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetName(v)
+		return nil
+	case sopnode.FieldConditionType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditionType(v)
+		return nil
+	case sopnode.FieldConditionList:
+		v, ok := value.([]string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditionList(v)
+		return nil
+	case sopnode.FieldNoReplyCondition:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetNoReplyCondition(v)
+		return nil
+	case sopnode.FieldActionMessage:
+		v, ok := value.([]custom_types.Action)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetActionMessage(v)
+		return nil
+	case sopnode.FieldActionLabel:
+		v, ok := value.([]uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetActionLabel(v)
+		return nil
+	case sopnode.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *SopNodeMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, sopnode.FieldStatus)
+	}
+	if m.addparent_id != nil {
+		fields = append(fields, sopnode.FieldParentID)
+	}
+	if m.addcondition_type != nil {
+		fields = append(fields, sopnode.FieldConditionType)
+	}
+	if m.addno_reply_condition != nil {
+		fields = append(fields, sopnode.FieldNoReplyCondition)
+	}
+	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 *SopNodeMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case sopnode.FieldStatus:
+		return m.AddedStatus()
+	case sopnode.FieldParentID:
+		return m.AddedParentID()
+	case sopnode.FieldConditionType:
+		return m.AddedConditionType()
+	case sopnode.FieldNoReplyCondition:
+		return m.AddedNoReplyCondition()
+	}
+	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 *SopNodeMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case sopnode.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case sopnode.FieldParentID:
+		v, ok := value.(int64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddParentID(v)
+		return nil
+	case sopnode.FieldConditionType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddConditionType(v)
+		return nil
+	case sopnode.FieldNoReplyCondition:
+		v, ok := value.(int64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddNoReplyCondition(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *SopNodeMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(sopnode.FieldStatus) {
+		fields = append(fields, sopnode.FieldStatus)
+	}
+	if m.FieldCleared(sopnode.FieldConditionList) {
+		fields = append(fields, sopnode.FieldConditionList)
+	}
+	if m.FieldCleared(sopnode.FieldActionMessage) {
+		fields = append(fields, sopnode.FieldActionMessage)
+	}
+	if m.FieldCleared(sopnode.FieldActionLabel) {
+		fields = append(fields, sopnode.FieldActionLabel)
+	}
+	if m.FieldCleared(sopnode.FieldDeletedAt) {
+		fields = append(fields, sopnode.FieldDeletedAt)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *SopNodeMutation) 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 *SopNodeMutation) ClearField(name string) error {
+	switch name {
+	case sopnode.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case sopnode.FieldConditionList:
+		m.ClearConditionList()
+		return nil
+	case sopnode.FieldActionMessage:
+		m.ClearActionMessage()
+		return nil
+	case sopnode.FieldActionLabel:
+		m.ClearActionLabel()
+		return nil
+	case sopnode.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode 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 *SopNodeMutation) ResetField(name string) error {
+	switch name {
+	case sopnode.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case sopnode.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case sopnode.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case sopnode.FieldStageID:
+		m.ResetStageID()
+		return nil
+	case sopnode.FieldParentID:
+		m.ResetParentID()
+		return nil
+	case sopnode.FieldName:
+		m.ResetName()
+		return nil
+	case sopnode.FieldConditionType:
+		m.ResetConditionType()
+		return nil
+	case sopnode.FieldConditionList:
+		m.ResetConditionList()
+		return nil
+	case sopnode.FieldNoReplyCondition:
+		m.ResetNoReplyCondition()
+		return nil
+	case sopnode.FieldActionMessage:
+		m.ResetActionMessage()
+		return nil
+	case sopnode.FieldActionLabel:
+		m.ResetActionLabel()
+		return nil
+	case sopnode.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *SopNodeMutation) AddedEdges() []string {
+	edges := make([]string, 0, 2)
+	if m.sop_stage != nil {
+		edges = append(edges, sopnode.EdgeSopStage)
+	}
+	if m.node_messages != nil {
+		edges = append(edges, sopnode.EdgeNodeMessages)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *SopNodeMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case sopnode.EdgeSopStage:
+		if id := m.sop_stage; id != nil {
+			return []ent.Value{*id}
+		}
+	case sopnode.EdgeNodeMessages:
+		ids := make([]ent.Value, 0, len(m.node_messages))
+		for id := range m.node_messages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *SopNodeMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 2)
+	if m.removednode_messages != nil {
+		edges = append(edges, sopnode.EdgeNodeMessages)
+	}
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *SopNodeMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case sopnode.EdgeNodeMessages:
+		ids := make([]ent.Value, 0, len(m.removednode_messages))
+		for id := range m.removednode_messages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *SopNodeMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 2)
+	if m.clearedsop_stage {
+		edges = append(edges, sopnode.EdgeSopStage)
+	}
+	if m.clearednode_messages {
+		edges = append(edges, sopnode.EdgeNodeMessages)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *SopNodeMutation) EdgeCleared(name string) bool {
+	switch name {
+	case sopnode.EdgeSopStage:
+		return m.clearedsop_stage
+	case sopnode.EdgeNodeMessages:
+		return m.clearednode_messages
+	}
+	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 *SopNodeMutation) ClearEdge(name string) error {
+	switch name {
+	case sopnode.EdgeSopStage:
+		m.ClearSopStage()
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode 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 *SopNodeMutation) ResetEdge(name string) error {
+	switch name {
+	case sopnode.EdgeSopStage:
+		m.ResetSopStage()
+		return nil
+	case sopnode.EdgeNodeMessages:
+		m.ResetNodeMessages()
+		return nil
+	}
+	return fmt.Errorf("unknown SopNode edge %s", name)
+}
+
+// SopStageMutation represents an operation that mutates the SopStage nodes in the graph.
+type SopStageMutation struct {
+	config
+	op                    Op
+	typ                   string
+	id                    *uint64
+	created_at            *time.Time
+	updated_at            *time.Time
+	status                *uint8
+	addstatus             *int8
+	name                  *string
+	condition_type        *int
+	addcondition_type     *int
+	condition_operator    *int
+	addcondition_operator *int
+	condition_list        *[]custom_types.Condition
+	appendcondition_list  []custom_types.Condition
+	action_message        *[]custom_types.Action
+	appendaction_message  []custom_types.Action
+	action_label          *[]uint64
+	appendaction_label    []uint64
+	index_sort            *int
+	addindex_sort         *int
+	deleted_at            *time.Time
+	clearedFields         map[string]struct{}
+	sop_task              *uint64
+	clearedsop_task       bool
+	stage_nodes           map[uint64]struct{}
+	removedstage_nodes    map[uint64]struct{}
+	clearedstage_nodes    bool
+	stage_messages        map[uint64]struct{}
+	removedstage_messages map[uint64]struct{}
+	clearedstage_messages bool
+	done                  bool
+	oldValue              func(context.Context) (*SopStage, error)
+	predicates            []predicate.SopStage
+}
+
+var _ ent.Mutation = (*SopStageMutation)(nil)
+
+// sopstageOption allows management of the mutation configuration using functional options.
+type sopstageOption func(*SopStageMutation)
+
+// newSopStageMutation creates new mutation for the SopStage entity.
+func newSopStageMutation(c config, op Op, opts ...sopstageOption) *SopStageMutation {
+	m := &SopStageMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeSopStage,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withSopStageID sets the ID field of the mutation.
+func withSopStageID(id uint64) sopstageOption {
+	return func(m *SopStageMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *SopStage
+		)
+		m.oldValue = func(ctx context.Context) (*SopStage, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().SopStage.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withSopStage sets the old SopStage of the mutation.
+func withSopStage(node *SopStage) sopstageOption {
+	return func(m *SopStageMutation) {
+		m.oldValue = func(context.Context) (*SopStage, 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 SopStageMutation) 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 SopStageMutation) 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
+}
+
+// SetID sets the value of the id field. Note that this
+// operation is only accepted on creation of SopStage entities.
+func (m *SopStageMutation) SetID(id uint64) {
+	m.id = &id
+}
+
+// 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 *SopStageMutation) ID() (id uint64, 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 *SopStageMutation) IDs(ctx context.Context) ([]uint64, error) {
+	switch {
+	case m.op.Is(OpUpdateOne | OpDeleteOne):
+		id, exists := m.ID()
+		if exists {
+			return []uint64{id}, nil
+		}
+		fallthrough
+	case m.op.Is(OpUpdate | OpDelete):
+		return m.Client().SopStage.Query().Where(m.predicates...).IDs(ctx)
+	default:
+		return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
+	}
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (m *SopStageMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *SopStageMutation) 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 SopStage entity.
+// If the SopStage 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 *SopStageMutation) 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 *SopStageMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *SopStageMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *SopStageMutation) UpdatedAt() (r time.Time, exists bool) {
+	v := m.updated_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldUpdatedAt returns the old "updated_at" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
+	}
+	return oldValue.UpdatedAt, nil
+}
+
+// ResetUpdatedAt resets all changes to the "updated_at" field.
+func (m *SopStageMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *SopStageMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *SopStageMutation) Status() (r uint8, exists bool) {
+	v := m.status
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStatus returns the old "status" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldStatus(ctx context.Context) (v uint8, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStatus is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStatus requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStatus: %w", err)
+	}
+	return oldValue.Status, nil
+}
+
+// AddStatus adds u to the "status" field.
+func (m *SopStageMutation) AddStatus(u int8) {
+	if m.addstatus != nil {
+		*m.addstatus += u
+	} else {
+		m.addstatus = &u
+	}
+}
+
+// AddedStatus returns the value that was added to the "status" field in this mutation.
+func (m *SopStageMutation) AddedStatus() (r int8, exists bool) {
+	v := m.addstatus
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearStatus clears the value of the "status" field.
+func (m *SopStageMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[sopstage.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *SopStageMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[sopstage.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *SopStageMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, sopstage.FieldStatus)
+}
+
+// SetTaskID sets the "task_id" field.
+func (m *SopStageMutation) SetTaskID(u uint64) {
+	m.sop_task = &u
+}
+
+// TaskID returns the value of the "task_id" field in the mutation.
+func (m *SopStageMutation) TaskID() (r uint64, exists bool) {
+	v := m.sop_task
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldTaskID returns the old "task_id" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldTaskID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldTaskID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldTaskID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldTaskID: %w", err)
+	}
+	return oldValue.TaskID, nil
+}
+
+// ResetTaskID resets all changes to the "task_id" field.
+func (m *SopStageMutation) ResetTaskID() {
+	m.sop_task = nil
+}
+
+// SetName sets the "name" field.
+func (m *SopStageMutation) SetName(s string) {
+	m.name = &s
+}
+
+// Name returns the value of the "name" field in the mutation.
+func (m *SopStageMutation) Name() (r string, exists bool) {
+	v := m.name
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldName returns the old "name" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldName(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldName is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldName requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldName: %w", err)
+	}
+	return oldValue.Name, nil
+}
+
+// ResetName resets all changes to the "name" field.
+func (m *SopStageMutation) ResetName() {
+	m.name = nil
+}
+
+// SetConditionType sets the "condition_type" field.
+func (m *SopStageMutation) SetConditionType(i int) {
+	m.condition_type = &i
+	m.addcondition_type = nil
+}
+
+// ConditionType returns the value of the "condition_type" field in the mutation.
+func (m *SopStageMutation) ConditionType() (r int, exists bool) {
+	v := m.condition_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditionType returns the old "condition_type" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldConditionType(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditionType is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditionType requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditionType: %w", err)
+	}
+	return oldValue.ConditionType, nil
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (m *SopStageMutation) AddConditionType(i int) {
+	if m.addcondition_type != nil {
+		*m.addcondition_type += i
+	} else {
+		m.addcondition_type = &i
+	}
+}
+
+// AddedConditionType returns the value that was added to the "condition_type" field in this mutation.
+func (m *SopStageMutation) AddedConditionType() (r int, exists bool) {
+	v := m.addcondition_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetConditionType resets all changes to the "condition_type" field.
+func (m *SopStageMutation) ResetConditionType() {
+	m.condition_type = nil
+	m.addcondition_type = nil
+}
+
+// SetConditionOperator sets the "condition_operator" field.
+func (m *SopStageMutation) SetConditionOperator(i int) {
+	m.condition_operator = &i
+	m.addcondition_operator = nil
+}
+
+// ConditionOperator returns the value of the "condition_operator" field in the mutation.
+func (m *SopStageMutation) ConditionOperator() (r int, exists bool) {
+	v := m.condition_operator
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditionOperator returns the old "condition_operator" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldConditionOperator(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditionOperator is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditionOperator requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditionOperator: %w", err)
+	}
+	return oldValue.ConditionOperator, nil
+}
+
+// AddConditionOperator adds i to the "condition_operator" field.
+func (m *SopStageMutation) AddConditionOperator(i int) {
+	if m.addcondition_operator != nil {
+		*m.addcondition_operator += i
+	} else {
+		m.addcondition_operator = &i
+	}
+}
+
+// AddedConditionOperator returns the value that was added to the "condition_operator" field in this mutation.
+func (m *SopStageMutation) AddedConditionOperator() (r int, exists bool) {
+	v := m.addcondition_operator
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetConditionOperator resets all changes to the "condition_operator" field.
+func (m *SopStageMutation) ResetConditionOperator() {
+	m.condition_operator = nil
+	m.addcondition_operator = nil
+}
+
+// SetConditionList sets the "condition_list" field.
+func (m *SopStageMutation) SetConditionList(ct []custom_types.Condition) {
+	m.condition_list = &ct
+	m.appendcondition_list = nil
+}
+
+// ConditionList returns the value of the "condition_list" field in the mutation.
+func (m *SopStageMutation) ConditionList() (r []custom_types.Condition, exists bool) {
+	v := m.condition_list
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditionList returns the old "condition_list" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldConditionList(ctx context.Context) (v []custom_types.Condition, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditionList is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditionList requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditionList: %w", err)
+	}
+	return oldValue.ConditionList, nil
+}
+
+// AppendConditionList adds ct to the "condition_list" field.
+func (m *SopStageMutation) AppendConditionList(ct []custom_types.Condition) {
+	m.appendcondition_list = append(m.appendcondition_list, ct...)
+}
+
+// AppendedConditionList returns the list of values that were appended to the "condition_list" field in this mutation.
+func (m *SopStageMutation) AppendedConditionList() ([]custom_types.Condition, bool) {
+	if len(m.appendcondition_list) == 0 {
+		return nil, false
+	}
+	return m.appendcondition_list, true
+}
+
+// ResetConditionList resets all changes to the "condition_list" field.
+func (m *SopStageMutation) ResetConditionList() {
+	m.condition_list = nil
+	m.appendcondition_list = nil
+}
+
+// SetActionMessage sets the "action_message" field.
+func (m *SopStageMutation) SetActionMessage(ct []custom_types.Action) {
+	m.action_message = &ct
+	m.appendaction_message = nil
+}
+
+// ActionMessage returns the value of the "action_message" field in the mutation.
+func (m *SopStageMutation) ActionMessage() (r []custom_types.Action, exists bool) {
+	v := m.action_message
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldActionMessage returns the old "action_message" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldActionMessage(ctx context.Context) (v []custom_types.Action, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldActionMessage is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldActionMessage requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldActionMessage: %w", err)
+	}
+	return oldValue.ActionMessage, nil
+}
+
+// AppendActionMessage adds ct to the "action_message" field.
+func (m *SopStageMutation) AppendActionMessage(ct []custom_types.Action) {
+	m.appendaction_message = append(m.appendaction_message, ct...)
+}
+
+// AppendedActionMessage returns the list of values that were appended to the "action_message" field in this mutation.
+func (m *SopStageMutation) AppendedActionMessage() ([]custom_types.Action, bool) {
+	if len(m.appendaction_message) == 0 {
+		return nil, false
+	}
+	return m.appendaction_message, true
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (m *SopStageMutation) ClearActionMessage() {
+	m.action_message = nil
+	m.appendaction_message = nil
+	m.clearedFields[sopstage.FieldActionMessage] = struct{}{}
+}
+
+// ActionMessageCleared returns if the "action_message" field was cleared in this mutation.
+func (m *SopStageMutation) ActionMessageCleared() bool {
+	_, ok := m.clearedFields[sopstage.FieldActionMessage]
+	return ok
+}
+
+// ResetActionMessage resets all changes to the "action_message" field.
+func (m *SopStageMutation) ResetActionMessage() {
+	m.action_message = nil
+	m.appendaction_message = nil
+	delete(m.clearedFields, sopstage.FieldActionMessage)
+}
+
+// SetActionLabel sets the "action_label" field.
+func (m *SopStageMutation) SetActionLabel(u []uint64) {
+	m.action_label = &u
+	m.appendaction_label = nil
+}
+
+// ActionLabel returns the value of the "action_label" field in the mutation.
+func (m *SopStageMutation) ActionLabel() (r []uint64, exists bool) {
+	v := m.action_label
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldActionLabel returns the old "action_label" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldActionLabel(ctx context.Context) (v []uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldActionLabel is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldActionLabel requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldActionLabel: %w", err)
+	}
+	return oldValue.ActionLabel, nil
+}
+
+// AppendActionLabel adds u to the "action_label" field.
+func (m *SopStageMutation) AppendActionLabel(u []uint64) {
+	m.appendaction_label = append(m.appendaction_label, u...)
+}
+
+// AppendedActionLabel returns the list of values that were appended to the "action_label" field in this mutation.
+func (m *SopStageMutation) AppendedActionLabel() ([]uint64, bool) {
+	if len(m.appendaction_label) == 0 {
+		return nil, false
+	}
+	return m.appendaction_label, true
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (m *SopStageMutation) ClearActionLabel() {
+	m.action_label = nil
+	m.appendaction_label = nil
+	m.clearedFields[sopstage.FieldActionLabel] = struct{}{}
+}
+
+// ActionLabelCleared returns if the "action_label" field was cleared in this mutation.
+func (m *SopStageMutation) ActionLabelCleared() bool {
+	_, ok := m.clearedFields[sopstage.FieldActionLabel]
+	return ok
+}
+
+// ResetActionLabel resets all changes to the "action_label" field.
+func (m *SopStageMutation) ResetActionLabel() {
+	m.action_label = nil
+	m.appendaction_label = nil
+	delete(m.clearedFields, sopstage.FieldActionLabel)
+}
+
+// SetIndexSort sets the "index_sort" field.
+func (m *SopStageMutation) SetIndexSort(i int) {
+	m.index_sort = &i
+	m.addindex_sort = nil
+}
+
+// IndexSort returns the value of the "index_sort" field in the mutation.
+func (m *SopStageMutation) IndexSort() (r int, exists bool) {
+	v := m.index_sort
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldIndexSort returns the old "index_sort" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldIndexSort(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldIndexSort is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldIndexSort requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldIndexSort: %w", err)
+	}
+	return oldValue.IndexSort, nil
+}
+
+// AddIndexSort adds i to the "index_sort" field.
+func (m *SopStageMutation) AddIndexSort(i int) {
+	if m.addindex_sort != nil {
+		*m.addindex_sort += i
+	} else {
+		m.addindex_sort = &i
+	}
+}
+
+// AddedIndexSort returns the value that was added to the "index_sort" field in this mutation.
+func (m *SopStageMutation) AddedIndexSort() (r int, exists bool) {
+	v := m.addindex_sort
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearIndexSort clears the value of the "index_sort" field.
+func (m *SopStageMutation) ClearIndexSort() {
+	m.index_sort = nil
+	m.addindex_sort = nil
+	m.clearedFields[sopstage.FieldIndexSort] = struct{}{}
+}
+
+// IndexSortCleared returns if the "index_sort" field was cleared in this mutation.
+func (m *SopStageMutation) IndexSortCleared() bool {
+	_, ok := m.clearedFields[sopstage.FieldIndexSort]
+	return ok
+}
+
+// ResetIndexSort resets all changes to the "index_sort" field.
+func (m *SopStageMutation) ResetIndexSort() {
+	m.index_sort = nil
+	m.addindex_sort = nil
+	delete(m.clearedFields, sopstage.FieldIndexSort)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *SopStageMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *SopStageMutation) DeletedAt() (r time.Time, exists bool) {
+	v := m.deleted_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDeletedAt returns the old "deleted_at" field's value of the SopStage entity.
+// If the SopStage 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 *SopStageMutation) OldDeletedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDeletedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err)
+	}
+	return oldValue.DeletedAt, nil
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (m *SopStageMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[sopstage.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *SopStageMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[sopstage.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *SopStageMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, sopstage.FieldDeletedAt)
+}
+
+// SetSopTaskID sets the "sop_task" edge to the SopTask entity by id.
+func (m *SopStageMutation) SetSopTaskID(id uint64) {
+	m.sop_task = &id
+}
+
+// ClearSopTask clears the "sop_task" edge to the SopTask entity.
+func (m *SopStageMutation) ClearSopTask() {
+	m.clearedsop_task = true
+	m.clearedFields[sopstage.FieldTaskID] = struct{}{}
+}
+
+// SopTaskCleared reports if the "sop_task" edge to the SopTask entity was cleared.
+func (m *SopStageMutation) SopTaskCleared() bool {
+	return m.clearedsop_task
+}
+
+// SopTaskID returns the "sop_task" edge ID in the mutation.
+func (m *SopStageMutation) SopTaskID() (id uint64, exists bool) {
+	if m.sop_task != nil {
+		return *m.sop_task, true
+	}
+	return
+}
+
+// SopTaskIDs returns the "sop_task" edge IDs in the mutation.
+// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
+// SopTaskID instead. It exists only for internal usage by the builders.
+func (m *SopStageMutation) SopTaskIDs() (ids []uint64) {
+	if id := m.sop_task; id != nil {
+		ids = append(ids, *id)
+	}
+	return
+}
+
+// ResetSopTask resets all changes to the "sop_task" edge.
+func (m *SopStageMutation) ResetSopTask() {
+	m.sop_task = nil
+	m.clearedsop_task = false
+}
+
+// AddStageNodeIDs adds the "stage_nodes" edge to the SopNode entity by ids.
+func (m *SopStageMutation) AddStageNodeIDs(ids ...uint64) {
+	if m.stage_nodes == nil {
+		m.stage_nodes = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.stage_nodes[ids[i]] = struct{}{}
+	}
+}
+
+// ClearStageNodes clears the "stage_nodes" edge to the SopNode entity.
+func (m *SopStageMutation) ClearStageNodes() {
+	m.clearedstage_nodes = true
+}
+
+// StageNodesCleared reports if the "stage_nodes" edge to the SopNode entity was cleared.
+func (m *SopStageMutation) StageNodesCleared() bool {
+	return m.clearedstage_nodes
+}
+
+// RemoveStageNodeIDs removes the "stage_nodes" edge to the SopNode entity by IDs.
+func (m *SopStageMutation) RemoveStageNodeIDs(ids ...uint64) {
+	if m.removedstage_nodes == nil {
+		m.removedstage_nodes = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.stage_nodes, ids[i])
+		m.removedstage_nodes[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedStageNodes returns the removed IDs of the "stage_nodes" edge to the SopNode entity.
+func (m *SopStageMutation) RemovedStageNodesIDs() (ids []uint64) {
+	for id := range m.removedstage_nodes {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// StageNodesIDs returns the "stage_nodes" edge IDs in the mutation.
+func (m *SopStageMutation) StageNodesIDs() (ids []uint64) {
+	for id := range m.stage_nodes {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetStageNodes resets all changes to the "stage_nodes" edge.
+func (m *SopStageMutation) ResetStageNodes() {
+	m.stage_nodes = nil
+	m.clearedstage_nodes = false
+	m.removedstage_nodes = nil
+}
+
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by ids.
+func (m *SopStageMutation) AddStageMessageIDs(ids ...uint64) {
+	if m.stage_messages == nil {
+		m.stage_messages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.stage_messages[ids[i]] = struct{}{}
+	}
+}
+
+// ClearStageMessages clears the "stage_messages" edge to the MessageRecords entity.
+func (m *SopStageMutation) ClearStageMessages() {
+	m.clearedstage_messages = true
+}
+
+// StageMessagesCleared reports if the "stage_messages" edge to the MessageRecords entity was cleared.
+func (m *SopStageMutation) StageMessagesCleared() bool {
+	return m.clearedstage_messages
+}
+
+// RemoveStageMessageIDs removes the "stage_messages" edge to the MessageRecords entity by IDs.
+func (m *SopStageMutation) RemoveStageMessageIDs(ids ...uint64) {
+	if m.removedstage_messages == nil {
+		m.removedstage_messages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.stage_messages, ids[i])
+		m.removedstage_messages[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedStageMessages returns the removed IDs of the "stage_messages" edge to the MessageRecords entity.
+func (m *SopStageMutation) RemovedStageMessagesIDs() (ids []uint64) {
+	for id := range m.removedstage_messages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// StageMessagesIDs returns the "stage_messages" edge IDs in the mutation.
+func (m *SopStageMutation) StageMessagesIDs() (ids []uint64) {
+	for id := range m.stage_messages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetStageMessages resets all changes to the "stage_messages" edge.
+func (m *SopStageMutation) ResetStageMessages() {
+	m.stage_messages = nil
+	m.clearedstage_messages = false
+	m.removedstage_messages = nil
+}
+
+// Where appends a list predicates to the SopStageMutation builder.
+func (m *SopStageMutation) Where(ps ...predicate.SopStage) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the SopStageMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *SopStageMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.SopStage, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *SopStageMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *SopStageMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (SopStage).
+func (m *SopStageMutation) 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 *SopStageMutation) Fields() []string {
+	fields := make([]string, 0, 12)
+	if m.created_at != nil {
+		fields = append(fields, sopstage.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, sopstage.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, sopstage.FieldStatus)
+	}
+	if m.sop_task != nil {
+		fields = append(fields, sopstage.FieldTaskID)
+	}
+	if m.name != nil {
+		fields = append(fields, sopstage.FieldName)
+	}
+	if m.condition_type != nil {
+		fields = append(fields, sopstage.FieldConditionType)
+	}
+	if m.condition_operator != nil {
+		fields = append(fields, sopstage.FieldConditionOperator)
+	}
+	if m.condition_list != nil {
+		fields = append(fields, sopstage.FieldConditionList)
+	}
+	if m.action_message != nil {
+		fields = append(fields, sopstage.FieldActionMessage)
+	}
+	if m.action_label != nil {
+		fields = append(fields, sopstage.FieldActionLabel)
+	}
+	if m.index_sort != nil {
+		fields = append(fields, sopstage.FieldIndexSort)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, sopstage.FieldDeletedAt)
+	}
+	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 *SopStageMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case sopstage.FieldCreatedAt:
+		return m.CreatedAt()
+	case sopstage.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case sopstage.FieldStatus:
+		return m.Status()
+	case sopstage.FieldTaskID:
+		return m.TaskID()
+	case sopstage.FieldName:
+		return m.Name()
+	case sopstage.FieldConditionType:
+		return m.ConditionType()
+	case sopstage.FieldConditionOperator:
+		return m.ConditionOperator()
+	case sopstage.FieldConditionList:
+		return m.ConditionList()
+	case sopstage.FieldActionMessage:
+		return m.ActionMessage()
+	case sopstage.FieldActionLabel:
+		return m.ActionLabel()
+	case sopstage.FieldIndexSort:
+		return m.IndexSort()
+	case sopstage.FieldDeletedAt:
+		return m.DeletedAt()
+	}
+	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 *SopStageMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case sopstage.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case sopstage.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case sopstage.FieldStatus:
+		return m.OldStatus(ctx)
+	case sopstage.FieldTaskID:
+		return m.OldTaskID(ctx)
+	case sopstage.FieldName:
+		return m.OldName(ctx)
+	case sopstage.FieldConditionType:
+		return m.OldConditionType(ctx)
+	case sopstage.FieldConditionOperator:
+		return m.OldConditionOperator(ctx)
+	case sopstage.FieldConditionList:
+		return m.OldConditionList(ctx)
+	case sopstage.FieldActionMessage:
+		return m.OldActionMessage(ctx)
+	case sopstage.FieldActionLabel:
+		return m.OldActionLabel(ctx)
+	case sopstage.FieldIndexSort:
+		return m.OldIndexSort(ctx)
+	case sopstage.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	}
+	return nil, fmt.Errorf("unknown SopStage 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 *SopStageMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case sopstage.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 sopstage.FieldUpdatedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetUpdatedAt(v)
+		return nil
+	case sopstage.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case sopstage.FieldTaskID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetTaskID(v)
+		return nil
+	case sopstage.FieldName:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetName(v)
+		return nil
+	case sopstage.FieldConditionType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditionType(v)
+		return nil
+	case sopstage.FieldConditionOperator:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditionOperator(v)
+		return nil
+	case sopstage.FieldConditionList:
+		v, ok := value.([]custom_types.Condition)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditionList(v)
+		return nil
+	case sopstage.FieldActionMessage:
+		v, ok := value.([]custom_types.Action)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetActionMessage(v)
+		return nil
+	case sopstage.FieldActionLabel:
+		v, ok := value.([]uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetActionLabel(v)
+		return nil
+	case sopstage.FieldIndexSort:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetIndexSort(v)
+		return nil
+	case sopstage.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *SopStageMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, sopstage.FieldStatus)
+	}
+	if m.addcondition_type != nil {
+		fields = append(fields, sopstage.FieldConditionType)
+	}
+	if m.addcondition_operator != nil {
+		fields = append(fields, sopstage.FieldConditionOperator)
+	}
+	if m.addindex_sort != nil {
+		fields = append(fields, sopstage.FieldIndexSort)
+	}
+	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 *SopStageMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case sopstage.FieldStatus:
+		return m.AddedStatus()
+	case sopstage.FieldConditionType:
+		return m.AddedConditionType()
+	case sopstage.FieldConditionOperator:
+		return m.AddedConditionOperator()
+	case sopstage.FieldIndexSort:
+		return m.AddedIndexSort()
+	}
+	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 *SopStageMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case sopstage.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case sopstage.FieldConditionType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddConditionType(v)
+		return nil
+	case sopstage.FieldConditionOperator:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddConditionOperator(v)
+		return nil
+	case sopstage.FieldIndexSort:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddIndexSort(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *SopStageMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(sopstage.FieldStatus) {
+		fields = append(fields, sopstage.FieldStatus)
+	}
+	if m.FieldCleared(sopstage.FieldActionMessage) {
+		fields = append(fields, sopstage.FieldActionMessage)
+	}
+	if m.FieldCleared(sopstage.FieldActionLabel) {
+		fields = append(fields, sopstage.FieldActionLabel)
+	}
+	if m.FieldCleared(sopstage.FieldIndexSort) {
+		fields = append(fields, sopstage.FieldIndexSort)
+	}
+	if m.FieldCleared(sopstage.FieldDeletedAt) {
+		fields = append(fields, sopstage.FieldDeletedAt)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *SopStageMutation) 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 *SopStageMutation) ClearField(name string) error {
+	switch name {
+	case sopstage.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case sopstage.FieldActionMessage:
+		m.ClearActionMessage()
+		return nil
+	case sopstage.FieldActionLabel:
+		m.ClearActionLabel()
+		return nil
+	case sopstage.FieldIndexSort:
+		m.ClearIndexSort()
+		return nil
+	case sopstage.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage 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 *SopStageMutation) ResetField(name string) error {
+	switch name {
+	case sopstage.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case sopstage.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case sopstage.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case sopstage.FieldTaskID:
+		m.ResetTaskID()
+		return nil
+	case sopstage.FieldName:
+		m.ResetName()
+		return nil
+	case sopstage.FieldConditionType:
+		m.ResetConditionType()
+		return nil
+	case sopstage.FieldConditionOperator:
+		m.ResetConditionOperator()
+		return nil
+	case sopstage.FieldConditionList:
+		m.ResetConditionList()
+		return nil
+	case sopstage.FieldActionMessage:
+		m.ResetActionMessage()
+		return nil
+	case sopstage.FieldActionLabel:
+		m.ResetActionLabel()
+		return nil
+	case sopstage.FieldIndexSort:
+		m.ResetIndexSort()
+		return nil
+	case sopstage.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *SopStageMutation) AddedEdges() []string {
+	edges := make([]string, 0, 3)
+	if m.sop_task != nil {
+		edges = append(edges, sopstage.EdgeSopTask)
+	}
+	if m.stage_nodes != nil {
+		edges = append(edges, sopstage.EdgeStageNodes)
+	}
+	if m.stage_messages != nil {
+		edges = append(edges, sopstage.EdgeStageMessages)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *SopStageMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case sopstage.EdgeSopTask:
+		if id := m.sop_task; id != nil {
+			return []ent.Value{*id}
+		}
+	case sopstage.EdgeStageNodes:
+		ids := make([]ent.Value, 0, len(m.stage_nodes))
+		for id := range m.stage_nodes {
+			ids = append(ids, id)
+		}
+		return ids
+	case sopstage.EdgeStageMessages:
+		ids := make([]ent.Value, 0, len(m.stage_messages))
+		for id := range m.stage_messages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *SopStageMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 3)
+	if m.removedstage_nodes != nil {
+		edges = append(edges, sopstage.EdgeStageNodes)
+	}
+	if m.removedstage_messages != nil {
+		edges = append(edges, sopstage.EdgeStageMessages)
+	}
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *SopStageMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case sopstage.EdgeStageNodes:
+		ids := make([]ent.Value, 0, len(m.removedstage_nodes))
+		for id := range m.removedstage_nodes {
+			ids = append(ids, id)
+		}
+		return ids
+	case sopstage.EdgeStageMessages:
+		ids := make([]ent.Value, 0, len(m.removedstage_messages))
+		for id := range m.removedstage_messages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *SopStageMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 3)
+	if m.clearedsop_task {
+		edges = append(edges, sopstage.EdgeSopTask)
+	}
+	if m.clearedstage_nodes {
+		edges = append(edges, sopstage.EdgeStageNodes)
+	}
+	if m.clearedstage_messages {
+		edges = append(edges, sopstage.EdgeStageMessages)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *SopStageMutation) EdgeCleared(name string) bool {
+	switch name {
+	case sopstage.EdgeSopTask:
+		return m.clearedsop_task
+	case sopstage.EdgeStageNodes:
+		return m.clearedstage_nodes
+	case sopstage.EdgeStageMessages:
+		return m.clearedstage_messages
+	}
+	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 *SopStageMutation) ClearEdge(name string) error {
+	switch name {
+	case sopstage.EdgeSopTask:
+		m.ClearSopTask()
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage 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 *SopStageMutation) ResetEdge(name string) error {
+	switch name {
+	case sopstage.EdgeSopTask:
+		m.ResetSopTask()
+		return nil
+	case sopstage.EdgeStageNodes:
+		m.ResetStageNodes()
+		return nil
+	case sopstage.EdgeStageMessages:
+		m.ResetStageMessages()
+		return nil
+	}
+	return fmt.Errorf("unknown SopStage edge %s", name)
+}
+
+// SopTaskMutation represents an operation that mutates the SopTask nodes in the graph.
+type SopTaskMutation struct {
+	config
+	op                  Op
+	typ                 string
+	id                  *uint64
+	created_at          *time.Time
+	updated_at          *time.Time
+	status              *uint8
+	addstatus           *int8
+	name                *string
+	bot_wxid_list       *[]string
+	appendbot_wxid_list []string
+	_type               *int
+	add_type            *int
+	plan_start_time     *time.Time
+	plan_end_time       *time.Time
+	creator_id          *string
+	deleted_at          *time.Time
+	clearedFields       map[string]struct{}
+	task_stages         map[uint64]struct{}
+	removedtask_stages  map[uint64]struct{}
+	clearedtask_stages  bool
+	done                bool
+	oldValue            func(context.Context) (*SopTask, error)
+	predicates          []predicate.SopTask
+}
+
+var _ ent.Mutation = (*SopTaskMutation)(nil)
+
+// soptaskOption allows management of the mutation configuration using functional options.
+type soptaskOption func(*SopTaskMutation)
+
+// newSopTaskMutation creates new mutation for the SopTask entity.
+func newSopTaskMutation(c config, op Op, opts ...soptaskOption) *SopTaskMutation {
+	m := &SopTaskMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeSopTask,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withSopTaskID sets the ID field of the mutation.
+func withSopTaskID(id uint64) soptaskOption {
+	return func(m *SopTaskMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *SopTask
+		)
+		m.oldValue = func(ctx context.Context) (*SopTask, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().SopTask.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withSopTask sets the old SopTask of the mutation.
+func withSopTask(node *SopTask) soptaskOption {
+	return func(m *SopTaskMutation) {
+		m.oldValue = func(context.Context) (*SopTask, 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 SopTaskMutation) 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 SopTaskMutation) 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
+}
+
+// SetID sets the value of the id field. Note that this
+// operation is only accepted on creation of SopTask entities.
+func (m *SopTaskMutation) SetID(id uint64) {
+	m.id = &id
+}
+
+// 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 *SopTaskMutation) ID() (id uint64, 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 *SopTaskMutation) IDs(ctx context.Context) ([]uint64, error) {
+	switch {
+	case m.op.Is(OpUpdateOne | OpDeleteOne):
+		id, exists := m.ID()
+		if exists {
+			return []uint64{id}, nil
+		}
+		fallthrough
+	case m.op.Is(OpUpdate | OpDelete):
+		return m.Client().SopTask.Query().Where(m.predicates...).IDs(ctx)
+	default:
+		return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
+	}
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (m *SopTaskMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *SopTaskMutation) 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 SopTask entity.
+// If the SopTask 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 *SopTaskMutation) 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 *SopTaskMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *SopTaskMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *SopTaskMutation) UpdatedAt() (r time.Time, exists bool) {
+	v := m.updated_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldUpdatedAt returns the old "updated_at" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
+	}
+	return oldValue.UpdatedAt, nil
+}
+
+// ResetUpdatedAt resets all changes to the "updated_at" field.
+func (m *SopTaskMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *SopTaskMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *SopTaskMutation) Status() (r uint8, exists bool) {
+	v := m.status
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStatus returns the old "status" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldStatus(ctx context.Context) (v uint8, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStatus is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStatus requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStatus: %w", err)
+	}
+	return oldValue.Status, nil
+}
+
+// AddStatus adds u to the "status" field.
+func (m *SopTaskMutation) AddStatus(u int8) {
+	if m.addstatus != nil {
+		*m.addstatus += u
+	} else {
+		m.addstatus = &u
+	}
+}
+
+// AddedStatus returns the value that was added to the "status" field in this mutation.
+func (m *SopTaskMutation) AddedStatus() (r int8, exists bool) {
+	v := m.addstatus
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearStatus clears the value of the "status" field.
+func (m *SopTaskMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[soptask.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *SopTaskMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *SopTaskMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, soptask.FieldStatus)
+}
+
+// SetName sets the "name" field.
+func (m *SopTaskMutation) SetName(s string) {
+	m.name = &s
+}
+
+// Name returns the value of the "name" field in the mutation.
+func (m *SopTaskMutation) Name() (r string, exists bool) {
+	v := m.name
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldName returns the old "name" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldName(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldName is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldName requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldName: %w", err)
+	}
+	return oldValue.Name, nil
+}
+
+// ResetName resets all changes to the "name" field.
+func (m *SopTaskMutation) ResetName() {
+	m.name = nil
+}
+
+// SetBotWxidList sets the "bot_wxid_list" field.
+func (m *SopTaskMutation) SetBotWxidList(s []string) {
+	m.bot_wxid_list = &s
+	m.appendbot_wxid_list = nil
+}
+
+// BotWxidList returns the value of the "bot_wxid_list" field in the mutation.
+func (m *SopTaskMutation) BotWxidList() (r []string, exists bool) {
+	v := m.bot_wxid_list
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldBotWxidList returns the old "bot_wxid_list" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldBotWxidList(ctx context.Context) (v []string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldBotWxidList is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldBotWxidList requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldBotWxidList: %w", err)
+	}
+	return oldValue.BotWxidList, nil
+}
+
+// AppendBotWxidList adds s to the "bot_wxid_list" field.
+func (m *SopTaskMutation) AppendBotWxidList(s []string) {
+	m.appendbot_wxid_list = append(m.appendbot_wxid_list, s...)
+}
+
+// AppendedBotWxidList returns the list of values that were appended to the "bot_wxid_list" field in this mutation.
+func (m *SopTaskMutation) AppendedBotWxidList() ([]string, bool) {
+	if len(m.appendbot_wxid_list) == 0 {
+		return nil, false
+	}
+	return m.appendbot_wxid_list, true
+}
+
+// ClearBotWxidList clears the value of the "bot_wxid_list" field.
+func (m *SopTaskMutation) ClearBotWxidList() {
+	m.bot_wxid_list = nil
+	m.appendbot_wxid_list = nil
+	m.clearedFields[soptask.FieldBotWxidList] = struct{}{}
+}
+
+// BotWxidListCleared returns if the "bot_wxid_list" field was cleared in this mutation.
+func (m *SopTaskMutation) BotWxidListCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldBotWxidList]
+	return ok
+}
+
+// ResetBotWxidList resets all changes to the "bot_wxid_list" field.
+func (m *SopTaskMutation) ResetBotWxidList() {
+	m.bot_wxid_list = nil
+	m.appendbot_wxid_list = nil
+	delete(m.clearedFields, soptask.FieldBotWxidList)
+}
+
+// SetType sets the "type" field.
+func (m *SopTaskMutation) SetType(i int) {
+	m._type = &i
+	m.add_type = nil
+}
+
+// GetType returns the value of the "type" field in the mutation.
+func (m *SopTaskMutation) GetType() (r int, exists bool) {
+	v := m._type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldType returns the old "type" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldType(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldType is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldType requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldType: %w", err)
+	}
+	return oldValue.Type, nil
+}
+
+// AddType adds i to the "type" field.
+func (m *SopTaskMutation) AddType(i int) {
+	if m.add_type != nil {
+		*m.add_type += i
+	} else {
+		m.add_type = &i
+	}
+}
+
+// AddedType returns the value that was added to the "type" field in this mutation.
+func (m *SopTaskMutation) AddedType() (r int, exists bool) {
+	v := m.add_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetType resets all changes to the "type" field.
+func (m *SopTaskMutation) ResetType() {
+	m._type = nil
+	m.add_type = nil
+}
+
+// SetPlanStartTime sets the "plan_start_time" field.
+func (m *SopTaskMutation) SetPlanStartTime(t time.Time) {
+	m.plan_start_time = &t
+}
+
+// PlanStartTime returns the value of the "plan_start_time" field in the mutation.
+func (m *SopTaskMutation) PlanStartTime() (r time.Time, exists bool) {
+	v := m.plan_start_time
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldPlanStartTime returns the old "plan_start_time" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldPlanStartTime(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldPlanStartTime is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldPlanStartTime requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldPlanStartTime: %w", err)
+	}
+	return oldValue.PlanStartTime, nil
+}
+
+// ClearPlanStartTime clears the value of the "plan_start_time" field.
+func (m *SopTaskMutation) ClearPlanStartTime() {
+	m.plan_start_time = nil
+	m.clearedFields[soptask.FieldPlanStartTime] = struct{}{}
+}
+
+// PlanStartTimeCleared returns if the "plan_start_time" field was cleared in this mutation.
+func (m *SopTaskMutation) PlanStartTimeCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldPlanStartTime]
+	return ok
+}
+
+// ResetPlanStartTime resets all changes to the "plan_start_time" field.
+func (m *SopTaskMutation) ResetPlanStartTime() {
+	m.plan_start_time = nil
+	delete(m.clearedFields, soptask.FieldPlanStartTime)
+}
+
+// SetPlanEndTime sets the "plan_end_time" field.
+func (m *SopTaskMutation) SetPlanEndTime(t time.Time) {
+	m.plan_end_time = &t
+}
+
+// PlanEndTime returns the value of the "plan_end_time" field in the mutation.
+func (m *SopTaskMutation) PlanEndTime() (r time.Time, exists bool) {
+	v := m.plan_end_time
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldPlanEndTime returns the old "plan_end_time" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldPlanEndTime(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldPlanEndTime is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldPlanEndTime requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldPlanEndTime: %w", err)
+	}
+	return oldValue.PlanEndTime, nil
+}
+
+// ClearPlanEndTime clears the value of the "plan_end_time" field.
+func (m *SopTaskMutation) ClearPlanEndTime() {
+	m.plan_end_time = nil
+	m.clearedFields[soptask.FieldPlanEndTime] = struct{}{}
+}
+
+// PlanEndTimeCleared returns if the "plan_end_time" field was cleared in this mutation.
+func (m *SopTaskMutation) PlanEndTimeCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldPlanEndTime]
+	return ok
+}
+
+// ResetPlanEndTime resets all changes to the "plan_end_time" field.
+func (m *SopTaskMutation) ResetPlanEndTime() {
+	m.plan_end_time = nil
+	delete(m.clearedFields, soptask.FieldPlanEndTime)
+}
+
+// SetCreatorID sets the "creator_id" field.
+func (m *SopTaskMutation) SetCreatorID(s string) {
+	m.creator_id = &s
+}
+
+// CreatorID returns the value of the "creator_id" field in the mutation.
+func (m *SopTaskMutation) CreatorID() (r string, exists bool) {
+	v := m.creator_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldCreatorID returns the old "creator_id" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldCreatorID(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldCreatorID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldCreatorID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldCreatorID: %w", err)
+	}
+	return oldValue.CreatorID, nil
+}
+
+// ClearCreatorID clears the value of the "creator_id" field.
+func (m *SopTaskMutation) ClearCreatorID() {
+	m.creator_id = nil
+	m.clearedFields[soptask.FieldCreatorID] = struct{}{}
+}
+
+// CreatorIDCleared returns if the "creator_id" field was cleared in this mutation.
+func (m *SopTaskMutation) CreatorIDCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldCreatorID]
+	return ok
+}
+
+// ResetCreatorID resets all changes to the "creator_id" field.
+func (m *SopTaskMutation) ResetCreatorID() {
+	m.creator_id = nil
+	delete(m.clearedFields, soptask.FieldCreatorID)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *SopTaskMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *SopTaskMutation) DeletedAt() (r time.Time, exists bool) {
+	v := m.deleted_at
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDeletedAt returns the old "deleted_at" field's value of the SopTask entity.
+// If the SopTask 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 *SopTaskMutation) OldDeletedAt(ctx context.Context) (v time.Time, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDeletedAt requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err)
+	}
+	return oldValue.DeletedAt, nil
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (m *SopTaskMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[soptask.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *SopTaskMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[soptask.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *SopTaskMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, soptask.FieldDeletedAt)
+}
+
+// AddTaskStageIDs adds the "task_stages" edge to the SopStage entity by ids.
+func (m *SopTaskMutation) AddTaskStageIDs(ids ...uint64) {
+	if m.task_stages == nil {
+		m.task_stages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.task_stages[ids[i]] = struct{}{}
+	}
+}
+
+// ClearTaskStages clears the "task_stages" edge to the SopStage entity.
+func (m *SopTaskMutation) ClearTaskStages() {
+	m.clearedtask_stages = true
+}
+
+// TaskStagesCleared reports if the "task_stages" edge to the SopStage entity was cleared.
+func (m *SopTaskMutation) TaskStagesCleared() bool {
+	return m.clearedtask_stages
+}
+
+// RemoveTaskStageIDs removes the "task_stages" edge to the SopStage entity by IDs.
+func (m *SopTaskMutation) RemoveTaskStageIDs(ids ...uint64) {
+	if m.removedtask_stages == nil {
+		m.removedtask_stages = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.task_stages, ids[i])
+		m.removedtask_stages[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedTaskStages returns the removed IDs of the "task_stages" edge to the SopStage entity.
+func (m *SopTaskMutation) RemovedTaskStagesIDs() (ids []uint64) {
+	for id := range m.removedtask_stages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// TaskStagesIDs returns the "task_stages" edge IDs in the mutation.
+func (m *SopTaskMutation) TaskStagesIDs() (ids []uint64) {
+	for id := range m.task_stages {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetTaskStages resets all changes to the "task_stages" edge.
+func (m *SopTaskMutation) ResetTaskStages() {
+	m.task_stages = nil
+	m.clearedtask_stages = false
+	m.removedtask_stages = nil
+}
+
+// Where appends a list predicates to the SopTaskMutation builder.
+func (m *SopTaskMutation) Where(ps ...predicate.SopTask) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the SopTaskMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *SopTaskMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.SopTask, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *SopTaskMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *SopTaskMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (SopTask).
+func (m *SopTaskMutation) 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 *SopTaskMutation) Fields() []string {
+	fields := make([]string, 0, 10)
+	if m.created_at != nil {
+		fields = append(fields, soptask.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, soptask.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, soptask.FieldStatus)
+	}
+	if m.name != nil {
+		fields = append(fields, soptask.FieldName)
+	}
+	if m.bot_wxid_list != nil {
+		fields = append(fields, soptask.FieldBotWxidList)
+	}
+	if m._type != nil {
+		fields = append(fields, soptask.FieldType)
+	}
+	if m.plan_start_time != nil {
+		fields = append(fields, soptask.FieldPlanStartTime)
+	}
+	if m.plan_end_time != nil {
+		fields = append(fields, soptask.FieldPlanEndTime)
+	}
+	if m.creator_id != nil {
+		fields = append(fields, soptask.FieldCreatorID)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, soptask.FieldDeletedAt)
+	}
+	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 *SopTaskMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case soptask.FieldCreatedAt:
+		return m.CreatedAt()
+	case soptask.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case soptask.FieldStatus:
+		return m.Status()
+	case soptask.FieldName:
+		return m.Name()
+	case soptask.FieldBotWxidList:
+		return m.BotWxidList()
+	case soptask.FieldType:
+		return m.GetType()
+	case soptask.FieldPlanStartTime:
+		return m.PlanStartTime()
+	case soptask.FieldPlanEndTime:
+		return m.PlanEndTime()
+	case soptask.FieldCreatorID:
+		return m.CreatorID()
+	case soptask.FieldDeletedAt:
+		return m.DeletedAt()
+	}
+	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 *SopTaskMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case soptask.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case soptask.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case soptask.FieldStatus:
+		return m.OldStatus(ctx)
+	case soptask.FieldName:
+		return m.OldName(ctx)
+	case soptask.FieldBotWxidList:
+		return m.OldBotWxidList(ctx)
+	case soptask.FieldType:
+		return m.OldType(ctx)
+	case soptask.FieldPlanStartTime:
+		return m.OldPlanStartTime(ctx)
+	case soptask.FieldPlanEndTime:
+		return m.OldPlanEndTime(ctx)
+	case soptask.FieldCreatorID:
+		return m.OldCreatorID(ctx)
+	case soptask.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	}
+	return nil, fmt.Errorf("unknown SopTask 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 *SopTaskMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case soptask.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 soptask.FieldUpdatedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetUpdatedAt(v)
+		return nil
+	case soptask.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case soptask.FieldName:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetName(v)
+		return nil
+	case soptask.FieldBotWxidList:
+		v, ok := value.([]string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetBotWxidList(v)
+		return nil
+	case soptask.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetType(v)
+		return nil
+	case soptask.FieldPlanStartTime:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetPlanStartTime(v)
+		return nil
+	case soptask.FieldPlanEndTime:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetPlanEndTime(v)
+		return nil
+	case soptask.FieldCreatorID:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetCreatorID(v)
+		return nil
+	case soptask.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopTask field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *SopTaskMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, soptask.FieldStatus)
+	}
+	if m.add_type != nil {
+		fields = append(fields, soptask.FieldType)
+	}
+	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 *SopTaskMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case soptask.FieldStatus:
+		return m.AddedStatus()
+	case soptask.FieldType:
+		return m.AddedType()
+	}
+	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 *SopTaskMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case soptask.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case soptask.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddType(v)
+		return nil
+	}
+	return fmt.Errorf("unknown SopTask numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *SopTaskMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(soptask.FieldStatus) {
+		fields = append(fields, soptask.FieldStatus)
+	}
+	if m.FieldCleared(soptask.FieldBotWxidList) {
+		fields = append(fields, soptask.FieldBotWxidList)
+	}
+	if m.FieldCleared(soptask.FieldPlanStartTime) {
+		fields = append(fields, soptask.FieldPlanStartTime)
+	}
+	if m.FieldCleared(soptask.FieldPlanEndTime) {
+		fields = append(fields, soptask.FieldPlanEndTime)
+	}
+	if m.FieldCleared(soptask.FieldCreatorID) {
+		fields = append(fields, soptask.FieldCreatorID)
+	}
+	if m.FieldCleared(soptask.FieldDeletedAt) {
+		fields = append(fields, soptask.FieldDeletedAt)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *SopTaskMutation) 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 *SopTaskMutation) ClearField(name string) error {
+	switch name {
+	case soptask.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case soptask.FieldBotWxidList:
+		m.ClearBotWxidList()
+		return nil
+	case soptask.FieldPlanStartTime:
+		m.ClearPlanStartTime()
+		return nil
+	case soptask.FieldPlanEndTime:
+		m.ClearPlanEndTime()
+		return nil
+	case soptask.FieldCreatorID:
+		m.ClearCreatorID()
+		return nil
+	case soptask.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopTask 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 *SopTaskMutation) ResetField(name string) error {
+	switch name {
+	case soptask.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case soptask.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case soptask.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case soptask.FieldName:
+		m.ResetName()
+		return nil
+	case soptask.FieldBotWxidList:
+		m.ResetBotWxidList()
+		return nil
+	case soptask.FieldType:
+		m.ResetType()
+		return nil
+	case soptask.FieldPlanStartTime:
+		m.ResetPlanStartTime()
+		return nil
+	case soptask.FieldPlanEndTime:
+		m.ResetPlanEndTime()
+		return nil
+	case soptask.FieldCreatorID:
+		m.ResetCreatorID()
+		return nil
+	case soptask.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown SopTask field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *SopTaskMutation) AddedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.task_stages != nil {
+		edges = append(edges, soptask.EdgeTaskStages)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *SopTaskMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case soptask.EdgeTaskStages:
+		ids := make([]ent.Value, 0, len(m.task_stages))
+		for id := range m.task_stages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *SopTaskMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.removedtask_stages != nil {
+		edges = append(edges, soptask.EdgeTaskStages)
+	}
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *SopTaskMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case soptask.EdgeTaskStages:
+		ids := make([]ent.Value, 0, len(m.removedtask_stages))
+		for id := range m.removedtask_stages {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *SopTaskMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.clearedtask_stages {
+		edges = append(edges, soptask.EdgeTaskStages)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *SopTaskMutation) EdgeCleared(name string) bool {
+	switch name {
+	case soptask.EdgeTaskStages:
+		return m.clearedtask_stages
+	}
+	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 *SopTaskMutation) ClearEdge(name string) error {
+	switch name {
+	}
+	return fmt.Errorf("unknown SopTask 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 *SopTaskMutation) ResetEdge(name string) error {
+	switch name {
+	case soptask.EdgeTaskStages:
+		m.ResetTaskStages()
+		return nil
+	}
+	return fmt.Errorf("unknown SopTask edge %s", name)
+}
+
 // TaskMutation represents an operation that mutates the Task nodes in the graph.
 type TaskMutation struct {
 	config

+ 240 - 0
ent/pagination.go

@@ -7,6 +7,9 @@ import (
 	"fmt"
 
 	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
 	"github.com/suyuan32/simple-admin-job/ent/task"
 	"github.com/suyuan32/simple-admin-job/ent/tasklog"
 )
@@ -136,6 +139,243 @@ func (mr *MessageRecordsQuery) Page(
 	return ret, nil
 }
 
+type SopNodePager struct {
+	Order  sopnode.OrderOption
+	Filter func(*SopNodeQuery) (*SopNodeQuery, error)
+}
+
+// SopNodePaginateOption enables pagination customization.
+type SopNodePaginateOption func(*SopNodePager)
+
+// DefaultSopNodeOrder is the default ordering of SopNode.
+var DefaultSopNodeOrder = Desc(sopnode.FieldID)
+
+func newSopNodePager(opts []SopNodePaginateOption) (*SopNodePager, error) {
+	pager := &SopNodePager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultSopNodeOrder
+	}
+	return pager, nil
+}
+
+func (p *SopNodePager) ApplyFilter(query *SopNodeQuery) (*SopNodeQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// SopNodePageList is SopNode PageList result.
+type SopNodePageList struct {
+	List        []*SopNode   `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (sn *SopNodeQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...SopNodePaginateOption,
+) (*SopNodePageList, error) {
+
+	pager, err := newSopNodePager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if sn, err = pager.ApplyFilter(sn); err != nil {
+		return nil, err
+	}
+
+	ret := &SopNodePageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := sn.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		sn = sn.Order(pager.Order)
+	} else {
+		sn = sn.Order(DefaultSopNodeOrder)
+	}
+
+	sn = sn.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := sn.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
+type SopStagePager struct {
+	Order  sopstage.OrderOption
+	Filter func(*SopStageQuery) (*SopStageQuery, error)
+}
+
+// SopStagePaginateOption enables pagination customization.
+type SopStagePaginateOption func(*SopStagePager)
+
+// DefaultSopStageOrder is the default ordering of SopStage.
+var DefaultSopStageOrder = Desc(sopstage.FieldID)
+
+func newSopStagePager(opts []SopStagePaginateOption) (*SopStagePager, error) {
+	pager := &SopStagePager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultSopStageOrder
+	}
+	return pager, nil
+}
+
+func (p *SopStagePager) ApplyFilter(query *SopStageQuery) (*SopStageQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// SopStagePageList is SopStage PageList result.
+type SopStagePageList struct {
+	List        []*SopStage  `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (ss *SopStageQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...SopStagePaginateOption,
+) (*SopStagePageList, error) {
+
+	pager, err := newSopStagePager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if ss, err = pager.ApplyFilter(ss); err != nil {
+		return nil, err
+	}
+
+	ret := &SopStagePageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := ss.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		ss = ss.Order(pager.Order)
+	} else {
+		ss = ss.Order(DefaultSopStageOrder)
+	}
+
+	ss = ss.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := ss.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
+type SopTaskPager struct {
+	Order  soptask.OrderOption
+	Filter func(*SopTaskQuery) (*SopTaskQuery, error)
+}
+
+// SopTaskPaginateOption enables pagination customization.
+type SopTaskPaginateOption func(*SopTaskPager)
+
+// DefaultSopTaskOrder is the default ordering of SopTask.
+var DefaultSopTaskOrder = Desc(soptask.FieldID)
+
+func newSopTaskPager(opts []SopTaskPaginateOption) (*SopTaskPager, error) {
+	pager := &SopTaskPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultSopTaskOrder
+	}
+	return pager, nil
+}
+
+func (p *SopTaskPager) ApplyFilter(query *SopTaskQuery) (*SopTaskQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// SopTaskPageList is SopTask PageList result.
+type SopTaskPageList struct {
+	List        []*SopTask   `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (st *SopTaskQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...SopTaskPaginateOption,
+) (*SopTaskPageList, error) {
+
+	pager, err := newSopTaskPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if st, err = pager.ApplyFilter(st); err != nil {
+		return nil, err
+	}
+
+	ret := &SopTaskPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := st.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		st = st.Order(pager.Order)
+	} else {
+		st = st.Order(DefaultSopTaskOrder)
+	}
+
+	st = st.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := st.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
 type TaskPager struct {
 	Order  task.OrderOption
 	Filter func(*TaskQuery) (*TaskQuery, error)

+ 9 - 0
ent/predicate/predicate.go

@@ -9,6 +9,15 @@ import (
 // MessageRecords is the predicate function for messagerecords builders.
 type MessageRecords func(*sql.Selector)
 
+// SopNode is the predicate function for sopnode builders.
+type SopNode func(*sql.Selector)
+
+// SopStage is the predicate function for sopstage builders.
+type SopStage func(*sql.Selector)
+
+// SopTask is the predicate function for soptask builders.
+type SopTask func(*sql.Selector)
+
 // Task is the predicate function for task builders.
 type Task func(*sql.Selector)
 

+ 102 - 0
ent/runtime.go

@@ -7,6 +7,9 @@ import (
 
 	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
 	"github.com/suyuan32/simple-admin-job/ent/schema"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
 	"github.com/suyuan32/simple-admin-job/ent/task"
 	"github.com/suyuan32/simple-admin-job/ent/tasklog"
 )
@@ -68,6 +71,105 @@ func init() {
 	messagerecordsDescSubSourceID := messagerecordsFields[11].Descriptor()
 	// messagerecords.DefaultSubSourceID holds the default value on creation for the sub_source_id field.
 	messagerecords.DefaultSubSourceID = messagerecordsDescSubSourceID.Default.(uint64)
+	sopnodeMixin := schema.SopNode{}.Mixin()
+	sopnodeMixinFields0 := sopnodeMixin[0].Fields()
+	_ = sopnodeMixinFields0
+	sopnodeMixinFields1 := sopnodeMixin[1].Fields()
+	_ = sopnodeMixinFields1
+	sopnodeFields := schema.SopNode{}.Fields()
+	_ = sopnodeFields
+	// sopnodeDescCreatedAt is the schema descriptor for created_at field.
+	sopnodeDescCreatedAt := sopnodeMixinFields0[1].Descriptor()
+	// sopnode.DefaultCreatedAt holds the default value on creation for the created_at field.
+	sopnode.DefaultCreatedAt = sopnodeDescCreatedAt.Default.(func() time.Time)
+	// sopnodeDescUpdatedAt is the schema descriptor for updated_at field.
+	sopnodeDescUpdatedAt := sopnodeMixinFields0[2].Descriptor()
+	// sopnode.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	sopnode.DefaultUpdatedAt = sopnodeDescUpdatedAt.Default.(func() time.Time)
+	// sopnode.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	sopnode.UpdateDefaultUpdatedAt = sopnodeDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// sopnodeDescStatus is the schema descriptor for status field.
+	sopnodeDescStatus := sopnodeMixinFields1[0].Descriptor()
+	// sopnode.DefaultStatus holds the default value on creation for the status field.
+	sopnode.DefaultStatus = sopnodeDescStatus.Default.(uint8)
+	// sopnodeDescName is the schema descriptor for name field.
+	sopnodeDescName := sopnodeFields[2].Descriptor()
+	// sopnode.DefaultName holds the default value on creation for the name field.
+	sopnode.DefaultName = sopnodeDescName.Default.(string)
+	// sopnodeDescConditionType is the schema descriptor for condition_type field.
+	sopnodeDescConditionType := sopnodeFields[3].Descriptor()
+	// sopnode.DefaultConditionType holds the default value on creation for the condition_type field.
+	sopnode.DefaultConditionType = sopnodeDescConditionType.Default.(int)
+	// sopnodeDescNoReplyCondition is the schema descriptor for no_reply_condition field.
+	sopnodeDescNoReplyCondition := sopnodeFields[5].Descriptor()
+	// sopnode.DefaultNoReplyCondition holds the default value on creation for the no_reply_condition field.
+	sopnode.DefaultNoReplyCondition = sopnodeDescNoReplyCondition.Default.(uint64)
+	sopstageMixin := schema.SopStage{}.Mixin()
+	sopstageMixinFields0 := sopstageMixin[0].Fields()
+	_ = sopstageMixinFields0
+	sopstageMixinFields1 := sopstageMixin[1].Fields()
+	_ = sopstageMixinFields1
+	sopstageFields := schema.SopStage{}.Fields()
+	_ = sopstageFields
+	// sopstageDescCreatedAt is the schema descriptor for created_at field.
+	sopstageDescCreatedAt := sopstageMixinFields0[1].Descriptor()
+	// sopstage.DefaultCreatedAt holds the default value on creation for the created_at field.
+	sopstage.DefaultCreatedAt = sopstageDescCreatedAt.Default.(func() time.Time)
+	// sopstageDescUpdatedAt is the schema descriptor for updated_at field.
+	sopstageDescUpdatedAt := sopstageMixinFields0[2].Descriptor()
+	// sopstage.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	sopstage.DefaultUpdatedAt = sopstageDescUpdatedAt.Default.(func() time.Time)
+	// sopstage.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	sopstage.UpdateDefaultUpdatedAt = sopstageDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// sopstageDescStatus is the schema descriptor for status field.
+	sopstageDescStatus := sopstageMixinFields1[0].Descriptor()
+	// sopstage.DefaultStatus holds the default value on creation for the status field.
+	sopstage.DefaultStatus = sopstageDescStatus.Default.(uint8)
+	// sopstageDescName is the schema descriptor for name field.
+	sopstageDescName := sopstageFields[1].Descriptor()
+	// sopstage.DefaultName holds the default value on creation for the name field.
+	sopstage.DefaultName = sopstageDescName.Default.(string)
+	// sopstageDescConditionType is the schema descriptor for condition_type field.
+	sopstageDescConditionType := sopstageFields[2].Descriptor()
+	// sopstage.DefaultConditionType holds the default value on creation for the condition_type field.
+	sopstage.DefaultConditionType = sopstageDescConditionType.Default.(int)
+	// sopstageDescConditionOperator is the schema descriptor for condition_operator field.
+	sopstageDescConditionOperator := sopstageFields[3].Descriptor()
+	// sopstage.DefaultConditionOperator holds the default value on creation for the condition_operator field.
+	sopstage.DefaultConditionOperator = sopstageDescConditionOperator.Default.(int)
+	// sopstageDescIndexSort is the schema descriptor for index_sort field.
+	sopstageDescIndexSort := sopstageFields[7].Descriptor()
+	// sopstage.DefaultIndexSort holds the default value on creation for the index_sort field.
+	sopstage.DefaultIndexSort = sopstageDescIndexSort.Default.(int)
+	soptaskMixin := schema.SopTask{}.Mixin()
+	soptaskMixinFields0 := soptaskMixin[0].Fields()
+	_ = soptaskMixinFields0
+	soptaskMixinFields1 := soptaskMixin[1].Fields()
+	_ = soptaskMixinFields1
+	soptaskFields := schema.SopTask{}.Fields()
+	_ = soptaskFields
+	// soptaskDescCreatedAt is the schema descriptor for created_at field.
+	soptaskDescCreatedAt := soptaskMixinFields0[1].Descriptor()
+	// soptask.DefaultCreatedAt holds the default value on creation for the created_at field.
+	soptask.DefaultCreatedAt = soptaskDescCreatedAt.Default.(func() time.Time)
+	// soptaskDescUpdatedAt is the schema descriptor for updated_at field.
+	soptaskDescUpdatedAt := soptaskMixinFields0[2].Descriptor()
+	// soptask.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	soptask.DefaultUpdatedAt = soptaskDescUpdatedAt.Default.(func() time.Time)
+	// soptask.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	soptask.UpdateDefaultUpdatedAt = soptaskDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// soptaskDescStatus is the schema descriptor for status field.
+	soptaskDescStatus := soptaskMixinFields1[0].Descriptor()
+	// soptask.DefaultStatus holds the default value on creation for the status field.
+	soptask.DefaultStatus = soptaskDescStatus.Default.(uint8)
+	// soptaskDescName is the schema descriptor for name field.
+	soptaskDescName := soptaskFields[0].Descriptor()
+	// soptask.NameValidator is a validator for the "name" field. It is called by the builders before save.
+	soptask.NameValidator = soptaskDescName.Validators[0].(func(string) error)
+	// soptaskDescType is the schema descriptor for type field.
+	soptaskDescType := soptaskFields[2].Descriptor()
+	// soptask.DefaultType holds the default value on creation for the type field.
+	soptask.DefaultType = soptaskDescType.Default.(int)
 	taskMixin := schema.Task{}.Mixin()
 	taskMixinFields0 := taskMixin[0].Fields()
 	_ = taskMixinFields0

+ 77 - 0
ent/schema/sop_node.go

@@ -0,0 +1,77 @@
+package schema
+
+import (
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+)
+
+type SopNode struct {
+	ent.Schema
+}
+
+func (SopNode) Fields() []ent.Field {
+	return []ent.Field{
+		field.Uint64("stage_id").
+			Annotations(entsql.WithComments(true)).
+			Comment("阶段 ID"),
+		field.Uint64("parent_id").
+			Annotations(entsql.WithComments(true)).
+			Comment("父节点 ID"),
+		field.String("name").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("节点名称"),
+		field.Int("condition_type").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("触发条件类型 1 客户回复后触发 2 超时后触发"),
+		field.JSON("condition_list", []string{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("触发语义列表 当为空时则代表用户回复任意内容后触发"),
+		field.Uint64("no_reply_condition").Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("超时触发时间(分钟)"),
+		field.JSON("action_message", []custom_types.Action{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("命中后发送的消息内容"),
+		field.JSON("action_label", []uint64{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("命中后需要打的标签"),
+		field.Time("deleted_at").
+			Optional().
+			Comment("Delete Time | 删除日期").
+			Annotations(entsql.WithComments(true)),
+	}
+}
+
+func (SopNode) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+	}
+}
+
+func (SopNode) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("name"),
+	}
+}
+
+func (SopNode) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.From("sop_stage", SopStage.Type).
+			Ref("stage_nodes").
+			Unique().
+			Field("stage_id").
+			Required(),
+		edge.To("node_messages", MessageRecords.Type),
+	}
+}
+
+func (SopNode) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "sop_node"}}
+}

+ 77 - 0
ent/schema/sop_stage.go

@@ -0,0 +1,77 @@
+package schema
+
+import (
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+)
+
+type SopStage struct {
+	ent.Schema
+}
+
+func (SopStage) Fields() []ent.Field {
+	return []ent.Field{
+		field.Uint64("task_id").
+			Annotations(entsql.WithComments(true)).
+			Comment("SOP 任务 ID"),
+		field.String("name").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("阶段名称"),
+		field.Int("condition_type").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("客群筛选条件类型  1 按标签筛选 2 按客户基本信息筛选"),
+		field.Int("condition_operator").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("筛选条件关系  1 满足所有条件(and) 2 满足任意条件(or)"),
+		field.JSON("condition_list", []custom_types.Condition{}).
+			Annotations(entsql.WithComments(true)).
+			Comment("筛选条件列表"),
+		field.JSON("action_message", []custom_types.Action{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("命中后发送的消息内容"),
+		field.JSON("action_label", []uint64{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("命中后需要打的标签"),
+		field.Int("index_sort").Default(1).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("阶段顺序"),
+		field.Time("deleted_at").
+			Optional().
+			Comment("Delete Time | 删除日期").
+			Annotations(entsql.WithComments(true)),
+	}
+}
+
+func (SopStage) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+	}
+}
+
+func (SopStage) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("name"),
+	}
+}
+
+func (SopStage) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.From("sop_task", SopTask.Type).
+			Ref("task_stages").
+			Unique().
+			Field("task_id").
+			Required(),
+		edge.To("stage_nodes", SopNode.Type),
+		edge.To("stage_messages", MessageRecords.Type),
+	}
+}
+func (SopStage) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "sop_stage"}}
+}

+ 65 - 0
ent/schema/sop_task.go

@@ -0,0 +1,65 @@
+package schema
+
+import (
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+)
+
+type SopTask struct {
+	ent.Schema
+}
+
+func (SopTask) Fields() []ent.Field {
+	return []ent.Field{
+		field.String("name").NotEmpty().
+			Annotations(entsql.WithComments(true)).
+			Comment("SOP 任务名称"),
+		field.JSON("bot_wxid_list", []string{}).Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("机器人微信 id 列表"),
+		field.Int("type").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("标签类型:1好友,2群组,3企业微信联系人"),
+		field.Time("plan_start_time").Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("任务计划开始时间"),
+		field.Time("plan_end_time").Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("任务计划结束时间"),
+		field.String("creator_id").Optional().
+			Annotations(entsql.WithComments(true)).
+			Comment("创建者 id"),
+		field.Time("deleted_at").
+			Optional().
+			Comment("Delete Time | 删除日期").
+			Annotations(entsql.WithComments(true)),
+	}
+}
+
+func (SopTask) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+	}
+}
+
+func (SopTask) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("name"),
+	}
+}
+
+func (SopTask) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.To("task_stages", SopStage.Type),
+	}
+}
+
+func (SopTask) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "sop_task"}}
+}

+ 744 - 0
ent/set_not_nil.go

@@ -345,6 +345,750 @@ func (mr *MessageRecordsCreate) SetNotNilSubSourceID(value *uint64) *MessageReco
 }
 
 // set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilUpdatedAt(value *time.Time) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetUpdatedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilUpdatedAt(value *time.Time) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetUpdatedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilUpdatedAt(value *time.Time) *SopNodeCreate {
+	if value != nil {
+		return sn.SetUpdatedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilStatus(value *uint8) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetStatus(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilStatus(value *uint8) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetStatus(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilStatus(value *uint8) *SopNodeCreate {
+	if value != nil {
+		return sn.SetStatus(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilStageID(value *uint64) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetStageID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilStageID(value *uint64) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetStageID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilStageID(value *uint64) *SopNodeCreate {
+	if value != nil {
+		return sn.SetStageID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilParentID(value *uint64) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetParentID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilParentID(value *uint64) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetParentID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilParentID(value *uint64) *SopNodeCreate {
+	if value != nil {
+		return sn.SetParentID(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilName(value *string) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetName(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilName(value *string) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetName(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilName(value *string) *SopNodeCreate {
+	if value != nil {
+		return sn.SetName(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilConditionType(value *int) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetConditionType(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilConditionType(value *int) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetConditionType(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilConditionType(value *int) *SopNodeCreate {
+	if value != nil {
+		return sn.SetConditionType(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilConditionList(value *[]string) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetConditionList(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilConditionList(value *[]string) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetConditionList(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilConditionList(value *[]string) *SopNodeCreate {
+	if value != nil {
+		return sn.SetConditionList(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilNoReplyCondition(value *uint64) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilNoReplyCondition(value *uint64) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilNoReplyCondition(value *uint64) *SopNodeCreate {
+	if value != nil {
+		return sn.SetNoReplyCondition(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilActionMessage(value *[]custom_types.Action) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetActionMessage(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilActionMessage(value *[]custom_types.Action) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetActionMessage(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilActionMessage(value *[]custom_types.Action) *SopNodeCreate {
+	if value != nil {
+		return sn.SetActionMessage(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilActionLabel(value *[]uint64) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetActionLabel(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilActionLabel(value *[]uint64) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetActionLabel(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilActionLabel(value *[]uint64) *SopNodeCreate {
+	if value != nil {
+		return sn.SetActionLabel(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdate) SetNotNilDeletedAt(value *time.Time) *SopNodeUpdate {
+	if value != nil {
+		return sn.SetDeletedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeUpdateOne) SetNotNilDeletedAt(value *time.Time) *SopNodeUpdateOne {
+	if value != nil {
+		return sn.SetDeletedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (sn *SopNodeCreate) SetNotNilDeletedAt(value *time.Time) *SopNodeCreate {
+	if value != nil {
+		return sn.SetDeletedAt(*value)
+	}
+	return sn
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilUpdatedAt(value *time.Time) *SopStageUpdate {
+	if value != nil {
+		return ss.SetUpdatedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilUpdatedAt(value *time.Time) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetUpdatedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilUpdatedAt(value *time.Time) *SopStageCreate {
+	if value != nil {
+		return ss.SetUpdatedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilStatus(value *uint8) *SopStageUpdate {
+	if value != nil {
+		return ss.SetStatus(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilStatus(value *uint8) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetStatus(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilStatus(value *uint8) *SopStageCreate {
+	if value != nil {
+		return ss.SetStatus(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilTaskID(value *uint64) *SopStageUpdate {
+	if value != nil {
+		return ss.SetTaskID(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilTaskID(value *uint64) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetTaskID(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilTaskID(value *uint64) *SopStageCreate {
+	if value != nil {
+		return ss.SetTaskID(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilName(value *string) *SopStageUpdate {
+	if value != nil {
+		return ss.SetName(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilName(value *string) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetName(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilName(value *string) *SopStageCreate {
+	if value != nil {
+		return ss.SetName(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilConditionType(value *int) *SopStageUpdate {
+	if value != nil {
+		return ss.SetConditionType(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilConditionType(value *int) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetConditionType(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilConditionType(value *int) *SopStageCreate {
+	if value != nil {
+		return ss.SetConditionType(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilConditionOperator(value *int) *SopStageUpdate {
+	if value != nil {
+		return ss.SetConditionOperator(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilConditionOperator(value *int) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetConditionOperator(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilConditionOperator(value *int) *SopStageCreate {
+	if value != nil {
+		return ss.SetConditionOperator(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilConditionList(value *[]custom_types.Condition) *SopStageUpdate {
+	if value != nil {
+		return ss.SetConditionList(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilConditionList(value *[]custom_types.Condition) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetConditionList(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilConditionList(value *[]custom_types.Condition) *SopStageCreate {
+	if value != nil {
+		return ss.SetConditionList(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilActionMessage(value *[]custom_types.Action) *SopStageUpdate {
+	if value != nil {
+		return ss.SetActionMessage(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilActionMessage(value *[]custom_types.Action) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetActionMessage(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilActionMessage(value *[]custom_types.Action) *SopStageCreate {
+	if value != nil {
+		return ss.SetActionMessage(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilActionLabel(value *[]uint64) *SopStageUpdate {
+	if value != nil {
+		return ss.SetActionLabel(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilActionLabel(value *[]uint64) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetActionLabel(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilActionLabel(value *[]uint64) *SopStageCreate {
+	if value != nil {
+		return ss.SetActionLabel(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilIndexSort(value *int) *SopStageUpdate {
+	if value != nil {
+		return ss.SetIndexSort(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilIndexSort(value *int) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetIndexSort(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilIndexSort(value *int) *SopStageCreate {
+	if value != nil {
+		return ss.SetIndexSort(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdate) SetNotNilDeletedAt(value *time.Time) *SopStageUpdate {
+	if value != nil {
+		return ss.SetDeletedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageUpdateOne) SetNotNilDeletedAt(value *time.Time) *SopStageUpdateOne {
+	if value != nil {
+		return ss.SetDeletedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (ss *SopStageCreate) SetNotNilDeletedAt(value *time.Time) *SopStageCreate {
+	if value != nil {
+		return ss.SetDeletedAt(*value)
+	}
+	return ss
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilUpdatedAt(value *time.Time) *SopTaskUpdate {
+	if value != nil {
+		return st.SetUpdatedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilUpdatedAt(value *time.Time) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetUpdatedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilUpdatedAt(value *time.Time) *SopTaskCreate {
+	if value != nil {
+		return st.SetUpdatedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilStatus(value *uint8) *SopTaskUpdate {
+	if value != nil {
+		return st.SetStatus(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilStatus(value *uint8) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetStatus(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilStatus(value *uint8) *SopTaskCreate {
+	if value != nil {
+		return st.SetStatus(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilName(value *string) *SopTaskUpdate {
+	if value != nil {
+		return st.SetName(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilName(value *string) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetName(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilName(value *string) *SopTaskCreate {
+	if value != nil {
+		return st.SetName(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilBotWxidList(value *[]string) *SopTaskUpdate {
+	if value != nil {
+		return st.SetBotWxidList(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilBotWxidList(value *[]string) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetBotWxidList(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilBotWxidList(value *[]string) *SopTaskCreate {
+	if value != nil {
+		return st.SetBotWxidList(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilType(value *int) *SopTaskUpdate {
+	if value != nil {
+		return st.SetType(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilType(value *int) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetType(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilType(value *int) *SopTaskCreate {
+	if value != nil {
+		return st.SetType(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilPlanStartTime(value *time.Time) *SopTaskUpdate {
+	if value != nil {
+		return st.SetPlanStartTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilPlanStartTime(value *time.Time) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetPlanStartTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilPlanStartTime(value *time.Time) *SopTaskCreate {
+	if value != nil {
+		return st.SetPlanStartTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilPlanEndTime(value *time.Time) *SopTaskUpdate {
+	if value != nil {
+		return st.SetPlanEndTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilPlanEndTime(value *time.Time) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetPlanEndTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilPlanEndTime(value *time.Time) *SopTaskCreate {
+	if value != nil {
+		return st.SetPlanEndTime(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilCreatorID(value *string) *SopTaskUpdate {
+	if value != nil {
+		return st.SetCreatorID(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilCreatorID(value *string) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetCreatorID(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilCreatorID(value *string) *SopTaskCreate {
+	if value != nil {
+		return st.SetCreatorID(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdate) SetNotNilDeletedAt(value *time.Time) *SopTaskUpdate {
+	if value != nil {
+		return st.SetDeletedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskUpdateOne) SetNotNilDeletedAt(value *time.Time) *SopTaskUpdateOne {
+	if value != nil {
+		return st.SetDeletedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
+func (st *SopTaskCreate) SetNotNilDeletedAt(value *time.Time) *SopTaskCreate {
+	if value != nil {
+		return st.SetDeletedAt(*value)
+	}
+	return st
+}
+
+// set field if value's pointer is not nil.
 func (t *TaskUpdate) SetNotNilUpdatedAt(value *time.Time) *TaskUpdate {
 	if value != nil {
 		return t.SetUpdatedAt(*value)

+ 282 - 0
ent/sopnode.go

@@ -0,0 +1,282 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+)
+
+// SopNode is the model entity for the SopNode schema.
+type SopNode struct {
+	config `json:"-"`
+	// ID of the ent.
+	ID uint64 `json:"id,omitempty"`
+	// Create Time | 创建日期
+	CreatedAt time.Time `json:"created_at,omitempty"`
+	// Update Time | 修改日期
+	UpdatedAt time.Time `json:"updated_at,omitempty"`
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status uint8 `json:"status,omitempty"`
+	// 阶段 ID
+	StageID uint64 `json:"stage_id,omitempty"`
+	// 父节点 ID
+	ParentID uint64 `json:"parent_id,omitempty"`
+	// 节点名称
+	Name string `json:"name,omitempty"`
+	// 触发条件类型 1 客户回复后触发 2 超时后触发
+	ConditionType int `json:"condition_type,omitempty"`
+	// 触发语义列表 当为空时则代表用户回复任意内容后触发
+	ConditionList []string `json:"condition_list,omitempty"`
+	// 超时触发时间(分钟)
+	NoReplyCondition uint64 `json:"no_reply_condition,omitempty"`
+	// 命中后发送的消息内容
+	ActionMessage []custom_types.Action `json:"action_message,omitempty"`
+	// 命中后需要打的标签
+	ActionLabel []uint64 `json:"action_label,omitempty"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the SopNodeQuery when eager-loading is set.
+	Edges        SopNodeEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// SopNodeEdges holds the relations/edges for other nodes in the graph.
+type SopNodeEdges struct {
+	// SopStage holds the value of the sop_stage edge.
+	SopStage *SopStage `json:"sop_stage,omitempty"`
+	// NodeMessages holds the value of the node_messages edge.
+	NodeMessages []*MessageRecords `json:"node_messages,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [2]bool
+}
+
+// SopStageOrErr returns the SopStage value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e SopNodeEdges) SopStageOrErr() (*SopStage, error) {
+	if e.SopStage != nil {
+		return e.SopStage, nil
+	} else if e.loadedTypes[0] {
+		return nil, &NotFoundError{label: sopstage.Label}
+	}
+	return nil, &NotLoadedError{edge: "sop_stage"}
+}
+
+// NodeMessagesOrErr returns the NodeMessages value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopNodeEdges) NodeMessagesOrErr() ([]*MessageRecords, error) {
+	if e.loadedTypes[1] {
+		return e.NodeMessages, nil
+	}
+	return nil, &NotLoadedError{edge: "node_messages"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*SopNode) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case sopnode.FieldConditionList, sopnode.FieldActionMessage, sopnode.FieldActionLabel:
+			values[i] = new([]byte)
+		case sopnode.FieldID, sopnode.FieldStatus, sopnode.FieldStageID, sopnode.FieldParentID, sopnode.FieldConditionType, sopnode.FieldNoReplyCondition:
+			values[i] = new(sql.NullInt64)
+		case sopnode.FieldName:
+			values[i] = new(sql.NullString)
+		case sopnode.FieldCreatedAt, sopnode.FieldUpdatedAt, sopnode.FieldDeletedAt:
+			values[i] = new(sql.NullTime)
+		default:
+			values[i] = new(sql.UnknownType)
+		}
+	}
+	return values, nil
+}
+
+// assignValues assigns the values that were returned from sql.Rows (after scanning)
+// to the SopNode fields.
+func (sn *SopNode) 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 sopnode.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			sn.ID = uint64(value.Int64)
+		case sopnode.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 {
+				sn.CreatedAt = value.Time
+			}
+		case sopnode.FieldUpdatedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field updated_at", values[i])
+			} else if value.Valid {
+				sn.UpdatedAt = value.Time
+			}
+		case sopnode.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				sn.Status = uint8(value.Int64)
+			}
+		case sopnode.FieldStageID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field stage_id", values[i])
+			} else if value.Valid {
+				sn.StageID = uint64(value.Int64)
+			}
+		case sopnode.FieldParentID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field parent_id", values[i])
+			} else if value.Valid {
+				sn.ParentID = uint64(value.Int64)
+			}
+		case sopnode.FieldName:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field name", values[i])
+			} else if value.Valid {
+				sn.Name = value.String
+			}
+		case sopnode.FieldConditionType:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field condition_type", values[i])
+			} else if value.Valid {
+				sn.ConditionType = int(value.Int64)
+			}
+		case sopnode.FieldConditionList:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field condition_list", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &sn.ConditionList); err != nil {
+					return fmt.Errorf("unmarshal field condition_list: %w", err)
+				}
+			}
+		case sopnode.FieldNoReplyCondition:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field no_reply_condition", values[i])
+			} else if value.Valid {
+				sn.NoReplyCondition = uint64(value.Int64)
+			}
+		case sopnode.FieldActionMessage:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field action_message", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &sn.ActionMessage); err != nil {
+					return fmt.Errorf("unmarshal field action_message: %w", err)
+				}
+			}
+		case sopnode.FieldActionLabel:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field action_label", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &sn.ActionLabel); err != nil {
+					return fmt.Errorf("unmarshal field action_label: %w", err)
+				}
+			}
+		case sopnode.FieldDeletedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field deleted_at", values[i])
+			} else if value.Valid {
+				sn.DeletedAt = value.Time
+			}
+		default:
+			sn.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the SopNode.
+// This includes values selected through modifiers, order, etc.
+func (sn *SopNode) Value(name string) (ent.Value, error) {
+	return sn.selectValues.Get(name)
+}
+
+// QuerySopStage queries the "sop_stage" edge of the SopNode entity.
+func (sn *SopNode) QuerySopStage() *SopStageQuery {
+	return NewSopNodeClient(sn.config).QuerySopStage(sn)
+}
+
+// QueryNodeMessages queries the "node_messages" edge of the SopNode entity.
+func (sn *SopNode) QueryNodeMessages() *MessageRecordsQuery {
+	return NewSopNodeClient(sn.config).QueryNodeMessages(sn)
+}
+
+// Update returns a builder for updating this SopNode.
+// Note that you need to call SopNode.Unwrap() before calling this method if this SopNode
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (sn *SopNode) Update() *SopNodeUpdateOne {
+	return NewSopNodeClient(sn.config).UpdateOne(sn)
+}
+
+// Unwrap unwraps the SopNode 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 (sn *SopNode) Unwrap() *SopNode {
+	_tx, ok := sn.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: SopNode is not a transactional entity")
+	}
+	sn.config.driver = _tx.drv
+	return sn
+}
+
+// String implements the fmt.Stringer.
+func (sn *SopNode) String() string {
+	var builder strings.Builder
+	builder.WriteString("SopNode(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", sn.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(sn.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(sn.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", sn.Status))
+	builder.WriteString(", ")
+	builder.WriteString("stage_id=")
+	builder.WriteString(fmt.Sprintf("%v", sn.StageID))
+	builder.WriteString(", ")
+	builder.WriteString("parent_id=")
+	builder.WriteString(fmt.Sprintf("%v", sn.ParentID))
+	builder.WriteString(", ")
+	builder.WriteString("name=")
+	builder.WriteString(sn.Name)
+	builder.WriteString(", ")
+	builder.WriteString("condition_type=")
+	builder.WriteString(fmt.Sprintf("%v", sn.ConditionType))
+	builder.WriteString(", ")
+	builder.WriteString("condition_list=")
+	builder.WriteString(fmt.Sprintf("%v", sn.ConditionList))
+	builder.WriteString(", ")
+	builder.WriteString("no_reply_condition=")
+	builder.WriteString(fmt.Sprintf("%v", sn.NoReplyCondition))
+	builder.WriteString(", ")
+	builder.WriteString("action_message=")
+	builder.WriteString(fmt.Sprintf("%v", sn.ActionMessage))
+	builder.WriteString(", ")
+	builder.WriteString("action_label=")
+	builder.WriteString(fmt.Sprintf("%v", sn.ActionLabel))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(sn.DeletedAt.Format(time.ANSIC))
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// SopNodes is a parsable slice of SopNode.
+type SopNodes []*SopNode

+ 193 - 0
ent/sopnode/sopnode.go

@@ -0,0 +1,193 @@
+// Code generated by ent, DO NOT EDIT.
+
+package sopnode
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the sopnode type in the database.
+	Label = "sop_node"
+	// FieldID holds the string denoting the id field in the database.
+	FieldID = "id"
+	// FieldCreatedAt holds the string denoting the created_at field in the database.
+	FieldCreatedAt = "created_at"
+	// FieldUpdatedAt holds the string denoting the updated_at field in the database.
+	FieldUpdatedAt = "updated_at"
+	// FieldStatus holds the string denoting the status field in the database.
+	FieldStatus = "status"
+	// FieldStageID holds the string denoting the stage_id field in the database.
+	FieldStageID = "stage_id"
+	// FieldParentID holds the string denoting the parent_id field in the database.
+	FieldParentID = "parent_id"
+	// FieldName holds the string denoting the name field in the database.
+	FieldName = "name"
+	// FieldConditionType holds the string denoting the condition_type field in the database.
+	FieldConditionType = "condition_type"
+	// FieldConditionList holds the string denoting the condition_list field in the database.
+	FieldConditionList = "condition_list"
+	// FieldNoReplyCondition holds the string denoting the no_reply_condition field in the database.
+	FieldNoReplyCondition = "no_reply_condition"
+	// FieldActionMessage holds the string denoting the action_message field in the database.
+	FieldActionMessage = "action_message"
+	// FieldActionLabel holds the string denoting the action_label field in the database.
+	FieldActionLabel = "action_label"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// EdgeSopStage holds the string denoting the sop_stage edge name in mutations.
+	EdgeSopStage = "sop_stage"
+	// EdgeNodeMessages holds the string denoting the node_messages edge name in mutations.
+	EdgeNodeMessages = "node_messages"
+	// Table holds the table name of the sopnode in the database.
+	Table = "sop_node"
+	// SopStageTable is the table that holds the sop_stage relation/edge.
+	SopStageTable = "sop_node"
+	// SopStageInverseTable is the table name for the SopStage entity.
+	// It exists in this package in order to avoid circular dependency with the "sopstage" package.
+	SopStageInverseTable = "sop_stage"
+	// SopStageColumn is the table column denoting the sop_stage relation/edge.
+	SopStageColumn = "stage_id"
+	// NodeMessagesTable is the table that holds the node_messages relation/edge.
+	NodeMessagesTable = "message_records"
+	// NodeMessagesInverseTable is the table name for the MessageRecords entity.
+	// It exists in this package in order to avoid circular dependency with the "messagerecords" package.
+	NodeMessagesInverseTable = "message_records"
+	// NodeMessagesColumn is the table column denoting the node_messages relation/edge.
+	NodeMessagesColumn = "sop_node_node_messages"
+)
+
+// Columns holds all SQL columns for sopnode fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldStageID,
+	FieldParentID,
+	FieldName,
+	FieldConditionType,
+	FieldConditionList,
+	FieldNoReplyCondition,
+	FieldActionMessage,
+	FieldActionLabel,
+	FieldDeletedAt,
+}
+
+// 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 (
+	// DefaultCreatedAt holds the default value on creation for the "created_at" field.
+	DefaultCreatedAt func() time.Time
+	// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
+	DefaultUpdatedAt func() time.Time
+	// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
+	UpdateDefaultUpdatedAt func() time.Time
+	// DefaultStatus holds the default value on creation for the "status" field.
+	DefaultStatus uint8
+	// DefaultName holds the default value on creation for the "name" field.
+	DefaultName string
+	// DefaultConditionType holds the default value on creation for the "condition_type" field.
+	DefaultConditionType int
+	// DefaultNoReplyCondition holds the default value on creation for the "no_reply_condition" field.
+	DefaultNoReplyCondition uint64
+)
+
+// OrderOption defines the ordering options for the SopNode queries.
+type OrderOption func(*sql.Selector)
+
+// ByID orders the results by the id field.
+func ByID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldID, opts...).ToFunc()
+}
+
+// ByCreatedAt orders the results by the created_at field.
+func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
+}
+
+// ByUpdatedAt orders the results by the updated_at field.
+func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
+}
+
+// ByStatus orders the results by the status field.
+func ByStatus(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStatus, opts...).ToFunc()
+}
+
+// ByStageID orders the results by the stage_id field.
+func ByStageID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStageID, opts...).ToFunc()
+}
+
+// ByParentID orders the results by the parent_id field.
+func ByParentID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldParentID, opts...).ToFunc()
+}
+
+// ByName orders the results by the name field.
+func ByName(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldName, opts...).ToFunc()
+}
+
+// ByConditionType orders the results by the condition_type field.
+func ByConditionType(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldConditionType, opts...).ToFunc()
+}
+
+// ByNoReplyCondition orders the results by the no_reply_condition field.
+func ByNoReplyCondition(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldNoReplyCondition, opts...).ToFunc()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// BySopStageField orders the results by sop_stage field.
+func BySopStageField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newSopStageStep(), sql.OrderByField(field, opts...))
+	}
+}
+
+// ByNodeMessagesCount orders the results by node_messages count.
+func ByNodeMessagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newNodeMessagesStep(), opts...)
+	}
+}
+
+// ByNodeMessages orders the results by node_messages terms.
+func ByNodeMessages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newNodeMessagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newSopStageStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(SopStageInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, SopStageTable, SopStageColumn),
+	)
+}
+func newNodeMessagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(NodeMessagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, NodeMessagesTable, NodeMessagesColumn),
+	)
+}

+ 577 - 0
ent/sopnode/where.go

@@ -0,0 +1,577 @@
+// Code generated by ent, DO NOT EDIT.
+
+package sopnode
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldID, id))
+}
+
+// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
+func CreatedAt(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
+func UpdatedAt(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldStatus, v))
+}
+
+// StageID applies equality check predicate on the "stage_id" field. It's identical to StageIDEQ.
+func StageID(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldStageID, v))
+}
+
+// ParentID applies equality check predicate on the "parent_id" field. It's identical to ParentIDEQ.
+func ParentID(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldParentID, v))
+}
+
+// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
+func Name(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldName, v))
+}
+
+// ConditionType applies equality check predicate on the "condition_type" field. It's identical to ConditionTypeEQ.
+func ConditionType(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldConditionType, v))
+}
+
+// NoReplyCondition applies equality check predicate on the "no_reply_condition" field. It's identical to NoReplyConditionEQ.
+func NoReplyCondition(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldNoReplyCondition, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotNull(FieldStatus))
+}
+
+// StageIDEQ applies the EQ predicate on the "stage_id" field.
+func StageIDEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldStageID, v))
+}
+
+// StageIDNEQ applies the NEQ predicate on the "stage_id" field.
+func StageIDNEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldStageID, v))
+}
+
+// StageIDIn applies the In predicate on the "stage_id" field.
+func StageIDIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldStageID, vs...))
+}
+
+// StageIDNotIn applies the NotIn predicate on the "stage_id" field.
+func StageIDNotIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldStageID, vs...))
+}
+
+// ParentIDEQ applies the EQ predicate on the "parent_id" field.
+func ParentIDEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldParentID, v))
+}
+
+// ParentIDNEQ applies the NEQ predicate on the "parent_id" field.
+func ParentIDNEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldParentID, v))
+}
+
+// ParentIDIn applies the In predicate on the "parent_id" field.
+func ParentIDIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldParentID, vs...))
+}
+
+// ParentIDNotIn applies the NotIn predicate on the "parent_id" field.
+func ParentIDNotIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldParentID, vs...))
+}
+
+// ParentIDGT applies the GT predicate on the "parent_id" field.
+func ParentIDGT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldParentID, v))
+}
+
+// ParentIDGTE applies the GTE predicate on the "parent_id" field.
+func ParentIDGTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldParentID, v))
+}
+
+// ParentIDLT applies the LT predicate on the "parent_id" field.
+func ParentIDLT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldParentID, v))
+}
+
+// ParentIDLTE applies the LTE predicate on the "parent_id" field.
+func ParentIDLTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldParentID, v))
+}
+
+// NameEQ applies the EQ predicate on the "name" field.
+func NameEQ(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldName, v))
+}
+
+// NameNEQ applies the NEQ predicate on the "name" field.
+func NameNEQ(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldName, v))
+}
+
+// NameIn applies the In predicate on the "name" field.
+func NameIn(vs ...string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldName, vs...))
+}
+
+// NameNotIn applies the NotIn predicate on the "name" field.
+func NameNotIn(vs ...string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldName, vs...))
+}
+
+// NameGT applies the GT predicate on the "name" field.
+func NameGT(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldName, v))
+}
+
+// NameGTE applies the GTE predicate on the "name" field.
+func NameGTE(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldName, v))
+}
+
+// NameLT applies the LT predicate on the "name" field.
+func NameLT(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldName, v))
+}
+
+// NameLTE applies the LTE predicate on the "name" field.
+func NameLTE(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldName, v))
+}
+
+// NameContains applies the Contains predicate on the "name" field.
+func NameContains(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldContains(FieldName, v))
+}
+
+// NameHasPrefix applies the HasPrefix predicate on the "name" field.
+func NameHasPrefix(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldHasPrefix(FieldName, v))
+}
+
+// NameHasSuffix applies the HasSuffix predicate on the "name" field.
+func NameHasSuffix(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldHasSuffix(FieldName, v))
+}
+
+// NameEqualFold applies the EqualFold predicate on the "name" field.
+func NameEqualFold(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEqualFold(FieldName, v))
+}
+
+// NameContainsFold applies the ContainsFold predicate on the "name" field.
+func NameContainsFold(v string) predicate.SopNode {
+	return predicate.SopNode(sql.FieldContainsFold(FieldName, v))
+}
+
+// ConditionTypeEQ applies the EQ predicate on the "condition_type" field.
+func ConditionTypeEQ(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldConditionType, v))
+}
+
+// ConditionTypeNEQ applies the NEQ predicate on the "condition_type" field.
+func ConditionTypeNEQ(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldConditionType, v))
+}
+
+// ConditionTypeIn applies the In predicate on the "condition_type" field.
+func ConditionTypeIn(vs ...int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldConditionType, vs...))
+}
+
+// ConditionTypeNotIn applies the NotIn predicate on the "condition_type" field.
+func ConditionTypeNotIn(vs ...int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldConditionType, vs...))
+}
+
+// ConditionTypeGT applies the GT predicate on the "condition_type" field.
+func ConditionTypeGT(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldConditionType, v))
+}
+
+// ConditionTypeGTE applies the GTE predicate on the "condition_type" field.
+func ConditionTypeGTE(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldConditionType, v))
+}
+
+// ConditionTypeLT applies the LT predicate on the "condition_type" field.
+func ConditionTypeLT(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldConditionType, v))
+}
+
+// ConditionTypeLTE applies the LTE predicate on the "condition_type" field.
+func ConditionTypeLTE(v int) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldConditionType, v))
+}
+
+// ConditionListIsNil applies the IsNil predicate on the "condition_list" field.
+func ConditionListIsNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldIsNull(FieldConditionList))
+}
+
+// ConditionListNotNil applies the NotNil predicate on the "condition_list" field.
+func ConditionListNotNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotNull(FieldConditionList))
+}
+
+// NoReplyConditionEQ applies the EQ predicate on the "no_reply_condition" field.
+func NoReplyConditionEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionNEQ applies the NEQ predicate on the "no_reply_condition" field.
+func NoReplyConditionNEQ(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionIn applies the In predicate on the "no_reply_condition" field.
+func NoReplyConditionIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldNoReplyCondition, vs...))
+}
+
+// NoReplyConditionNotIn applies the NotIn predicate on the "no_reply_condition" field.
+func NoReplyConditionNotIn(vs ...uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldNoReplyCondition, vs...))
+}
+
+// NoReplyConditionGT applies the GT predicate on the "no_reply_condition" field.
+func NoReplyConditionGT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionGTE applies the GTE predicate on the "no_reply_condition" field.
+func NoReplyConditionGTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionLT applies the LT predicate on the "no_reply_condition" field.
+func NoReplyConditionLT(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldNoReplyCondition, v))
+}
+
+// NoReplyConditionLTE applies the LTE predicate on the "no_reply_condition" field.
+func NoReplyConditionLTE(v uint64) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldNoReplyCondition, v))
+}
+
+// ActionMessageIsNil applies the IsNil predicate on the "action_message" field.
+func ActionMessageIsNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldIsNull(FieldActionMessage))
+}
+
+// ActionMessageNotNil applies the NotNil predicate on the "action_message" field.
+func ActionMessageNotNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotNull(FieldActionMessage))
+}
+
+// ActionLabelIsNil applies the IsNil predicate on the "action_label" field.
+func ActionLabelIsNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldIsNull(FieldActionLabel))
+}
+
+// ActionLabelNotNil applies the NotNil predicate on the "action_label" field.
+func ActionLabelNotNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotNull(FieldActionLabel))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.SopNode {
+	return predicate.SopNode(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.SopNode {
+	return predicate.SopNode(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// HasSopStage applies the HasEdge predicate on the "sop_stage" edge.
+func HasSopStage() predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, SopStageTable, SopStageColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasSopStageWith applies the HasEdge predicate on the "sop_stage" edge with a given conditions (other predicates).
+func HasSopStageWith(preds ...predicate.SopStage) predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := newSopStageStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasNodeMessages applies the HasEdge predicate on the "node_messages" edge.
+func HasNodeMessages() predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, NodeMessagesTable, NodeMessagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasNodeMessagesWith applies the HasEdge predicate on the "node_messages" edge with a given conditions (other predicates).
+func HasNodeMessagesWith(preds ...predicate.MessageRecords) predicate.SopNode {
+	return predicate.SopNode(func(s *sql.Selector) {
+		step := newNodeMessagesStep()
+		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.SopNode) predicate.SopNode {
+	return predicate.SopNode(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.SopNode) predicate.SopNode {
+	return predicate.SopNode(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.SopNode) predicate.SopNode {
+	return predicate.SopNode(sql.NotPredicates(p))
+}

+ 471 - 0
ent/sopnode_create.go

@@ -0,0 +1,471 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+)
+
+// SopNodeCreate is the builder for creating a SopNode entity.
+type SopNodeCreate struct {
+	config
+	mutation *SopNodeMutation
+	hooks    []Hook
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (snc *SopNodeCreate) SetCreatedAt(t time.Time) *SopNodeCreate {
+	snc.mutation.SetCreatedAt(t)
+	return snc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableCreatedAt(t *time.Time) *SopNodeCreate {
+	if t != nil {
+		snc.SetCreatedAt(*t)
+	}
+	return snc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (snc *SopNodeCreate) SetUpdatedAt(t time.Time) *SopNodeCreate {
+	snc.mutation.SetUpdatedAt(t)
+	return snc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableUpdatedAt(t *time.Time) *SopNodeCreate {
+	if t != nil {
+		snc.SetUpdatedAt(*t)
+	}
+	return snc
+}
+
+// SetStatus sets the "status" field.
+func (snc *SopNodeCreate) SetStatus(u uint8) *SopNodeCreate {
+	snc.mutation.SetStatus(u)
+	return snc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableStatus(u *uint8) *SopNodeCreate {
+	if u != nil {
+		snc.SetStatus(*u)
+	}
+	return snc
+}
+
+// SetStageID sets the "stage_id" field.
+func (snc *SopNodeCreate) SetStageID(u uint64) *SopNodeCreate {
+	snc.mutation.SetStageID(u)
+	return snc
+}
+
+// SetParentID sets the "parent_id" field.
+func (snc *SopNodeCreate) SetParentID(u uint64) *SopNodeCreate {
+	snc.mutation.SetParentID(u)
+	return snc
+}
+
+// SetName sets the "name" field.
+func (snc *SopNodeCreate) SetName(s string) *SopNodeCreate {
+	snc.mutation.SetName(s)
+	return snc
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableName(s *string) *SopNodeCreate {
+	if s != nil {
+		snc.SetName(*s)
+	}
+	return snc
+}
+
+// SetConditionType sets the "condition_type" field.
+func (snc *SopNodeCreate) SetConditionType(i int) *SopNodeCreate {
+	snc.mutation.SetConditionType(i)
+	return snc
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableConditionType(i *int) *SopNodeCreate {
+	if i != nil {
+		snc.SetConditionType(*i)
+	}
+	return snc
+}
+
+// SetConditionList sets the "condition_list" field.
+func (snc *SopNodeCreate) SetConditionList(s []string) *SopNodeCreate {
+	snc.mutation.SetConditionList(s)
+	return snc
+}
+
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snc *SopNodeCreate) SetNoReplyCondition(u uint64) *SopNodeCreate {
+	snc.mutation.SetNoReplyCondition(u)
+	return snc
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableNoReplyCondition(u *uint64) *SopNodeCreate {
+	if u != nil {
+		snc.SetNoReplyCondition(*u)
+	}
+	return snc
+}
+
+// SetActionMessage sets the "action_message" field.
+func (snc *SopNodeCreate) SetActionMessage(ct []custom_types.Action) *SopNodeCreate {
+	snc.mutation.SetActionMessage(ct)
+	return snc
+}
+
+// SetActionLabel sets the "action_label" field.
+func (snc *SopNodeCreate) SetActionLabel(u []uint64) *SopNodeCreate {
+	snc.mutation.SetActionLabel(u)
+	return snc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (snc *SopNodeCreate) SetDeletedAt(t time.Time) *SopNodeCreate {
+	snc.mutation.SetDeletedAt(t)
+	return snc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (snc *SopNodeCreate) SetNillableDeletedAt(t *time.Time) *SopNodeCreate {
+	if t != nil {
+		snc.SetDeletedAt(*t)
+	}
+	return snc
+}
+
+// SetID sets the "id" field.
+func (snc *SopNodeCreate) SetID(u uint64) *SopNodeCreate {
+	snc.mutation.SetID(u)
+	return snc
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (snc *SopNodeCreate) SetSopStageID(id uint64) *SopNodeCreate {
+	snc.mutation.SetSopStageID(id)
+	return snc
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (snc *SopNodeCreate) SetSopStage(s *SopStage) *SopNodeCreate {
+	return snc.SetSopStageID(s.ID)
+}
+
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snc *SopNodeCreate) AddNodeMessageIDs(ids ...uint64) *SopNodeCreate {
+	snc.mutation.AddNodeMessageIDs(ids...)
+	return snc
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snc *SopNodeCreate) AddNodeMessages(m ...*MessageRecords) *SopNodeCreate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snc.AddNodeMessageIDs(ids...)
+}
+
+// Mutation returns the SopNodeMutation object of the builder.
+func (snc *SopNodeCreate) Mutation() *SopNodeMutation {
+	return snc.mutation
+}
+
+// Save creates the SopNode in the database.
+func (snc *SopNodeCreate) Save(ctx context.Context) (*SopNode, error) {
+	snc.defaults()
+	return withHooks(ctx, snc.sqlSave, snc.mutation, snc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (snc *SopNodeCreate) SaveX(ctx context.Context) *SopNode {
+	v, err := snc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (snc *SopNodeCreate) Exec(ctx context.Context) error {
+	_, err := snc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (snc *SopNodeCreate) ExecX(ctx context.Context) {
+	if err := snc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (snc *SopNodeCreate) defaults() {
+	if _, ok := snc.mutation.CreatedAt(); !ok {
+		v := sopnode.DefaultCreatedAt()
+		snc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := snc.mutation.UpdatedAt(); !ok {
+		v := sopnode.DefaultUpdatedAt()
+		snc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := snc.mutation.Status(); !ok {
+		v := sopnode.DefaultStatus
+		snc.mutation.SetStatus(v)
+	}
+	if _, ok := snc.mutation.Name(); !ok {
+		v := sopnode.DefaultName
+		snc.mutation.SetName(v)
+	}
+	if _, ok := snc.mutation.ConditionType(); !ok {
+		v := sopnode.DefaultConditionType
+		snc.mutation.SetConditionType(v)
+	}
+	if _, ok := snc.mutation.NoReplyCondition(); !ok {
+		v := sopnode.DefaultNoReplyCondition
+		snc.mutation.SetNoReplyCondition(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (snc *SopNodeCreate) check() error {
+	if _, ok := snc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "SopNode.created_at"`)}
+	}
+	if _, ok := snc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "SopNode.updated_at"`)}
+	}
+	if _, ok := snc.mutation.StageID(); !ok {
+		return &ValidationError{Name: "stage_id", err: errors.New(`ent: missing required field "SopNode.stage_id"`)}
+	}
+	if _, ok := snc.mutation.ParentID(); !ok {
+		return &ValidationError{Name: "parent_id", err: errors.New(`ent: missing required field "SopNode.parent_id"`)}
+	}
+	if _, ok := snc.mutation.Name(); !ok {
+		return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "SopNode.name"`)}
+	}
+	if _, ok := snc.mutation.ConditionType(); !ok {
+		return &ValidationError{Name: "condition_type", err: errors.New(`ent: missing required field "SopNode.condition_type"`)}
+	}
+	if _, ok := snc.mutation.NoReplyCondition(); !ok {
+		return &ValidationError{Name: "no_reply_condition", err: errors.New(`ent: missing required field "SopNode.no_reply_condition"`)}
+	}
+	if _, ok := snc.mutation.SopStageID(); !ok {
+		return &ValidationError{Name: "sop_stage", err: errors.New(`ent: missing required edge "SopNode.sop_stage"`)}
+	}
+	return nil
+}
+
+func (snc *SopNodeCreate) sqlSave(ctx context.Context) (*SopNode, error) {
+	if err := snc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := snc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, snc.driver, _spec); err != nil {
+		if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	if _spec.ID.Value != _node.ID {
+		id := _spec.ID.Value.(int64)
+		_node.ID = uint64(id)
+	}
+	snc.mutation.id = &_node.ID
+	snc.mutation.done = true
+	return _node, nil
+}
+
+func (snc *SopNodeCreate) createSpec() (*SopNode, *sqlgraph.CreateSpec) {
+	var (
+		_node = &SopNode{config: snc.config}
+		_spec = sqlgraph.NewCreateSpec(sopnode.Table, sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64))
+	)
+	if id, ok := snc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := snc.mutation.CreatedAt(); ok {
+		_spec.SetField(sopnode.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := snc.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopnode.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := snc.mutation.Status(); ok {
+		_spec.SetField(sopnode.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := snc.mutation.ParentID(); ok {
+		_spec.SetField(sopnode.FieldParentID, field.TypeUint64, value)
+		_node.ParentID = value
+	}
+	if value, ok := snc.mutation.Name(); ok {
+		_spec.SetField(sopnode.FieldName, field.TypeString, value)
+		_node.Name = value
+	}
+	if value, ok := snc.mutation.ConditionType(); ok {
+		_spec.SetField(sopnode.FieldConditionType, field.TypeInt, value)
+		_node.ConditionType = value
+	}
+	if value, ok := snc.mutation.ConditionList(); ok {
+		_spec.SetField(sopnode.FieldConditionList, field.TypeJSON, value)
+		_node.ConditionList = value
+	}
+	if value, ok := snc.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+		_node.NoReplyCondition = value
+	}
+	if value, ok := snc.mutation.ActionMessage(); ok {
+		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
+		_node.ActionMessage = value
+	}
+	if value, ok := snc.mutation.ActionLabel(); ok {
+		_spec.SetField(sopnode.FieldActionLabel, field.TypeJSON, value)
+		_node.ActionLabel = value
+	}
+	if value, ok := snc.mutation.DeletedAt(); ok {
+		_spec.SetField(sopnode.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if nodes := snc.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopnode.SopStageTable,
+			Columns: []string{sopnode.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.StageID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := snc.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	return _node, _spec
+}
+
+// SopNodeCreateBulk is the builder for creating many SopNode entities in bulk.
+type SopNodeCreateBulk struct {
+	config
+	err      error
+	builders []*SopNodeCreate
+}
+
+// Save creates the SopNode entities in the database.
+func (sncb *SopNodeCreateBulk) Save(ctx context.Context) ([]*SopNode, error) {
+	if sncb.err != nil {
+		return nil, sncb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(sncb.builders))
+	nodes := make([]*SopNode, len(sncb.builders))
+	mutators := make([]Mutator, len(sncb.builders))
+	for i := range sncb.builders {
+		func(i int, root context.Context) {
+			builder := sncb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*SopNodeMutation)
+				if !ok {
+					return nil, fmt.Errorf("unexpected mutation type %T", m)
+				}
+				if err := builder.check(); err != nil {
+					return nil, err
+				}
+				builder.mutation = mutation
+				var err error
+				nodes[i], specs[i] = builder.createSpec()
+				if i < len(mutators)-1 {
+					_, err = mutators[i+1].Mutate(root, sncb.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, sncb.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 && nodes[i].ID == 0 {
+					id := specs[i].ID.Value.(int64)
+					nodes[i].ID = uint64(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, sncb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (sncb *SopNodeCreateBulk) SaveX(ctx context.Context) []*SopNode {
+	v, err := sncb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (sncb *SopNodeCreateBulk) Exec(ctx context.Context) error {
+	_, err := sncb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (sncb *SopNodeCreateBulk) ExecX(ctx context.Context) {
+	if err := sncb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/sopnode_delete.go

@@ -0,0 +1,88 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+)
+
+// SopNodeDelete is the builder for deleting a SopNode entity.
+type SopNodeDelete struct {
+	config
+	hooks    []Hook
+	mutation *SopNodeMutation
+}
+
+// Where appends a list predicates to the SopNodeDelete builder.
+func (snd *SopNodeDelete) Where(ps ...predicate.SopNode) *SopNodeDelete {
+	snd.mutation.Where(ps...)
+	return snd
+}
+
+// Exec executes the deletion query and returns how many vertices were deleted.
+func (snd *SopNodeDelete) Exec(ctx context.Context) (int, error) {
+	return withHooks(ctx, snd.sqlExec, snd.mutation, snd.hooks)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (snd *SopNodeDelete) ExecX(ctx context.Context) int {
+	n, err := snd.Exec(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func (snd *SopNodeDelete) sqlExec(ctx context.Context) (int, error) {
+	_spec := sqlgraph.NewDeleteSpec(sopnode.Table, sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64))
+	if ps := snd.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	affected, err := sqlgraph.DeleteNodes(ctx, snd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	snd.mutation.done = true
+	return affected, err
+}
+
+// SopNodeDeleteOne is the builder for deleting a single SopNode entity.
+type SopNodeDeleteOne struct {
+	snd *SopNodeDelete
+}
+
+// Where appends a list predicates to the SopNodeDelete builder.
+func (sndo *SopNodeDeleteOne) Where(ps ...predicate.SopNode) *SopNodeDeleteOne {
+	sndo.snd.mutation.Where(ps...)
+	return sndo
+}
+
+// Exec executes the deletion query.
+func (sndo *SopNodeDeleteOne) Exec(ctx context.Context) error {
+	n, err := sndo.snd.Exec(ctx)
+	switch {
+	case err != nil:
+		return err
+	case n == 0:
+		return &NotFoundError{sopnode.Label}
+	default:
+		return nil
+	}
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (sndo *SopNodeDeleteOne) ExecX(ctx context.Context) {
+	if err := sndo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 681 - 0
ent/sopnode_query.go

@@ -0,0 +1,681 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"database/sql/driver"
+	"fmt"
+	"math"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+)
+
+// SopNodeQuery is the builder for querying SopNode entities.
+type SopNodeQuery struct {
+	config
+	ctx              *QueryContext
+	order            []sopnode.OrderOption
+	inters           []Interceptor
+	predicates       []predicate.SopNode
+	withSopStage     *SopStageQuery
+	withNodeMessages *MessageRecordsQuery
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the SopNodeQuery builder.
+func (snq *SopNodeQuery) Where(ps ...predicate.SopNode) *SopNodeQuery {
+	snq.predicates = append(snq.predicates, ps...)
+	return snq
+}
+
+// Limit the number of records to be returned by this query.
+func (snq *SopNodeQuery) Limit(limit int) *SopNodeQuery {
+	snq.ctx.Limit = &limit
+	return snq
+}
+
+// Offset to start from.
+func (snq *SopNodeQuery) Offset(offset int) *SopNodeQuery {
+	snq.ctx.Offset = &offset
+	return snq
+}
+
+// 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 (snq *SopNodeQuery) Unique(unique bool) *SopNodeQuery {
+	snq.ctx.Unique = &unique
+	return snq
+}
+
+// Order specifies how the records should be ordered.
+func (snq *SopNodeQuery) Order(o ...sopnode.OrderOption) *SopNodeQuery {
+	snq.order = append(snq.order, o...)
+	return snq
+}
+
+// QuerySopStage chains the current query on the "sop_stage" edge.
+func (snq *SopNodeQuery) QuerySopStage() *SopStageQuery {
+	query := (&SopStageClient{config: snq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := snq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := snq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, selector),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, sopnode.SopStageTable, sopnode.SopStageColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(snq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QueryNodeMessages chains the current query on the "node_messages" edge.
+func (snq *SopNodeQuery) QueryNodeMessages() *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: snq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := snq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := snq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopnode.Table, sopnode.FieldID, selector),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopnode.NodeMessagesTable, sopnode.NodeMessagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(snq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// First returns the first SopNode entity from the query.
+// Returns a *NotFoundError when no SopNode was found.
+func (snq *SopNodeQuery) First(ctx context.Context) (*SopNode, error) {
+	nodes, err := snq.Limit(1).All(setContextOp(ctx, snq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{sopnode.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (snq *SopNodeQuery) FirstX(ctx context.Context) *SopNode {
+	node, err := snq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first SopNode ID from the query.
+// Returns a *NotFoundError when no SopNode ID was found.
+func (snq *SopNodeQuery) FirstID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = snq.Limit(1).IDs(setContextOp(ctx, snq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{sopnode.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (snq *SopNodeQuery) FirstIDX(ctx context.Context) uint64 {
+	id, err := snq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single SopNode entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one SopNode entity is found.
+// Returns a *NotFoundError when no SopNode entities are found.
+func (snq *SopNodeQuery) Only(ctx context.Context) (*SopNode, error) {
+	nodes, err := snq.Limit(2).All(setContextOp(ctx, snq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{sopnode.Label}
+	default:
+		return nil, &NotSingularError{sopnode.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (snq *SopNodeQuery) OnlyX(ctx context.Context) *SopNode {
+	node, err := snq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only SopNode ID in the query.
+// Returns a *NotSingularError when more than one SopNode ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (snq *SopNodeQuery) OnlyID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = snq.Limit(2).IDs(setContextOp(ctx, snq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{sopnode.Label}
+	default:
+		err = &NotSingularError{sopnode.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (snq *SopNodeQuery) OnlyIDX(ctx context.Context) uint64 {
+	id, err := snq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of SopNodes.
+func (snq *SopNodeQuery) All(ctx context.Context) ([]*SopNode, error) {
+	ctx = setContextOp(ctx, snq.ctx, "All")
+	if err := snq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*SopNode, *SopNodeQuery]()
+	return withInterceptors[[]*SopNode](ctx, snq, qr, snq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (snq *SopNodeQuery) AllX(ctx context.Context) []*SopNode {
+	nodes, err := snq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of SopNode IDs.
+func (snq *SopNodeQuery) IDs(ctx context.Context) (ids []uint64, err error) {
+	if snq.ctx.Unique == nil && snq.path != nil {
+		snq.Unique(true)
+	}
+	ctx = setContextOp(ctx, snq.ctx, "IDs")
+	if err = snq.Select(sopnode.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (snq *SopNodeQuery) IDsX(ctx context.Context) []uint64 {
+	ids, err := snq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (snq *SopNodeQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, snq.ctx, "Count")
+	if err := snq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, snq, querierCount[*SopNodeQuery](), snq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (snq *SopNodeQuery) CountX(ctx context.Context) int {
+	count, err := snq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (snq *SopNodeQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, snq.ctx, "Exist")
+	switch _, err := snq.FirstID(ctx); {
+	case IsNotFound(err):
+		return false, nil
+	case err != nil:
+		return false, fmt.Errorf("ent: check existence: %w", err)
+	default:
+		return true, nil
+	}
+}
+
+// ExistX is like Exist, but panics if an error occurs.
+func (snq *SopNodeQuery) ExistX(ctx context.Context) bool {
+	exist, err := snq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the SopNodeQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (snq *SopNodeQuery) Clone() *SopNodeQuery {
+	if snq == nil {
+		return nil
+	}
+	return &SopNodeQuery{
+		config:           snq.config,
+		ctx:              snq.ctx.Clone(),
+		order:            append([]sopnode.OrderOption{}, snq.order...),
+		inters:           append([]Interceptor{}, snq.inters...),
+		predicates:       append([]predicate.SopNode{}, snq.predicates...),
+		withSopStage:     snq.withSopStage.Clone(),
+		withNodeMessages: snq.withNodeMessages.Clone(),
+		// clone intermediate query.
+		sql:  snq.sql.Clone(),
+		path: snq.path,
+	}
+}
+
+// WithSopStage tells the query-builder to eager-load the nodes that are connected to
+// the "sop_stage" edge. The optional arguments are used to configure the query builder of the edge.
+func (snq *SopNodeQuery) WithSopStage(opts ...func(*SopStageQuery)) *SopNodeQuery {
+	query := (&SopStageClient{config: snq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	snq.withSopStage = query
+	return snq
+}
+
+// WithNodeMessages tells the query-builder to eager-load the nodes that are connected to
+// the "node_messages" edge. The optional arguments are used to configure the query builder of the edge.
+func (snq *SopNodeQuery) WithNodeMessages(opts ...func(*MessageRecordsQuery)) *SopNodeQuery {
+	query := (&MessageRecordsClient{config: snq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	snq.withNodeMessages = query
+	return snq
+}
+
+// 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//		Count int `json:"count,omitempty"`
+//	}
+//
+//	client.SopNode.Query().
+//		GroupBy(sopnode.FieldCreatedAt).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (snq *SopNodeQuery) GroupBy(field string, fields ...string) *SopNodeGroupBy {
+	snq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &SopNodeGroupBy{build: snq}
+	grbuild.flds = &snq.ctx.Fields
+	grbuild.label = sopnode.Label
+	grbuild.scan = 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//	}
+//
+//	client.SopNode.Query().
+//		Select(sopnode.FieldCreatedAt).
+//		Scan(ctx, &v)
+func (snq *SopNodeQuery) Select(fields ...string) *SopNodeSelect {
+	snq.ctx.Fields = append(snq.ctx.Fields, fields...)
+	sbuild := &SopNodeSelect{SopNodeQuery: snq}
+	sbuild.label = sopnode.Label
+	sbuild.flds, sbuild.scan = &snq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a SopNodeSelect configured with the given aggregations.
+func (snq *SopNodeQuery) Aggregate(fns ...AggregateFunc) *SopNodeSelect {
+	return snq.Select().Aggregate(fns...)
+}
+
+func (snq *SopNodeQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range snq.inters {
+		if inter == nil {
+			return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
+		}
+		if trv, ok := inter.(Traverser); ok {
+			if err := trv.Traverse(ctx, snq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range snq.ctx.Fields {
+		if !sopnode.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if snq.path != nil {
+		prev, err := snq.path(ctx)
+		if err != nil {
+			return err
+		}
+		snq.sql = prev
+	}
+	return nil
+}
+
+func (snq *SopNodeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*SopNode, error) {
+	var (
+		nodes       = []*SopNode{}
+		_spec       = snq.querySpec()
+		loadedTypes = [2]bool{
+			snq.withSopStage != nil,
+			snq.withNodeMessages != nil,
+		}
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*SopNode).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &SopNode{config: snq.config}
+		nodes = append(nodes, node)
+		node.Edges.loadedTypes = loadedTypes
+		return node.assignValues(columns, values)
+	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
+	if err := sqlgraph.QueryNodes(ctx, snq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	if query := snq.withSopStage; query != nil {
+		if err := snq.loadSopStage(ctx, query, nodes, nil,
+			func(n *SopNode, e *SopStage) { n.Edges.SopStage = e }); err != nil {
+			return nil, err
+		}
+	}
+	if query := snq.withNodeMessages; query != nil {
+		if err := snq.loadNodeMessages(ctx, query, nodes,
+			func(n *SopNode) { n.Edges.NodeMessages = []*MessageRecords{} },
+			func(n *SopNode, e *MessageRecords) { n.Edges.NodeMessages = append(n.Edges.NodeMessages, e) }); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+func (snq *SopNodeQuery) loadSopStage(ctx context.Context, query *SopStageQuery, nodes []*SopNode, init func(*SopNode), assign func(*SopNode, *SopStage)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*SopNode)
+	for i := range nodes {
+		fk := nodes[i].StageID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(sopstage.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 "stage_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+func (snq *SopNodeQuery) loadNodeMessages(ctx context.Context, query *MessageRecordsQuery, nodes []*SopNode, init func(*SopNode), assign func(*SopNode, *MessageRecords)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopNode)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	query.withFKs = true
+	query.Where(predicate.MessageRecords(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(sopnode.NodeMessagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.sop_node_node_messages
+		if fk == nil {
+			return fmt.Errorf(`foreign-key "sop_node_node_messages" is nil for node %v`, n.ID)
+		}
+		node, ok := nodeids[*fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "sop_node_node_messages" returned %v for node %v`, *fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
+
+func (snq *SopNodeQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := snq.querySpec()
+	_spec.Node.Columns = snq.ctx.Fields
+	if len(snq.ctx.Fields) > 0 {
+		_spec.Unique = snq.ctx.Unique != nil && *snq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, snq.driver, _spec)
+}
+
+func (snq *SopNodeQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(sopnode.Table, sopnode.Columns, sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64))
+	_spec.From = snq.sql
+	if unique := snq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if snq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := snq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, sopnode.FieldID)
+		for i := range fields {
+			if fields[i] != sopnode.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+		if snq.withSopStage != nil {
+			_spec.Node.AddColumnOnce(sopnode.FieldStageID)
+		}
+	}
+	if ps := snq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := snq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := snq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := snq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (snq *SopNodeQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(snq.driver.Dialect())
+	t1 := builder.Table(sopnode.Table)
+	columns := snq.ctx.Fields
+	if len(columns) == 0 {
+		columns = sopnode.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if snq.sql != nil {
+		selector = snq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if snq.ctx.Unique != nil && *snq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range snq.predicates {
+		p(selector)
+	}
+	for _, p := range snq.order {
+		p(selector)
+	}
+	if offset := snq.ctx.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 := snq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// SopNodeGroupBy is the group-by builder for SopNode entities.
+type SopNodeGroupBy struct {
+	selector
+	build *SopNodeQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (sngb *SopNodeGroupBy) Aggregate(fns ...AggregateFunc) *SopNodeGroupBy {
+	sngb.fns = append(sngb.fns, fns...)
+	return sngb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (sngb *SopNodeGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, sngb.build.ctx, "GroupBy")
+	if err := sngb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopNodeQuery, *SopNodeGroupBy](ctx, sngb.build, sngb, sngb.build.inters, v)
+}
+
+func (sngb *SopNodeGroupBy) sqlScan(ctx context.Context, root *SopNodeQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(sngb.fns))
+	for _, fn := range sngb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*sngb.flds)+len(sngb.fns))
+		for _, f := range *sngb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*sngb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := sngb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// SopNodeSelect is the builder for selecting fields of SopNode entities.
+type SopNodeSelect struct {
+	*SopNodeQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (sns *SopNodeSelect) Aggregate(fns ...AggregateFunc) *SopNodeSelect {
+	sns.fns = append(sns.fns, fns...)
+	return sns
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (sns *SopNodeSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, sns.ctx, "Select")
+	if err := sns.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopNodeQuery, *SopNodeSelect](ctx, sns.SopNodeQuery, sns, sns.inters, v)
+}
+
+func (sns *SopNodeSelect) sqlScan(ctx context.Context, root *SopNodeQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(sns.fns))
+	for _, fn := range sns.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*sns.selector.flds); {
+	case n == 0 && len(aggregation) > 0:
+		selector.Select(aggregation...)
+	case n != 0 && len(aggregation) > 0:
+		selector.AppendSelect(aggregation...)
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := sns.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 1014 - 0
ent/sopnode_update.go

@@ -0,0 +1,1014 @@
+// 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/dialect/sql/sqljson"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+)
+
+// SopNodeUpdate is the builder for updating SopNode entities.
+type SopNodeUpdate struct {
+	config
+	hooks    []Hook
+	mutation *SopNodeMutation
+}
+
+// Where appends a list predicates to the SopNodeUpdate builder.
+func (snu *SopNodeUpdate) Where(ps ...predicate.SopNode) *SopNodeUpdate {
+	snu.mutation.Where(ps...)
+	return snu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (snu *SopNodeUpdate) SetUpdatedAt(t time.Time) *SopNodeUpdate {
+	snu.mutation.SetUpdatedAt(t)
+	return snu
+}
+
+// SetStatus sets the "status" field.
+func (snu *SopNodeUpdate) SetStatus(u uint8) *SopNodeUpdate {
+	snu.mutation.ResetStatus()
+	snu.mutation.SetStatus(u)
+	return snu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableStatus(u *uint8) *SopNodeUpdate {
+	if u != nil {
+		snu.SetStatus(*u)
+	}
+	return snu
+}
+
+// AddStatus adds u to the "status" field.
+func (snu *SopNodeUpdate) AddStatus(u int8) *SopNodeUpdate {
+	snu.mutation.AddStatus(u)
+	return snu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (snu *SopNodeUpdate) ClearStatus() *SopNodeUpdate {
+	snu.mutation.ClearStatus()
+	return snu
+}
+
+// SetStageID sets the "stage_id" field.
+func (snu *SopNodeUpdate) SetStageID(u uint64) *SopNodeUpdate {
+	snu.mutation.SetStageID(u)
+	return snu
+}
+
+// SetNillableStageID sets the "stage_id" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableStageID(u *uint64) *SopNodeUpdate {
+	if u != nil {
+		snu.SetStageID(*u)
+	}
+	return snu
+}
+
+// SetParentID sets the "parent_id" field.
+func (snu *SopNodeUpdate) SetParentID(u uint64) *SopNodeUpdate {
+	snu.mutation.ResetParentID()
+	snu.mutation.SetParentID(u)
+	return snu
+}
+
+// SetNillableParentID sets the "parent_id" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableParentID(u *uint64) *SopNodeUpdate {
+	if u != nil {
+		snu.SetParentID(*u)
+	}
+	return snu
+}
+
+// AddParentID adds u to the "parent_id" field.
+func (snu *SopNodeUpdate) AddParentID(u int64) *SopNodeUpdate {
+	snu.mutation.AddParentID(u)
+	return snu
+}
+
+// SetName sets the "name" field.
+func (snu *SopNodeUpdate) SetName(s string) *SopNodeUpdate {
+	snu.mutation.SetName(s)
+	return snu
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableName(s *string) *SopNodeUpdate {
+	if s != nil {
+		snu.SetName(*s)
+	}
+	return snu
+}
+
+// SetConditionType sets the "condition_type" field.
+func (snu *SopNodeUpdate) SetConditionType(i int) *SopNodeUpdate {
+	snu.mutation.ResetConditionType()
+	snu.mutation.SetConditionType(i)
+	return snu
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableConditionType(i *int) *SopNodeUpdate {
+	if i != nil {
+		snu.SetConditionType(*i)
+	}
+	return snu
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (snu *SopNodeUpdate) AddConditionType(i int) *SopNodeUpdate {
+	snu.mutation.AddConditionType(i)
+	return snu
+}
+
+// SetConditionList sets the "condition_list" field.
+func (snu *SopNodeUpdate) SetConditionList(s []string) *SopNodeUpdate {
+	snu.mutation.SetConditionList(s)
+	return snu
+}
+
+// AppendConditionList appends s to the "condition_list" field.
+func (snu *SopNodeUpdate) AppendConditionList(s []string) *SopNodeUpdate {
+	snu.mutation.AppendConditionList(s)
+	return snu
+}
+
+// ClearConditionList clears the value of the "condition_list" field.
+func (snu *SopNodeUpdate) ClearConditionList() *SopNodeUpdate {
+	snu.mutation.ClearConditionList()
+	return snu
+}
+
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snu *SopNodeUpdate) SetNoReplyCondition(u uint64) *SopNodeUpdate {
+	snu.mutation.ResetNoReplyCondition()
+	snu.mutation.SetNoReplyCondition(u)
+	return snu
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableNoReplyCondition(u *uint64) *SopNodeUpdate {
+	if u != nil {
+		snu.SetNoReplyCondition(*u)
+	}
+	return snu
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (snu *SopNodeUpdate) AddNoReplyCondition(u int64) *SopNodeUpdate {
+	snu.mutation.AddNoReplyCondition(u)
+	return snu
+}
+
+// SetActionMessage sets the "action_message" field.
+func (snu *SopNodeUpdate) SetActionMessage(ct []custom_types.Action) *SopNodeUpdate {
+	snu.mutation.SetActionMessage(ct)
+	return snu
+}
+
+// AppendActionMessage appends ct to the "action_message" field.
+func (snu *SopNodeUpdate) AppendActionMessage(ct []custom_types.Action) *SopNodeUpdate {
+	snu.mutation.AppendActionMessage(ct)
+	return snu
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (snu *SopNodeUpdate) ClearActionMessage() *SopNodeUpdate {
+	snu.mutation.ClearActionMessage()
+	return snu
+}
+
+// SetActionLabel sets the "action_label" field.
+func (snu *SopNodeUpdate) SetActionLabel(u []uint64) *SopNodeUpdate {
+	snu.mutation.SetActionLabel(u)
+	return snu
+}
+
+// AppendActionLabel appends u to the "action_label" field.
+func (snu *SopNodeUpdate) AppendActionLabel(u []uint64) *SopNodeUpdate {
+	snu.mutation.AppendActionLabel(u)
+	return snu
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (snu *SopNodeUpdate) ClearActionLabel() *SopNodeUpdate {
+	snu.mutation.ClearActionLabel()
+	return snu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (snu *SopNodeUpdate) SetDeletedAt(t time.Time) *SopNodeUpdate {
+	snu.mutation.SetDeletedAt(t)
+	return snu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (snu *SopNodeUpdate) SetNillableDeletedAt(t *time.Time) *SopNodeUpdate {
+	if t != nil {
+		snu.SetDeletedAt(*t)
+	}
+	return snu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (snu *SopNodeUpdate) ClearDeletedAt() *SopNodeUpdate {
+	snu.mutation.ClearDeletedAt()
+	return snu
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (snu *SopNodeUpdate) SetSopStageID(id uint64) *SopNodeUpdate {
+	snu.mutation.SetSopStageID(id)
+	return snu
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (snu *SopNodeUpdate) SetSopStage(s *SopStage) *SopNodeUpdate {
+	return snu.SetSopStageID(s.ID)
+}
+
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snu *SopNodeUpdate) AddNodeMessageIDs(ids ...uint64) *SopNodeUpdate {
+	snu.mutation.AddNodeMessageIDs(ids...)
+	return snu
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snu *SopNodeUpdate) AddNodeMessages(m ...*MessageRecords) *SopNodeUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snu.AddNodeMessageIDs(ids...)
+}
+
+// Mutation returns the SopNodeMutation object of the builder.
+func (snu *SopNodeUpdate) Mutation() *SopNodeMutation {
+	return snu.mutation
+}
+
+// ClearSopStage clears the "sop_stage" edge to the SopStage entity.
+func (snu *SopNodeUpdate) ClearSopStage() *SopNodeUpdate {
+	snu.mutation.ClearSopStage()
+	return snu
+}
+
+// ClearNodeMessages clears all "node_messages" edges to the MessageRecords entity.
+func (snu *SopNodeUpdate) ClearNodeMessages() *SopNodeUpdate {
+	snu.mutation.ClearNodeMessages()
+	return snu
+}
+
+// RemoveNodeMessageIDs removes the "node_messages" edge to MessageRecords entities by IDs.
+func (snu *SopNodeUpdate) RemoveNodeMessageIDs(ids ...uint64) *SopNodeUpdate {
+	snu.mutation.RemoveNodeMessageIDs(ids...)
+	return snu
+}
+
+// RemoveNodeMessages removes "node_messages" edges to MessageRecords entities.
+func (snu *SopNodeUpdate) RemoveNodeMessages(m ...*MessageRecords) *SopNodeUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snu.RemoveNodeMessageIDs(ids...)
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (snu *SopNodeUpdate) Save(ctx context.Context) (int, error) {
+	snu.defaults()
+	return withHooks(ctx, snu.sqlSave, snu.mutation, snu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (snu *SopNodeUpdate) SaveX(ctx context.Context) int {
+	affected, err := snu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (snu *SopNodeUpdate) Exec(ctx context.Context) error {
+	_, err := snu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (snu *SopNodeUpdate) ExecX(ctx context.Context) {
+	if err := snu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (snu *SopNodeUpdate) defaults() {
+	if _, ok := snu.mutation.UpdatedAt(); !ok {
+		v := sopnode.UpdateDefaultUpdatedAt()
+		snu.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (snu *SopNodeUpdate) check() error {
+	if _, ok := snu.mutation.SopStageID(); snu.mutation.SopStageCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "SopNode.sop_stage"`)
+	}
+	return nil
+}
+
+func (snu *SopNodeUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	if err := snu.check(); err != nil {
+		return n, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(sopnode.Table, sopnode.Columns, sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64))
+	if ps := snu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := snu.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopnode.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := snu.mutation.Status(); ok {
+		_spec.SetField(sopnode.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := snu.mutation.AddedStatus(); ok {
+		_spec.AddField(sopnode.FieldStatus, field.TypeUint8, value)
+	}
+	if snu.mutation.StatusCleared() {
+		_spec.ClearField(sopnode.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := snu.mutation.ParentID(); ok {
+		_spec.SetField(sopnode.FieldParentID, field.TypeUint64, value)
+	}
+	if value, ok := snu.mutation.AddedParentID(); ok {
+		_spec.AddField(sopnode.FieldParentID, field.TypeUint64, value)
+	}
+	if value, ok := snu.mutation.Name(); ok {
+		_spec.SetField(sopnode.FieldName, field.TypeString, value)
+	}
+	if value, ok := snu.mutation.ConditionType(); ok {
+		_spec.SetField(sopnode.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := snu.mutation.AddedConditionType(); ok {
+		_spec.AddField(sopnode.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := snu.mutation.ConditionList(); ok {
+		_spec.SetField(sopnode.FieldConditionList, field.TypeJSON, value)
+	}
+	if value, ok := snu.mutation.AppendedConditionList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldConditionList, value)
+		})
+	}
+	if snu.mutation.ConditionListCleared() {
+		_spec.ClearField(sopnode.FieldConditionList, field.TypeJSON)
+	}
+	if value, ok := snu.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snu.mutation.AddedNoReplyCondition(); ok {
+		_spec.AddField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snu.mutation.ActionMessage(); ok {
+		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
+	}
+	if value, ok := snu.mutation.AppendedActionMessage(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldActionMessage, value)
+		})
+	}
+	if snu.mutation.ActionMessageCleared() {
+		_spec.ClearField(sopnode.FieldActionMessage, field.TypeJSON)
+	}
+	if value, ok := snu.mutation.ActionLabel(); ok {
+		_spec.SetField(sopnode.FieldActionLabel, field.TypeJSON, value)
+	}
+	if value, ok := snu.mutation.AppendedActionLabel(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldActionLabel, value)
+		})
+	}
+	if snu.mutation.ActionLabelCleared() {
+		_spec.ClearField(sopnode.FieldActionLabel, field.TypeJSON)
+	}
+	if value, ok := snu.mutation.DeletedAt(); ok {
+		_spec.SetField(sopnode.FieldDeletedAt, field.TypeTime, value)
+	}
+	if snu.mutation.DeletedAtCleared() {
+		_spec.ClearField(sopnode.FieldDeletedAt, field.TypeTime)
+	}
+	if snu.mutation.SopStageCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopnode.SopStageTable,
+			Columns: []string{sopnode.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snu.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopnode.SopStageTable,
+			Columns: []string{sopnode.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if snu.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snu.mutation.RemovedNodeMessagesIDs(); len(nodes) > 0 && !snu.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snu.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, snu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{sopnode.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	snu.mutation.done = true
+	return n, nil
+}
+
+// SopNodeUpdateOne is the builder for updating a single SopNode entity.
+type SopNodeUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *SopNodeMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (snuo *SopNodeUpdateOne) SetUpdatedAt(t time.Time) *SopNodeUpdateOne {
+	snuo.mutation.SetUpdatedAt(t)
+	return snuo
+}
+
+// SetStatus sets the "status" field.
+func (snuo *SopNodeUpdateOne) SetStatus(u uint8) *SopNodeUpdateOne {
+	snuo.mutation.ResetStatus()
+	snuo.mutation.SetStatus(u)
+	return snuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableStatus(u *uint8) *SopNodeUpdateOne {
+	if u != nil {
+		snuo.SetStatus(*u)
+	}
+	return snuo
+}
+
+// AddStatus adds u to the "status" field.
+func (snuo *SopNodeUpdateOne) AddStatus(u int8) *SopNodeUpdateOne {
+	snuo.mutation.AddStatus(u)
+	return snuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (snuo *SopNodeUpdateOne) ClearStatus() *SopNodeUpdateOne {
+	snuo.mutation.ClearStatus()
+	return snuo
+}
+
+// SetStageID sets the "stage_id" field.
+func (snuo *SopNodeUpdateOne) SetStageID(u uint64) *SopNodeUpdateOne {
+	snuo.mutation.SetStageID(u)
+	return snuo
+}
+
+// SetNillableStageID sets the "stage_id" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableStageID(u *uint64) *SopNodeUpdateOne {
+	if u != nil {
+		snuo.SetStageID(*u)
+	}
+	return snuo
+}
+
+// SetParentID sets the "parent_id" field.
+func (snuo *SopNodeUpdateOne) SetParentID(u uint64) *SopNodeUpdateOne {
+	snuo.mutation.ResetParentID()
+	snuo.mutation.SetParentID(u)
+	return snuo
+}
+
+// SetNillableParentID sets the "parent_id" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableParentID(u *uint64) *SopNodeUpdateOne {
+	if u != nil {
+		snuo.SetParentID(*u)
+	}
+	return snuo
+}
+
+// AddParentID adds u to the "parent_id" field.
+func (snuo *SopNodeUpdateOne) AddParentID(u int64) *SopNodeUpdateOne {
+	snuo.mutation.AddParentID(u)
+	return snuo
+}
+
+// SetName sets the "name" field.
+func (snuo *SopNodeUpdateOne) SetName(s string) *SopNodeUpdateOne {
+	snuo.mutation.SetName(s)
+	return snuo
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableName(s *string) *SopNodeUpdateOne {
+	if s != nil {
+		snuo.SetName(*s)
+	}
+	return snuo
+}
+
+// SetConditionType sets the "condition_type" field.
+func (snuo *SopNodeUpdateOne) SetConditionType(i int) *SopNodeUpdateOne {
+	snuo.mutation.ResetConditionType()
+	snuo.mutation.SetConditionType(i)
+	return snuo
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableConditionType(i *int) *SopNodeUpdateOne {
+	if i != nil {
+		snuo.SetConditionType(*i)
+	}
+	return snuo
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (snuo *SopNodeUpdateOne) AddConditionType(i int) *SopNodeUpdateOne {
+	snuo.mutation.AddConditionType(i)
+	return snuo
+}
+
+// SetConditionList sets the "condition_list" field.
+func (snuo *SopNodeUpdateOne) SetConditionList(s []string) *SopNodeUpdateOne {
+	snuo.mutation.SetConditionList(s)
+	return snuo
+}
+
+// AppendConditionList appends s to the "condition_list" field.
+func (snuo *SopNodeUpdateOne) AppendConditionList(s []string) *SopNodeUpdateOne {
+	snuo.mutation.AppendConditionList(s)
+	return snuo
+}
+
+// ClearConditionList clears the value of the "condition_list" field.
+func (snuo *SopNodeUpdateOne) ClearConditionList() *SopNodeUpdateOne {
+	snuo.mutation.ClearConditionList()
+	return snuo
+}
+
+// SetNoReplyCondition sets the "no_reply_condition" field.
+func (snuo *SopNodeUpdateOne) SetNoReplyCondition(u uint64) *SopNodeUpdateOne {
+	snuo.mutation.ResetNoReplyCondition()
+	snuo.mutation.SetNoReplyCondition(u)
+	return snuo
+}
+
+// SetNillableNoReplyCondition sets the "no_reply_condition" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableNoReplyCondition(u *uint64) *SopNodeUpdateOne {
+	if u != nil {
+		snuo.SetNoReplyCondition(*u)
+	}
+	return snuo
+}
+
+// AddNoReplyCondition adds u to the "no_reply_condition" field.
+func (snuo *SopNodeUpdateOne) AddNoReplyCondition(u int64) *SopNodeUpdateOne {
+	snuo.mutation.AddNoReplyCondition(u)
+	return snuo
+}
+
+// SetActionMessage sets the "action_message" field.
+func (snuo *SopNodeUpdateOne) SetActionMessage(ct []custom_types.Action) *SopNodeUpdateOne {
+	snuo.mutation.SetActionMessage(ct)
+	return snuo
+}
+
+// AppendActionMessage appends ct to the "action_message" field.
+func (snuo *SopNodeUpdateOne) AppendActionMessage(ct []custom_types.Action) *SopNodeUpdateOne {
+	snuo.mutation.AppendActionMessage(ct)
+	return snuo
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (snuo *SopNodeUpdateOne) ClearActionMessage() *SopNodeUpdateOne {
+	snuo.mutation.ClearActionMessage()
+	return snuo
+}
+
+// SetActionLabel sets the "action_label" field.
+func (snuo *SopNodeUpdateOne) SetActionLabel(u []uint64) *SopNodeUpdateOne {
+	snuo.mutation.SetActionLabel(u)
+	return snuo
+}
+
+// AppendActionLabel appends u to the "action_label" field.
+func (snuo *SopNodeUpdateOne) AppendActionLabel(u []uint64) *SopNodeUpdateOne {
+	snuo.mutation.AppendActionLabel(u)
+	return snuo
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (snuo *SopNodeUpdateOne) ClearActionLabel() *SopNodeUpdateOne {
+	snuo.mutation.ClearActionLabel()
+	return snuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (snuo *SopNodeUpdateOne) SetDeletedAt(t time.Time) *SopNodeUpdateOne {
+	snuo.mutation.SetDeletedAt(t)
+	return snuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (snuo *SopNodeUpdateOne) SetNillableDeletedAt(t *time.Time) *SopNodeUpdateOne {
+	if t != nil {
+		snuo.SetDeletedAt(*t)
+	}
+	return snuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (snuo *SopNodeUpdateOne) ClearDeletedAt() *SopNodeUpdateOne {
+	snuo.mutation.ClearDeletedAt()
+	return snuo
+}
+
+// SetSopStageID sets the "sop_stage" edge to the SopStage entity by ID.
+func (snuo *SopNodeUpdateOne) SetSopStageID(id uint64) *SopNodeUpdateOne {
+	snuo.mutation.SetSopStageID(id)
+	return snuo
+}
+
+// SetSopStage sets the "sop_stage" edge to the SopStage entity.
+func (snuo *SopNodeUpdateOne) SetSopStage(s *SopStage) *SopNodeUpdateOne {
+	return snuo.SetSopStageID(s.ID)
+}
+
+// AddNodeMessageIDs adds the "node_messages" edge to the MessageRecords entity by IDs.
+func (snuo *SopNodeUpdateOne) AddNodeMessageIDs(ids ...uint64) *SopNodeUpdateOne {
+	snuo.mutation.AddNodeMessageIDs(ids...)
+	return snuo
+}
+
+// AddNodeMessages adds the "node_messages" edges to the MessageRecords entity.
+func (snuo *SopNodeUpdateOne) AddNodeMessages(m ...*MessageRecords) *SopNodeUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snuo.AddNodeMessageIDs(ids...)
+}
+
+// Mutation returns the SopNodeMutation object of the builder.
+func (snuo *SopNodeUpdateOne) Mutation() *SopNodeMutation {
+	return snuo.mutation
+}
+
+// ClearSopStage clears the "sop_stage" edge to the SopStage entity.
+func (snuo *SopNodeUpdateOne) ClearSopStage() *SopNodeUpdateOne {
+	snuo.mutation.ClearSopStage()
+	return snuo
+}
+
+// ClearNodeMessages clears all "node_messages" edges to the MessageRecords entity.
+func (snuo *SopNodeUpdateOne) ClearNodeMessages() *SopNodeUpdateOne {
+	snuo.mutation.ClearNodeMessages()
+	return snuo
+}
+
+// RemoveNodeMessageIDs removes the "node_messages" edge to MessageRecords entities by IDs.
+func (snuo *SopNodeUpdateOne) RemoveNodeMessageIDs(ids ...uint64) *SopNodeUpdateOne {
+	snuo.mutation.RemoveNodeMessageIDs(ids...)
+	return snuo
+}
+
+// RemoveNodeMessages removes "node_messages" edges to MessageRecords entities.
+func (snuo *SopNodeUpdateOne) RemoveNodeMessages(m ...*MessageRecords) *SopNodeUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return snuo.RemoveNodeMessageIDs(ids...)
+}
+
+// Where appends a list predicates to the SopNodeUpdate builder.
+func (snuo *SopNodeUpdateOne) Where(ps ...predicate.SopNode) *SopNodeUpdateOne {
+	snuo.mutation.Where(ps...)
+	return snuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (snuo *SopNodeUpdateOne) Select(field string, fields ...string) *SopNodeUpdateOne {
+	snuo.fields = append([]string{field}, fields...)
+	return snuo
+}
+
+// Save executes the query and returns the updated SopNode entity.
+func (snuo *SopNodeUpdateOne) Save(ctx context.Context) (*SopNode, error) {
+	snuo.defaults()
+	return withHooks(ctx, snuo.sqlSave, snuo.mutation, snuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (snuo *SopNodeUpdateOne) SaveX(ctx context.Context) *SopNode {
+	node, err := snuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (snuo *SopNodeUpdateOne) Exec(ctx context.Context) error {
+	_, err := snuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (snuo *SopNodeUpdateOne) ExecX(ctx context.Context) {
+	if err := snuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (snuo *SopNodeUpdateOne) defaults() {
+	if _, ok := snuo.mutation.UpdatedAt(); !ok {
+		v := sopnode.UpdateDefaultUpdatedAt()
+		snuo.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (snuo *SopNodeUpdateOne) check() error {
+	if _, ok := snuo.mutation.SopStageID(); snuo.mutation.SopStageCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "SopNode.sop_stage"`)
+	}
+	return nil
+}
+
+func (snuo *SopNodeUpdateOne) sqlSave(ctx context.Context) (_node *SopNode, err error) {
+	if err := snuo.check(); err != nil {
+		return _node, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(sopnode.Table, sopnode.Columns, sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64))
+	id, ok := snuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "SopNode.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := snuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, sopnode.FieldID)
+		for _, f := range fields {
+			if !sopnode.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != sopnode.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := snuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := snuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopnode.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := snuo.mutation.Status(); ok {
+		_spec.SetField(sopnode.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := snuo.mutation.AddedStatus(); ok {
+		_spec.AddField(sopnode.FieldStatus, field.TypeUint8, value)
+	}
+	if snuo.mutation.StatusCleared() {
+		_spec.ClearField(sopnode.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := snuo.mutation.ParentID(); ok {
+		_spec.SetField(sopnode.FieldParentID, field.TypeUint64, value)
+	}
+	if value, ok := snuo.mutation.AddedParentID(); ok {
+		_spec.AddField(sopnode.FieldParentID, field.TypeUint64, value)
+	}
+	if value, ok := snuo.mutation.Name(); ok {
+		_spec.SetField(sopnode.FieldName, field.TypeString, value)
+	}
+	if value, ok := snuo.mutation.ConditionType(); ok {
+		_spec.SetField(sopnode.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := snuo.mutation.AddedConditionType(); ok {
+		_spec.AddField(sopnode.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := snuo.mutation.ConditionList(); ok {
+		_spec.SetField(sopnode.FieldConditionList, field.TypeJSON, value)
+	}
+	if value, ok := snuo.mutation.AppendedConditionList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldConditionList, value)
+		})
+	}
+	if snuo.mutation.ConditionListCleared() {
+		_spec.ClearField(sopnode.FieldConditionList, field.TypeJSON)
+	}
+	if value, ok := snuo.mutation.NoReplyCondition(); ok {
+		_spec.SetField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snuo.mutation.AddedNoReplyCondition(); ok {
+		_spec.AddField(sopnode.FieldNoReplyCondition, field.TypeUint64, value)
+	}
+	if value, ok := snuo.mutation.ActionMessage(); ok {
+		_spec.SetField(sopnode.FieldActionMessage, field.TypeJSON, value)
+	}
+	if value, ok := snuo.mutation.AppendedActionMessage(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldActionMessage, value)
+		})
+	}
+	if snuo.mutation.ActionMessageCleared() {
+		_spec.ClearField(sopnode.FieldActionMessage, field.TypeJSON)
+	}
+	if value, ok := snuo.mutation.ActionLabel(); ok {
+		_spec.SetField(sopnode.FieldActionLabel, field.TypeJSON, value)
+	}
+	if value, ok := snuo.mutation.AppendedActionLabel(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopnode.FieldActionLabel, value)
+		})
+	}
+	if snuo.mutation.ActionLabelCleared() {
+		_spec.ClearField(sopnode.FieldActionLabel, field.TypeJSON)
+	}
+	if value, ok := snuo.mutation.DeletedAt(); ok {
+		_spec.SetField(sopnode.FieldDeletedAt, field.TypeTime, value)
+	}
+	if snuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(sopnode.FieldDeletedAt, field.TypeTime)
+	}
+	if snuo.mutation.SopStageCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopnode.SopStageTable,
+			Columns: []string{sopnode.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snuo.mutation.SopStageIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopnode.SopStageTable,
+			Columns: []string{sopnode.SopStageColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if snuo.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snuo.mutation.RemovedNodeMessagesIDs(); len(nodes) > 0 && !snuo.mutation.NodeMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := snuo.mutation.NodeMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopnode.NodeMessagesTable,
+			Columns: []string{sopnode.NodeMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &SopNode{config: snuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, snuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{sopnode.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	snuo.mutation.done = true
+	return _node, nil
+}

+ 298 - 0
ent/sopstage.go

@@ -0,0 +1,298 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopStage is the model entity for the SopStage schema.
+type SopStage struct {
+	config `json:"-"`
+	// ID of the ent.
+	ID uint64 `json:"id,omitempty"`
+	// Create Time | 创建日期
+	CreatedAt time.Time `json:"created_at,omitempty"`
+	// Update Time | 修改日期
+	UpdatedAt time.Time `json:"updated_at,omitempty"`
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status uint8 `json:"status,omitempty"`
+	// SOP 任务 ID
+	TaskID uint64 `json:"task_id,omitempty"`
+	// 阶段名称
+	Name string `json:"name,omitempty"`
+	// 客群筛选条件类型  1 按标签筛选 2 按客户基本信息筛选
+	ConditionType int `json:"condition_type,omitempty"`
+	// 筛选条件关系  1 满足所有条件(and) 2 满足任意条件(or)
+	ConditionOperator int `json:"condition_operator,omitempty"`
+	// 筛选条件列表
+	ConditionList []custom_types.Condition `json:"condition_list,omitempty"`
+	// 命中后发送的消息内容
+	ActionMessage []custom_types.Action `json:"action_message,omitempty"`
+	// 命中后需要打的标签
+	ActionLabel []uint64 `json:"action_label,omitempty"`
+	// 阶段顺序
+	IndexSort int `json:"index_sort,omitempty"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the SopStageQuery when eager-loading is set.
+	Edges        SopStageEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// SopStageEdges holds the relations/edges for other nodes in the graph.
+type SopStageEdges struct {
+	// SopTask holds the value of the sop_task edge.
+	SopTask *SopTask `json:"sop_task,omitempty"`
+	// StageNodes holds the value of the stage_nodes edge.
+	StageNodes []*SopNode `json:"stage_nodes,omitempty"`
+	// StageMessages holds the value of the stage_messages edge.
+	StageMessages []*MessageRecords `json:"stage_messages,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [3]bool
+}
+
+// SopTaskOrErr returns the SopTask value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e SopStageEdges) SopTaskOrErr() (*SopTask, error) {
+	if e.SopTask != nil {
+		return e.SopTask, nil
+	} else if e.loadedTypes[0] {
+		return nil, &NotFoundError{label: soptask.Label}
+	}
+	return nil, &NotLoadedError{edge: "sop_task"}
+}
+
+// StageNodesOrErr returns the StageNodes value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopStageEdges) StageNodesOrErr() ([]*SopNode, error) {
+	if e.loadedTypes[1] {
+		return e.StageNodes, nil
+	}
+	return nil, &NotLoadedError{edge: "stage_nodes"}
+}
+
+// StageMessagesOrErr returns the StageMessages value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopStageEdges) StageMessagesOrErr() ([]*MessageRecords, error) {
+	if e.loadedTypes[2] {
+		return e.StageMessages, nil
+	}
+	return nil, &NotLoadedError{edge: "stage_messages"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*SopStage) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case sopstage.FieldConditionList, sopstage.FieldActionMessage, sopstage.FieldActionLabel:
+			values[i] = new([]byte)
+		case sopstage.FieldID, sopstage.FieldStatus, sopstage.FieldTaskID, sopstage.FieldConditionType, sopstage.FieldConditionOperator, sopstage.FieldIndexSort:
+			values[i] = new(sql.NullInt64)
+		case sopstage.FieldName:
+			values[i] = new(sql.NullString)
+		case sopstage.FieldCreatedAt, sopstage.FieldUpdatedAt, sopstage.FieldDeletedAt:
+			values[i] = new(sql.NullTime)
+		default:
+			values[i] = new(sql.UnknownType)
+		}
+	}
+	return values, nil
+}
+
+// assignValues assigns the values that were returned from sql.Rows (after scanning)
+// to the SopStage fields.
+func (ss *SopStage) 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 sopstage.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			ss.ID = uint64(value.Int64)
+		case sopstage.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 {
+				ss.CreatedAt = value.Time
+			}
+		case sopstage.FieldUpdatedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field updated_at", values[i])
+			} else if value.Valid {
+				ss.UpdatedAt = value.Time
+			}
+		case sopstage.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				ss.Status = uint8(value.Int64)
+			}
+		case sopstage.FieldTaskID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field task_id", values[i])
+			} else if value.Valid {
+				ss.TaskID = uint64(value.Int64)
+			}
+		case sopstage.FieldName:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field name", values[i])
+			} else if value.Valid {
+				ss.Name = value.String
+			}
+		case sopstage.FieldConditionType:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field condition_type", values[i])
+			} else if value.Valid {
+				ss.ConditionType = int(value.Int64)
+			}
+		case sopstage.FieldConditionOperator:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field condition_operator", values[i])
+			} else if value.Valid {
+				ss.ConditionOperator = int(value.Int64)
+			}
+		case sopstage.FieldConditionList:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field condition_list", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &ss.ConditionList); err != nil {
+					return fmt.Errorf("unmarshal field condition_list: %w", err)
+				}
+			}
+		case sopstage.FieldActionMessage:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field action_message", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &ss.ActionMessage); err != nil {
+					return fmt.Errorf("unmarshal field action_message: %w", err)
+				}
+			}
+		case sopstage.FieldActionLabel:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field action_label", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &ss.ActionLabel); err != nil {
+					return fmt.Errorf("unmarshal field action_label: %w", err)
+				}
+			}
+		case sopstage.FieldIndexSort:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field index_sort", values[i])
+			} else if value.Valid {
+				ss.IndexSort = int(value.Int64)
+			}
+		case sopstage.FieldDeletedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field deleted_at", values[i])
+			} else if value.Valid {
+				ss.DeletedAt = value.Time
+			}
+		default:
+			ss.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the SopStage.
+// This includes values selected through modifiers, order, etc.
+func (ss *SopStage) Value(name string) (ent.Value, error) {
+	return ss.selectValues.Get(name)
+}
+
+// QuerySopTask queries the "sop_task" edge of the SopStage entity.
+func (ss *SopStage) QuerySopTask() *SopTaskQuery {
+	return NewSopStageClient(ss.config).QuerySopTask(ss)
+}
+
+// QueryStageNodes queries the "stage_nodes" edge of the SopStage entity.
+func (ss *SopStage) QueryStageNodes() *SopNodeQuery {
+	return NewSopStageClient(ss.config).QueryStageNodes(ss)
+}
+
+// QueryStageMessages queries the "stage_messages" edge of the SopStage entity.
+func (ss *SopStage) QueryStageMessages() *MessageRecordsQuery {
+	return NewSopStageClient(ss.config).QueryStageMessages(ss)
+}
+
+// Update returns a builder for updating this SopStage.
+// Note that you need to call SopStage.Unwrap() before calling this method if this SopStage
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (ss *SopStage) Update() *SopStageUpdateOne {
+	return NewSopStageClient(ss.config).UpdateOne(ss)
+}
+
+// Unwrap unwraps the SopStage 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 (ss *SopStage) Unwrap() *SopStage {
+	_tx, ok := ss.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: SopStage is not a transactional entity")
+	}
+	ss.config.driver = _tx.drv
+	return ss
+}
+
+// String implements the fmt.Stringer.
+func (ss *SopStage) String() string {
+	var builder strings.Builder
+	builder.WriteString("SopStage(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", ss.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(ss.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(ss.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", ss.Status))
+	builder.WriteString(", ")
+	builder.WriteString("task_id=")
+	builder.WriteString(fmt.Sprintf("%v", ss.TaskID))
+	builder.WriteString(", ")
+	builder.WriteString("name=")
+	builder.WriteString(ss.Name)
+	builder.WriteString(", ")
+	builder.WriteString("condition_type=")
+	builder.WriteString(fmt.Sprintf("%v", ss.ConditionType))
+	builder.WriteString(", ")
+	builder.WriteString("condition_operator=")
+	builder.WriteString(fmt.Sprintf("%v", ss.ConditionOperator))
+	builder.WriteString(", ")
+	builder.WriteString("condition_list=")
+	builder.WriteString(fmt.Sprintf("%v", ss.ConditionList))
+	builder.WriteString(", ")
+	builder.WriteString("action_message=")
+	builder.WriteString(fmt.Sprintf("%v", ss.ActionMessage))
+	builder.WriteString(", ")
+	builder.WriteString("action_label=")
+	builder.WriteString(fmt.Sprintf("%v", ss.ActionLabel))
+	builder.WriteString(", ")
+	builder.WriteString("index_sort=")
+	builder.WriteString(fmt.Sprintf("%v", ss.IndexSort))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(ss.DeletedAt.Format(time.ANSIC))
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// SopStages is a parsable slice of SopStage.
+type SopStages []*SopStage

+ 225 - 0
ent/sopstage/sopstage.go

@@ -0,0 +1,225 @@
+// Code generated by ent, DO NOT EDIT.
+
+package sopstage
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the sopstage type in the database.
+	Label = "sop_stage"
+	// FieldID holds the string denoting the id field in the database.
+	FieldID = "id"
+	// FieldCreatedAt holds the string denoting the created_at field in the database.
+	FieldCreatedAt = "created_at"
+	// FieldUpdatedAt holds the string denoting the updated_at field in the database.
+	FieldUpdatedAt = "updated_at"
+	// FieldStatus holds the string denoting the status field in the database.
+	FieldStatus = "status"
+	// FieldTaskID holds the string denoting the task_id field in the database.
+	FieldTaskID = "task_id"
+	// FieldName holds the string denoting the name field in the database.
+	FieldName = "name"
+	// FieldConditionType holds the string denoting the condition_type field in the database.
+	FieldConditionType = "condition_type"
+	// FieldConditionOperator holds the string denoting the condition_operator field in the database.
+	FieldConditionOperator = "condition_operator"
+	// FieldConditionList holds the string denoting the condition_list field in the database.
+	FieldConditionList = "condition_list"
+	// FieldActionMessage holds the string denoting the action_message field in the database.
+	FieldActionMessage = "action_message"
+	// FieldActionLabel holds the string denoting the action_label field in the database.
+	FieldActionLabel = "action_label"
+	// FieldIndexSort holds the string denoting the index_sort field in the database.
+	FieldIndexSort = "index_sort"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// EdgeSopTask holds the string denoting the sop_task edge name in mutations.
+	EdgeSopTask = "sop_task"
+	// EdgeStageNodes holds the string denoting the stage_nodes edge name in mutations.
+	EdgeStageNodes = "stage_nodes"
+	// EdgeStageMessages holds the string denoting the stage_messages edge name in mutations.
+	EdgeStageMessages = "stage_messages"
+	// Table holds the table name of the sopstage in the database.
+	Table = "sop_stage"
+	// SopTaskTable is the table that holds the sop_task relation/edge.
+	SopTaskTable = "sop_stage"
+	// SopTaskInverseTable is the table name for the SopTask entity.
+	// It exists in this package in order to avoid circular dependency with the "soptask" package.
+	SopTaskInverseTable = "sop_task"
+	// SopTaskColumn is the table column denoting the sop_task relation/edge.
+	SopTaskColumn = "task_id"
+	// StageNodesTable is the table that holds the stage_nodes relation/edge.
+	StageNodesTable = "sop_node"
+	// StageNodesInverseTable is the table name for the SopNode entity.
+	// It exists in this package in order to avoid circular dependency with the "sopnode" package.
+	StageNodesInverseTable = "sop_node"
+	// StageNodesColumn is the table column denoting the stage_nodes relation/edge.
+	StageNodesColumn = "stage_id"
+	// StageMessagesTable is the table that holds the stage_messages relation/edge.
+	StageMessagesTable = "message_records"
+	// StageMessagesInverseTable is the table name for the MessageRecords entity.
+	// It exists in this package in order to avoid circular dependency with the "messagerecords" package.
+	StageMessagesInverseTable = "message_records"
+	// StageMessagesColumn is the table column denoting the stage_messages relation/edge.
+	StageMessagesColumn = "sop_stage_stage_messages"
+)
+
+// Columns holds all SQL columns for sopstage fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldTaskID,
+	FieldName,
+	FieldConditionType,
+	FieldConditionOperator,
+	FieldConditionList,
+	FieldActionMessage,
+	FieldActionLabel,
+	FieldIndexSort,
+	FieldDeletedAt,
+}
+
+// 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 (
+	// DefaultCreatedAt holds the default value on creation for the "created_at" field.
+	DefaultCreatedAt func() time.Time
+	// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
+	DefaultUpdatedAt func() time.Time
+	// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
+	UpdateDefaultUpdatedAt func() time.Time
+	// DefaultStatus holds the default value on creation for the "status" field.
+	DefaultStatus uint8
+	// DefaultName holds the default value on creation for the "name" field.
+	DefaultName string
+	// DefaultConditionType holds the default value on creation for the "condition_type" field.
+	DefaultConditionType int
+	// DefaultConditionOperator holds the default value on creation for the "condition_operator" field.
+	DefaultConditionOperator int
+	// DefaultIndexSort holds the default value on creation for the "index_sort" field.
+	DefaultIndexSort int
+)
+
+// OrderOption defines the ordering options for the SopStage queries.
+type OrderOption func(*sql.Selector)
+
+// ByID orders the results by the id field.
+func ByID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldID, opts...).ToFunc()
+}
+
+// ByCreatedAt orders the results by the created_at field.
+func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
+}
+
+// ByUpdatedAt orders the results by the updated_at field.
+func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
+}
+
+// ByStatus orders the results by the status field.
+func ByStatus(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStatus, opts...).ToFunc()
+}
+
+// ByTaskID orders the results by the task_id field.
+func ByTaskID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldTaskID, opts...).ToFunc()
+}
+
+// ByName orders the results by the name field.
+func ByName(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldName, opts...).ToFunc()
+}
+
+// ByConditionType orders the results by the condition_type field.
+func ByConditionType(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldConditionType, opts...).ToFunc()
+}
+
+// ByConditionOperator orders the results by the condition_operator field.
+func ByConditionOperator(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldConditionOperator, opts...).ToFunc()
+}
+
+// ByIndexSort orders the results by the index_sort field.
+func ByIndexSort(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldIndexSort, opts...).ToFunc()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// BySopTaskField orders the results by sop_task field.
+func BySopTaskField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newSopTaskStep(), sql.OrderByField(field, opts...))
+	}
+}
+
+// ByStageNodesCount orders the results by stage_nodes count.
+func ByStageNodesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newStageNodesStep(), opts...)
+	}
+}
+
+// ByStageNodes orders the results by stage_nodes terms.
+func ByStageNodes(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newStageNodesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+
+// ByStageMessagesCount orders the results by stage_messages count.
+func ByStageMessagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newStageMessagesStep(), opts...)
+	}
+}
+
+// ByStageMessages orders the results by stage_messages terms.
+func ByStageMessages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newStageMessagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newSopTaskStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(SopTaskInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, SopTaskTable, SopTaskColumn),
+	)
+}
+func newStageNodesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(StageNodesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, StageNodesTable, StageNodesColumn),
+	)
+}
+func newStageMessagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(StageMessagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, StageMessagesTable, StageMessagesColumn),
+	)
+}

+ 600 - 0
ent/sopstage/where.go

@@ -0,0 +1,600 @@
+// Code generated by ent, DO NOT EDIT.
+
+package sopstage
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldID, id))
+}
+
+// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
+func CreatedAt(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
+func UpdatedAt(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldStatus, v))
+}
+
+// TaskID applies equality check predicate on the "task_id" field. It's identical to TaskIDEQ.
+func TaskID(v uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldTaskID, v))
+}
+
+// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
+func Name(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldName, v))
+}
+
+// ConditionType applies equality check predicate on the "condition_type" field. It's identical to ConditionTypeEQ.
+func ConditionType(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldConditionType, v))
+}
+
+// ConditionOperator applies equality check predicate on the "condition_operator" field. It's identical to ConditionOperatorEQ.
+func ConditionOperator(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldConditionOperator, v))
+}
+
+// IndexSort applies equality check predicate on the "index_sort" field. It's identical to IndexSortEQ.
+func IndexSort(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldIndexSort, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotNull(FieldStatus))
+}
+
+// TaskIDEQ applies the EQ predicate on the "task_id" field.
+func TaskIDEQ(v uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldTaskID, v))
+}
+
+// TaskIDNEQ applies the NEQ predicate on the "task_id" field.
+func TaskIDNEQ(v uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldTaskID, v))
+}
+
+// TaskIDIn applies the In predicate on the "task_id" field.
+func TaskIDIn(vs ...uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldTaskID, vs...))
+}
+
+// TaskIDNotIn applies the NotIn predicate on the "task_id" field.
+func TaskIDNotIn(vs ...uint64) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldTaskID, vs...))
+}
+
+// NameEQ applies the EQ predicate on the "name" field.
+func NameEQ(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldName, v))
+}
+
+// NameNEQ applies the NEQ predicate on the "name" field.
+func NameNEQ(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldName, v))
+}
+
+// NameIn applies the In predicate on the "name" field.
+func NameIn(vs ...string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldName, vs...))
+}
+
+// NameNotIn applies the NotIn predicate on the "name" field.
+func NameNotIn(vs ...string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldName, vs...))
+}
+
+// NameGT applies the GT predicate on the "name" field.
+func NameGT(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldName, v))
+}
+
+// NameGTE applies the GTE predicate on the "name" field.
+func NameGTE(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldName, v))
+}
+
+// NameLT applies the LT predicate on the "name" field.
+func NameLT(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldName, v))
+}
+
+// NameLTE applies the LTE predicate on the "name" field.
+func NameLTE(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldName, v))
+}
+
+// NameContains applies the Contains predicate on the "name" field.
+func NameContains(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldContains(FieldName, v))
+}
+
+// NameHasPrefix applies the HasPrefix predicate on the "name" field.
+func NameHasPrefix(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldHasPrefix(FieldName, v))
+}
+
+// NameHasSuffix applies the HasSuffix predicate on the "name" field.
+func NameHasSuffix(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldHasSuffix(FieldName, v))
+}
+
+// NameEqualFold applies the EqualFold predicate on the "name" field.
+func NameEqualFold(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEqualFold(FieldName, v))
+}
+
+// NameContainsFold applies the ContainsFold predicate on the "name" field.
+func NameContainsFold(v string) predicate.SopStage {
+	return predicate.SopStage(sql.FieldContainsFold(FieldName, v))
+}
+
+// ConditionTypeEQ applies the EQ predicate on the "condition_type" field.
+func ConditionTypeEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldConditionType, v))
+}
+
+// ConditionTypeNEQ applies the NEQ predicate on the "condition_type" field.
+func ConditionTypeNEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldConditionType, v))
+}
+
+// ConditionTypeIn applies the In predicate on the "condition_type" field.
+func ConditionTypeIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldConditionType, vs...))
+}
+
+// ConditionTypeNotIn applies the NotIn predicate on the "condition_type" field.
+func ConditionTypeNotIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldConditionType, vs...))
+}
+
+// ConditionTypeGT applies the GT predicate on the "condition_type" field.
+func ConditionTypeGT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldConditionType, v))
+}
+
+// ConditionTypeGTE applies the GTE predicate on the "condition_type" field.
+func ConditionTypeGTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldConditionType, v))
+}
+
+// ConditionTypeLT applies the LT predicate on the "condition_type" field.
+func ConditionTypeLT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldConditionType, v))
+}
+
+// ConditionTypeLTE applies the LTE predicate on the "condition_type" field.
+func ConditionTypeLTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldConditionType, v))
+}
+
+// ConditionOperatorEQ applies the EQ predicate on the "condition_operator" field.
+func ConditionOperatorEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldConditionOperator, v))
+}
+
+// ConditionOperatorNEQ applies the NEQ predicate on the "condition_operator" field.
+func ConditionOperatorNEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldConditionOperator, v))
+}
+
+// ConditionOperatorIn applies the In predicate on the "condition_operator" field.
+func ConditionOperatorIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldConditionOperator, vs...))
+}
+
+// ConditionOperatorNotIn applies the NotIn predicate on the "condition_operator" field.
+func ConditionOperatorNotIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldConditionOperator, vs...))
+}
+
+// ConditionOperatorGT applies the GT predicate on the "condition_operator" field.
+func ConditionOperatorGT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldConditionOperator, v))
+}
+
+// ConditionOperatorGTE applies the GTE predicate on the "condition_operator" field.
+func ConditionOperatorGTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldConditionOperator, v))
+}
+
+// ConditionOperatorLT applies the LT predicate on the "condition_operator" field.
+func ConditionOperatorLT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldConditionOperator, v))
+}
+
+// ConditionOperatorLTE applies the LTE predicate on the "condition_operator" field.
+func ConditionOperatorLTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldConditionOperator, v))
+}
+
+// ActionMessageIsNil applies the IsNil predicate on the "action_message" field.
+func ActionMessageIsNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldIsNull(FieldActionMessage))
+}
+
+// ActionMessageNotNil applies the NotNil predicate on the "action_message" field.
+func ActionMessageNotNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotNull(FieldActionMessage))
+}
+
+// ActionLabelIsNil applies the IsNil predicate on the "action_label" field.
+func ActionLabelIsNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldIsNull(FieldActionLabel))
+}
+
+// ActionLabelNotNil applies the NotNil predicate on the "action_label" field.
+func ActionLabelNotNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotNull(FieldActionLabel))
+}
+
+// IndexSortEQ applies the EQ predicate on the "index_sort" field.
+func IndexSortEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldIndexSort, v))
+}
+
+// IndexSortNEQ applies the NEQ predicate on the "index_sort" field.
+func IndexSortNEQ(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldIndexSort, v))
+}
+
+// IndexSortIn applies the In predicate on the "index_sort" field.
+func IndexSortIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldIndexSort, vs...))
+}
+
+// IndexSortNotIn applies the NotIn predicate on the "index_sort" field.
+func IndexSortNotIn(vs ...int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldIndexSort, vs...))
+}
+
+// IndexSortGT applies the GT predicate on the "index_sort" field.
+func IndexSortGT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldIndexSort, v))
+}
+
+// IndexSortGTE applies the GTE predicate on the "index_sort" field.
+func IndexSortGTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldIndexSort, v))
+}
+
+// IndexSortLT applies the LT predicate on the "index_sort" field.
+func IndexSortLT(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldIndexSort, v))
+}
+
+// IndexSortLTE applies the LTE predicate on the "index_sort" field.
+func IndexSortLTE(v int) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldIndexSort, v))
+}
+
+// IndexSortIsNil applies the IsNil predicate on the "index_sort" field.
+func IndexSortIsNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldIsNull(FieldIndexSort))
+}
+
+// IndexSortNotNil applies the NotNil predicate on the "index_sort" field.
+func IndexSortNotNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotNull(FieldIndexSort))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.SopStage {
+	return predicate.SopStage(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.SopStage {
+	return predicate.SopStage(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// HasSopTask applies the HasEdge predicate on the "sop_task" edge.
+func HasSopTask() predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, SopTaskTable, SopTaskColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasSopTaskWith applies the HasEdge predicate on the "sop_task" edge with a given conditions (other predicates).
+func HasSopTaskWith(preds ...predicate.SopTask) predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := newSopTaskStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasStageNodes applies the HasEdge predicate on the "stage_nodes" edge.
+func HasStageNodes() predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, StageNodesTable, StageNodesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasStageNodesWith applies the HasEdge predicate on the "stage_nodes" edge with a given conditions (other predicates).
+func HasStageNodesWith(preds ...predicate.SopNode) predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := newStageNodesStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasStageMessages applies the HasEdge predicate on the "stage_messages" edge.
+func HasStageMessages() predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, StageMessagesTable, StageMessagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasStageMessagesWith applies the HasEdge predicate on the "stage_messages" edge with a given conditions (other predicates).
+func HasStageMessagesWith(preds ...predicate.MessageRecords) predicate.SopStage {
+	return predicate.SopStage(func(s *sql.Selector) {
+		step := newStageMessagesStep()
+		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.SopStage) predicate.SopStage {
+	return predicate.SopStage(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.SopStage) predicate.SopStage {
+	return predicate.SopStage(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.SopStage) predicate.SopStage {
+	return predicate.SopStage(sql.NotPredicates(p))
+}

+ 515 - 0
ent/sopstage_create.go

@@ -0,0 +1,515 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopStageCreate is the builder for creating a SopStage entity.
+type SopStageCreate struct {
+	config
+	mutation *SopStageMutation
+	hooks    []Hook
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (ssc *SopStageCreate) SetCreatedAt(t time.Time) *SopStageCreate {
+	ssc.mutation.SetCreatedAt(t)
+	return ssc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableCreatedAt(t *time.Time) *SopStageCreate {
+	if t != nil {
+		ssc.SetCreatedAt(*t)
+	}
+	return ssc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (ssc *SopStageCreate) SetUpdatedAt(t time.Time) *SopStageCreate {
+	ssc.mutation.SetUpdatedAt(t)
+	return ssc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableUpdatedAt(t *time.Time) *SopStageCreate {
+	if t != nil {
+		ssc.SetUpdatedAt(*t)
+	}
+	return ssc
+}
+
+// SetStatus sets the "status" field.
+func (ssc *SopStageCreate) SetStatus(u uint8) *SopStageCreate {
+	ssc.mutation.SetStatus(u)
+	return ssc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableStatus(u *uint8) *SopStageCreate {
+	if u != nil {
+		ssc.SetStatus(*u)
+	}
+	return ssc
+}
+
+// SetTaskID sets the "task_id" field.
+func (ssc *SopStageCreate) SetTaskID(u uint64) *SopStageCreate {
+	ssc.mutation.SetTaskID(u)
+	return ssc
+}
+
+// SetName sets the "name" field.
+func (ssc *SopStageCreate) SetName(s string) *SopStageCreate {
+	ssc.mutation.SetName(s)
+	return ssc
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableName(s *string) *SopStageCreate {
+	if s != nil {
+		ssc.SetName(*s)
+	}
+	return ssc
+}
+
+// SetConditionType sets the "condition_type" field.
+func (ssc *SopStageCreate) SetConditionType(i int) *SopStageCreate {
+	ssc.mutation.SetConditionType(i)
+	return ssc
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableConditionType(i *int) *SopStageCreate {
+	if i != nil {
+		ssc.SetConditionType(*i)
+	}
+	return ssc
+}
+
+// SetConditionOperator sets the "condition_operator" field.
+func (ssc *SopStageCreate) SetConditionOperator(i int) *SopStageCreate {
+	ssc.mutation.SetConditionOperator(i)
+	return ssc
+}
+
+// SetNillableConditionOperator sets the "condition_operator" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableConditionOperator(i *int) *SopStageCreate {
+	if i != nil {
+		ssc.SetConditionOperator(*i)
+	}
+	return ssc
+}
+
+// SetConditionList sets the "condition_list" field.
+func (ssc *SopStageCreate) SetConditionList(ct []custom_types.Condition) *SopStageCreate {
+	ssc.mutation.SetConditionList(ct)
+	return ssc
+}
+
+// SetActionMessage sets the "action_message" field.
+func (ssc *SopStageCreate) SetActionMessage(ct []custom_types.Action) *SopStageCreate {
+	ssc.mutation.SetActionMessage(ct)
+	return ssc
+}
+
+// SetActionLabel sets the "action_label" field.
+func (ssc *SopStageCreate) SetActionLabel(u []uint64) *SopStageCreate {
+	ssc.mutation.SetActionLabel(u)
+	return ssc
+}
+
+// SetIndexSort sets the "index_sort" field.
+func (ssc *SopStageCreate) SetIndexSort(i int) *SopStageCreate {
+	ssc.mutation.SetIndexSort(i)
+	return ssc
+}
+
+// SetNillableIndexSort sets the "index_sort" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableIndexSort(i *int) *SopStageCreate {
+	if i != nil {
+		ssc.SetIndexSort(*i)
+	}
+	return ssc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (ssc *SopStageCreate) SetDeletedAt(t time.Time) *SopStageCreate {
+	ssc.mutation.SetDeletedAt(t)
+	return ssc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (ssc *SopStageCreate) SetNillableDeletedAt(t *time.Time) *SopStageCreate {
+	if t != nil {
+		ssc.SetDeletedAt(*t)
+	}
+	return ssc
+}
+
+// SetID sets the "id" field.
+func (ssc *SopStageCreate) SetID(u uint64) *SopStageCreate {
+	ssc.mutation.SetID(u)
+	return ssc
+}
+
+// SetSopTaskID sets the "sop_task" edge to the SopTask entity by ID.
+func (ssc *SopStageCreate) SetSopTaskID(id uint64) *SopStageCreate {
+	ssc.mutation.SetSopTaskID(id)
+	return ssc
+}
+
+// SetSopTask sets the "sop_task" edge to the SopTask entity.
+func (ssc *SopStageCreate) SetSopTask(s *SopTask) *SopStageCreate {
+	return ssc.SetSopTaskID(s.ID)
+}
+
+// AddStageNodeIDs adds the "stage_nodes" edge to the SopNode entity by IDs.
+func (ssc *SopStageCreate) AddStageNodeIDs(ids ...uint64) *SopStageCreate {
+	ssc.mutation.AddStageNodeIDs(ids...)
+	return ssc
+}
+
+// AddStageNodes adds the "stage_nodes" edges to the SopNode entity.
+func (ssc *SopStageCreate) AddStageNodes(s ...*SopNode) *SopStageCreate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return ssc.AddStageNodeIDs(ids...)
+}
+
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssc *SopStageCreate) AddStageMessageIDs(ids ...uint64) *SopStageCreate {
+	ssc.mutation.AddStageMessageIDs(ids...)
+	return ssc
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssc *SopStageCreate) AddStageMessages(m ...*MessageRecords) *SopStageCreate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssc.AddStageMessageIDs(ids...)
+}
+
+// Mutation returns the SopStageMutation object of the builder.
+func (ssc *SopStageCreate) Mutation() *SopStageMutation {
+	return ssc.mutation
+}
+
+// Save creates the SopStage in the database.
+func (ssc *SopStageCreate) Save(ctx context.Context) (*SopStage, error) {
+	ssc.defaults()
+	return withHooks(ctx, ssc.sqlSave, ssc.mutation, ssc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (ssc *SopStageCreate) SaveX(ctx context.Context) *SopStage {
+	v, err := ssc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (ssc *SopStageCreate) Exec(ctx context.Context) error {
+	_, err := ssc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ssc *SopStageCreate) ExecX(ctx context.Context) {
+	if err := ssc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (ssc *SopStageCreate) defaults() {
+	if _, ok := ssc.mutation.CreatedAt(); !ok {
+		v := sopstage.DefaultCreatedAt()
+		ssc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := ssc.mutation.UpdatedAt(); !ok {
+		v := sopstage.DefaultUpdatedAt()
+		ssc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := ssc.mutation.Status(); !ok {
+		v := sopstage.DefaultStatus
+		ssc.mutation.SetStatus(v)
+	}
+	if _, ok := ssc.mutation.Name(); !ok {
+		v := sopstage.DefaultName
+		ssc.mutation.SetName(v)
+	}
+	if _, ok := ssc.mutation.ConditionType(); !ok {
+		v := sopstage.DefaultConditionType
+		ssc.mutation.SetConditionType(v)
+	}
+	if _, ok := ssc.mutation.ConditionOperator(); !ok {
+		v := sopstage.DefaultConditionOperator
+		ssc.mutation.SetConditionOperator(v)
+	}
+	if _, ok := ssc.mutation.IndexSort(); !ok {
+		v := sopstage.DefaultIndexSort
+		ssc.mutation.SetIndexSort(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (ssc *SopStageCreate) check() error {
+	if _, ok := ssc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "SopStage.created_at"`)}
+	}
+	if _, ok := ssc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "SopStage.updated_at"`)}
+	}
+	if _, ok := ssc.mutation.TaskID(); !ok {
+		return &ValidationError{Name: "task_id", err: errors.New(`ent: missing required field "SopStage.task_id"`)}
+	}
+	if _, ok := ssc.mutation.Name(); !ok {
+		return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "SopStage.name"`)}
+	}
+	if _, ok := ssc.mutation.ConditionType(); !ok {
+		return &ValidationError{Name: "condition_type", err: errors.New(`ent: missing required field "SopStage.condition_type"`)}
+	}
+	if _, ok := ssc.mutation.ConditionOperator(); !ok {
+		return &ValidationError{Name: "condition_operator", err: errors.New(`ent: missing required field "SopStage.condition_operator"`)}
+	}
+	if _, ok := ssc.mutation.ConditionList(); !ok {
+		return &ValidationError{Name: "condition_list", err: errors.New(`ent: missing required field "SopStage.condition_list"`)}
+	}
+	if _, ok := ssc.mutation.SopTaskID(); !ok {
+		return &ValidationError{Name: "sop_task", err: errors.New(`ent: missing required edge "SopStage.sop_task"`)}
+	}
+	return nil
+}
+
+func (ssc *SopStageCreate) sqlSave(ctx context.Context) (*SopStage, error) {
+	if err := ssc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := ssc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, ssc.driver, _spec); err != nil {
+		if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	if _spec.ID.Value != _node.ID {
+		id := _spec.ID.Value.(int64)
+		_node.ID = uint64(id)
+	}
+	ssc.mutation.id = &_node.ID
+	ssc.mutation.done = true
+	return _node, nil
+}
+
+func (ssc *SopStageCreate) createSpec() (*SopStage, *sqlgraph.CreateSpec) {
+	var (
+		_node = &SopStage{config: ssc.config}
+		_spec = sqlgraph.NewCreateSpec(sopstage.Table, sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64))
+	)
+	if id, ok := ssc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := ssc.mutation.CreatedAt(); ok {
+		_spec.SetField(sopstage.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := ssc.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopstage.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := ssc.mutation.Status(); ok {
+		_spec.SetField(sopstage.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := ssc.mutation.Name(); ok {
+		_spec.SetField(sopstage.FieldName, field.TypeString, value)
+		_node.Name = value
+	}
+	if value, ok := ssc.mutation.ConditionType(); ok {
+		_spec.SetField(sopstage.FieldConditionType, field.TypeInt, value)
+		_node.ConditionType = value
+	}
+	if value, ok := ssc.mutation.ConditionOperator(); ok {
+		_spec.SetField(sopstage.FieldConditionOperator, field.TypeInt, value)
+		_node.ConditionOperator = value
+	}
+	if value, ok := ssc.mutation.ConditionList(); ok {
+		_spec.SetField(sopstage.FieldConditionList, field.TypeJSON, value)
+		_node.ConditionList = value
+	}
+	if value, ok := ssc.mutation.ActionMessage(); ok {
+		_spec.SetField(sopstage.FieldActionMessage, field.TypeJSON, value)
+		_node.ActionMessage = value
+	}
+	if value, ok := ssc.mutation.ActionLabel(); ok {
+		_spec.SetField(sopstage.FieldActionLabel, field.TypeJSON, value)
+		_node.ActionLabel = value
+	}
+	if value, ok := ssc.mutation.IndexSort(); ok {
+		_spec.SetField(sopstage.FieldIndexSort, field.TypeInt, value)
+		_node.IndexSort = value
+	}
+	if value, ok := ssc.mutation.DeletedAt(); ok {
+		_spec.SetField(sopstage.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if nodes := ssc.mutation.SopTaskIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopstage.SopTaskTable,
+			Columns: []string{sopstage.SopTaskColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.TaskID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := ssc.mutation.StageNodesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := ssc.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	return _node, _spec
+}
+
+// SopStageCreateBulk is the builder for creating many SopStage entities in bulk.
+type SopStageCreateBulk struct {
+	config
+	err      error
+	builders []*SopStageCreate
+}
+
+// Save creates the SopStage entities in the database.
+func (sscb *SopStageCreateBulk) Save(ctx context.Context) ([]*SopStage, error) {
+	if sscb.err != nil {
+		return nil, sscb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(sscb.builders))
+	nodes := make([]*SopStage, len(sscb.builders))
+	mutators := make([]Mutator, len(sscb.builders))
+	for i := range sscb.builders {
+		func(i int, root context.Context) {
+			builder := sscb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*SopStageMutation)
+				if !ok {
+					return nil, fmt.Errorf("unexpected mutation type %T", m)
+				}
+				if err := builder.check(); err != nil {
+					return nil, err
+				}
+				builder.mutation = mutation
+				var err error
+				nodes[i], specs[i] = builder.createSpec()
+				if i < len(mutators)-1 {
+					_, err = mutators[i+1].Mutate(root, sscb.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, sscb.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 && nodes[i].ID == 0 {
+					id := specs[i].ID.Value.(int64)
+					nodes[i].ID = uint64(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, sscb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (sscb *SopStageCreateBulk) SaveX(ctx context.Context) []*SopStage {
+	v, err := sscb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (sscb *SopStageCreateBulk) Exec(ctx context.Context) error {
+	_, err := sscb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (sscb *SopStageCreateBulk) ExecX(ctx context.Context) {
+	if err := sscb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/sopstage_delete.go

@@ -0,0 +1,88 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+)
+
+// SopStageDelete is the builder for deleting a SopStage entity.
+type SopStageDelete struct {
+	config
+	hooks    []Hook
+	mutation *SopStageMutation
+}
+
+// Where appends a list predicates to the SopStageDelete builder.
+func (ssd *SopStageDelete) Where(ps ...predicate.SopStage) *SopStageDelete {
+	ssd.mutation.Where(ps...)
+	return ssd
+}
+
+// Exec executes the deletion query and returns how many vertices were deleted.
+func (ssd *SopStageDelete) Exec(ctx context.Context) (int, error) {
+	return withHooks(ctx, ssd.sqlExec, ssd.mutation, ssd.hooks)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ssd *SopStageDelete) ExecX(ctx context.Context) int {
+	n, err := ssd.Exec(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func (ssd *SopStageDelete) sqlExec(ctx context.Context) (int, error) {
+	_spec := sqlgraph.NewDeleteSpec(sopstage.Table, sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64))
+	if ps := ssd.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	affected, err := sqlgraph.DeleteNodes(ctx, ssd.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	ssd.mutation.done = true
+	return affected, err
+}
+
+// SopStageDeleteOne is the builder for deleting a single SopStage entity.
+type SopStageDeleteOne struct {
+	ssd *SopStageDelete
+}
+
+// Where appends a list predicates to the SopStageDelete builder.
+func (ssdo *SopStageDeleteOne) Where(ps ...predicate.SopStage) *SopStageDeleteOne {
+	ssdo.ssd.mutation.Where(ps...)
+	return ssdo
+}
+
+// Exec executes the deletion query.
+func (ssdo *SopStageDeleteOne) Exec(ctx context.Context) error {
+	n, err := ssdo.ssd.Exec(ctx)
+	switch {
+	case err != nil:
+		return err
+	case n == 0:
+		return &NotFoundError{sopstage.Label}
+	default:
+		return nil
+	}
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ssdo *SopStageDeleteOne) ExecX(ctx context.Context) {
+	if err := ssdo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 755 - 0
ent/sopstage_query.go

@@ -0,0 +1,755 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"database/sql/driver"
+	"fmt"
+	"math"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopStageQuery is the builder for querying SopStage entities.
+type SopStageQuery struct {
+	config
+	ctx               *QueryContext
+	order             []sopstage.OrderOption
+	inters            []Interceptor
+	predicates        []predicate.SopStage
+	withSopTask       *SopTaskQuery
+	withStageNodes    *SopNodeQuery
+	withStageMessages *MessageRecordsQuery
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the SopStageQuery builder.
+func (ssq *SopStageQuery) Where(ps ...predicate.SopStage) *SopStageQuery {
+	ssq.predicates = append(ssq.predicates, ps...)
+	return ssq
+}
+
+// Limit the number of records to be returned by this query.
+func (ssq *SopStageQuery) Limit(limit int) *SopStageQuery {
+	ssq.ctx.Limit = &limit
+	return ssq
+}
+
+// Offset to start from.
+func (ssq *SopStageQuery) Offset(offset int) *SopStageQuery {
+	ssq.ctx.Offset = &offset
+	return ssq
+}
+
+// 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 (ssq *SopStageQuery) Unique(unique bool) *SopStageQuery {
+	ssq.ctx.Unique = &unique
+	return ssq
+}
+
+// Order specifies how the records should be ordered.
+func (ssq *SopStageQuery) Order(o ...sopstage.OrderOption) *SopStageQuery {
+	ssq.order = append(ssq.order, o...)
+	return ssq
+}
+
+// QuerySopTask chains the current query on the "sop_task" edge.
+func (ssq *SopStageQuery) QuerySopTask() *SopTaskQuery {
+	query := (&SopTaskClient{config: ssq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := ssq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := ssq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, selector),
+			sqlgraph.To(soptask.Table, soptask.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, sopstage.SopTaskTable, sopstage.SopTaskColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(ssq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QueryStageNodes chains the current query on the "stage_nodes" edge.
+func (ssq *SopStageQuery) QueryStageNodes() *SopNodeQuery {
+	query := (&SopNodeClient{config: ssq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := ssq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := ssq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, selector),
+			sqlgraph.To(sopnode.Table, sopnode.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageNodesTable, sopstage.StageNodesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(ssq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QueryStageMessages chains the current query on the "stage_messages" edge.
+func (ssq *SopStageQuery) QueryStageMessages() *MessageRecordsQuery {
+	query := (&MessageRecordsClient{config: ssq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := ssq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := ssq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(sopstage.Table, sopstage.FieldID, selector),
+			sqlgraph.To(messagerecords.Table, messagerecords.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, sopstage.StageMessagesTable, sopstage.StageMessagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(ssq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// First returns the first SopStage entity from the query.
+// Returns a *NotFoundError when no SopStage was found.
+func (ssq *SopStageQuery) First(ctx context.Context) (*SopStage, error) {
+	nodes, err := ssq.Limit(1).All(setContextOp(ctx, ssq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{sopstage.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (ssq *SopStageQuery) FirstX(ctx context.Context) *SopStage {
+	node, err := ssq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first SopStage ID from the query.
+// Returns a *NotFoundError when no SopStage ID was found.
+func (ssq *SopStageQuery) FirstID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = ssq.Limit(1).IDs(setContextOp(ctx, ssq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{sopstage.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (ssq *SopStageQuery) FirstIDX(ctx context.Context) uint64 {
+	id, err := ssq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single SopStage entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one SopStage entity is found.
+// Returns a *NotFoundError when no SopStage entities are found.
+func (ssq *SopStageQuery) Only(ctx context.Context) (*SopStage, error) {
+	nodes, err := ssq.Limit(2).All(setContextOp(ctx, ssq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{sopstage.Label}
+	default:
+		return nil, &NotSingularError{sopstage.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (ssq *SopStageQuery) OnlyX(ctx context.Context) *SopStage {
+	node, err := ssq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only SopStage ID in the query.
+// Returns a *NotSingularError when more than one SopStage ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (ssq *SopStageQuery) OnlyID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = ssq.Limit(2).IDs(setContextOp(ctx, ssq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{sopstage.Label}
+	default:
+		err = &NotSingularError{sopstage.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (ssq *SopStageQuery) OnlyIDX(ctx context.Context) uint64 {
+	id, err := ssq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of SopStages.
+func (ssq *SopStageQuery) All(ctx context.Context) ([]*SopStage, error) {
+	ctx = setContextOp(ctx, ssq.ctx, "All")
+	if err := ssq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*SopStage, *SopStageQuery]()
+	return withInterceptors[[]*SopStage](ctx, ssq, qr, ssq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (ssq *SopStageQuery) AllX(ctx context.Context) []*SopStage {
+	nodes, err := ssq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of SopStage IDs.
+func (ssq *SopStageQuery) IDs(ctx context.Context) (ids []uint64, err error) {
+	if ssq.ctx.Unique == nil && ssq.path != nil {
+		ssq.Unique(true)
+	}
+	ctx = setContextOp(ctx, ssq.ctx, "IDs")
+	if err = ssq.Select(sopstage.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (ssq *SopStageQuery) IDsX(ctx context.Context) []uint64 {
+	ids, err := ssq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (ssq *SopStageQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, ssq.ctx, "Count")
+	if err := ssq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, ssq, querierCount[*SopStageQuery](), ssq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (ssq *SopStageQuery) CountX(ctx context.Context) int {
+	count, err := ssq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (ssq *SopStageQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, ssq.ctx, "Exist")
+	switch _, err := ssq.FirstID(ctx); {
+	case IsNotFound(err):
+		return false, nil
+	case err != nil:
+		return false, fmt.Errorf("ent: check existence: %w", err)
+	default:
+		return true, nil
+	}
+}
+
+// ExistX is like Exist, but panics if an error occurs.
+func (ssq *SopStageQuery) ExistX(ctx context.Context) bool {
+	exist, err := ssq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the SopStageQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (ssq *SopStageQuery) Clone() *SopStageQuery {
+	if ssq == nil {
+		return nil
+	}
+	return &SopStageQuery{
+		config:            ssq.config,
+		ctx:               ssq.ctx.Clone(),
+		order:             append([]sopstage.OrderOption{}, ssq.order...),
+		inters:            append([]Interceptor{}, ssq.inters...),
+		predicates:        append([]predicate.SopStage{}, ssq.predicates...),
+		withSopTask:       ssq.withSopTask.Clone(),
+		withStageNodes:    ssq.withStageNodes.Clone(),
+		withStageMessages: ssq.withStageMessages.Clone(),
+		// clone intermediate query.
+		sql:  ssq.sql.Clone(),
+		path: ssq.path,
+	}
+}
+
+// WithSopTask tells the query-builder to eager-load the nodes that are connected to
+// the "sop_task" edge. The optional arguments are used to configure the query builder of the edge.
+func (ssq *SopStageQuery) WithSopTask(opts ...func(*SopTaskQuery)) *SopStageQuery {
+	query := (&SopTaskClient{config: ssq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	ssq.withSopTask = query
+	return ssq
+}
+
+// WithStageNodes tells the query-builder to eager-load the nodes that are connected to
+// the "stage_nodes" edge. The optional arguments are used to configure the query builder of the edge.
+func (ssq *SopStageQuery) WithStageNodes(opts ...func(*SopNodeQuery)) *SopStageQuery {
+	query := (&SopNodeClient{config: ssq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	ssq.withStageNodes = query
+	return ssq
+}
+
+// WithStageMessages tells the query-builder to eager-load the nodes that are connected to
+// the "stage_messages" edge. The optional arguments are used to configure the query builder of the edge.
+func (ssq *SopStageQuery) WithStageMessages(opts ...func(*MessageRecordsQuery)) *SopStageQuery {
+	query := (&MessageRecordsClient{config: ssq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	ssq.withStageMessages = query
+	return ssq
+}
+
+// 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//		Count int `json:"count,omitempty"`
+//	}
+//
+//	client.SopStage.Query().
+//		GroupBy(sopstage.FieldCreatedAt).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (ssq *SopStageQuery) GroupBy(field string, fields ...string) *SopStageGroupBy {
+	ssq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &SopStageGroupBy{build: ssq}
+	grbuild.flds = &ssq.ctx.Fields
+	grbuild.label = sopstage.Label
+	grbuild.scan = 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//	}
+//
+//	client.SopStage.Query().
+//		Select(sopstage.FieldCreatedAt).
+//		Scan(ctx, &v)
+func (ssq *SopStageQuery) Select(fields ...string) *SopStageSelect {
+	ssq.ctx.Fields = append(ssq.ctx.Fields, fields...)
+	sbuild := &SopStageSelect{SopStageQuery: ssq}
+	sbuild.label = sopstage.Label
+	sbuild.flds, sbuild.scan = &ssq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a SopStageSelect configured with the given aggregations.
+func (ssq *SopStageQuery) Aggregate(fns ...AggregateFunc) *SopStageSelect {
+	return ssq.Select().Aggregate(fns...)
+}
+
+func (ssq *SopStageQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range ssq.inters {
+		if inter == nil {
+			return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
+		}
+		if trv, ok := inter.(Traverser); ok {
+			if err := trv.Traverse(ctx, ssq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range ssq.ctx.Fields {
+		if !sopstage.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if ssq.path != nil {
+		prev, err := ssq.path(ctx)
+		if err != nil {
+			return err
+		}
+		ssq.sql = prev
+	}
+	return nil
+}
+
+func (ssq *SopStageQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*SopStage, error) {
+	var (
+		nodes       = []*SopStage{}
+		_spec       = ssq.querySpec()
+		loadedTypes = [3]bool{
+			ssq.withSopTask != nil,
+			ssq.withStageNodes != nil,
+			ssq.withStageMessages != nil,
+		}
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*SopStage).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &SopStage{config: ssq.config}
+		nodes = append(nodes, node)
+		node.Edges.loadedTypes = loadedTypes
+		return node.assignValues(columns, values)
+	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
+	if err := sqlgraph.QueryNodes(ctx, ssq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	if query := ssq.withSopTask; query != nil {
+		if err := ssq.loadSopTask(ctx, query, nodes, nil,
+			func(n *SopStage, e *SopTask) { n.Edges.SopTask = e }); err != nil {
+			return nil, err
+		}
+	}
+	if query := ssq.withStageNodes; query != nil {
+		if err := ssq.loadStageNodes(ctx, query, nodes,
+			func(n *SopStage) { n.Edges.StageNodes = []*SopNode{} },
+			func(n *SopStage, e *SopNode) { n.Edges.StageNodes = append(n.Edges.StageNodes, e) }); err != nil {
+			return nil, err
+		}
+	}
+	if query := ssq.withStageMessages; query != nil {
+		if err := ssq.loadStageMessages(ctx, query, nodes,
+			func(n *SopStage) { n.Edges.StageMessages = []*MessageRecords{} },
+			func(n *SopStage, e *MessageRecords) { n.Edges.StageMessages = append(n.Edges.StageMessages, e) }); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+func (ssq *SopStageQuery) loadSopTask(ctx context.Context, query *SopTaskQuery, nodes []*SopStage, init func(*SopStage), assign func(*SopStage, *SopTask)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*SopStage)
+	for i := range nodes {
+		fk := nodes[i].TaskID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(soptask.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 "task_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+func (ssq *SopStageQuery) loadStageNodes(ctx context.Context, query *SopNodeQuery, nodes []*SopStage, init func(*SopStage), assign func(*SopStage, *SopNode)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopStage)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	if len(query.ctx.Fields) > 0 {
+		query.ctx.AppendFieldOnce(sopnode.FieldStageID)
+	}
+	query.Where(predicate.SopNode(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(sopstage.StageNodesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.StageID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "stage_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
+func (ssq *SopStageQuery) loadStageMessages(ctx context.Context, query *MessageRecordsQuery, nodes []*SopStage, init func(*SopStage), assign func(*SopStage, *MessageRecords)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopStage)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	query.withFKs = true
+	query.Where(predicate.MessageRecords(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(sopstage.StageMessagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.sop_stage_stage_messages
+		if fk == nil {
+			return fmt.Errorf(`foreign-key "sop_stage_stage_messages" is nil for node %v`, n.ID)
+		}
+		node, ok := nodeids[*fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "sop_stage_stage_messages" returned %v for node %v`, *fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
+
+func (ssq *SopStageQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := ssq.querySpec()
+	_spec.Node.Columns = ssq.ctx.Fields
+	if len(ssq.ctx.Fields) > 0 {
+		_spec.Unique = ssq.ctx.Unique != nil && *ssq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, ssq.driver, _spec)
+}
+
+func (ssq *SopStageQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(sopstage.Table, sopstage.Columns, sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64))
+	_spec.From = ssq.sql
+	if unique := ssq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if ssq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := ssq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, sopstage.FieldID)
+		for i := range fields {
+			if fields[i] != sopstage.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+		if ssq.withSopTask != nil {
+			_spec.Node.AddColumnOnce(sopstage.FieldTaskID)
+		}
+	}
+	if ps := ssq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := ssq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := ssq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := ssq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (ssq *SopStageQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(ssq.driver.Dialect())
+	t1 := builder.Table(sopstage.Table)
+	columns := ssq.ctx.Fields
+	if len(columns) == 0 {
+		columns = sopstage.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if ssq.sql != nil {
+		selector = ssq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if ssq.ctx.Unique != nil && *ssq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range ssq.predicates {
+		p(selector)
+	}
+	for _, p := range ssq.order {
+		p(selector)
+	}
+	if offset := ssq.ctx.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 := ssq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// SopStageGroupBy is the group-by builder for SopStage entities.
+type SopStageGroupBy struct {
+	selector
+	build *SopStageQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (ssgb *SopStageGroupBy) Aggregate(fns ...AggregateFunc) *SopStageGroupBy {
+	ssgb.fns = append(ssgb.fns, fns...)
+	return ssgb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (ssgb *SopStageGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, ssgb.build.ctx, "GroupBy")
+	if err := ssgb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopStageQuery, *SopStageGroupBy](ctx, ssgb.build, ssgb, ssgb.build.inters, v)
+}
+
+func (ssgb *SopStageGroupBy) sqlScan(ctx context.Context, root *SopStageQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(ssgb.fns))
+	for _, fn := range ssgb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*ssgb.flds)+len(ssgb.fns))
+		for _, f := range *ssgb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*ssgb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := ssgb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// SopStageSelect is the builder for selecting fields of SopStage entities.
+type SopStageSelect struct {
+	*SopStageQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (sss *SopStageSelect) Aggregate(fns ...AggregateFunc) *SopStageSelect {
+	sss.fns = append(sss.fns, fns...)
+	return sss
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (sss *SopStageSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, sss.ctx, "Select")
+	if err := sss.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopStageQuery, *SopStageSelect](ctx, sss.SopStageQuery, sss, sss.inters, v)
+}
+
+func (sss *SopStageSelect) sqlScan(ctx context.Context, root *SopStageQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(sss.fns))
+	for _, fn := range sss.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*sss.selector.flds); {
+	case n == 0 && len(aggregation) > 0:
+		selector.Select(aggregation...)
+	case n != 0 && len(aggregation) > 0:
+		selector.AppendSelect(aggregation...)
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := sss.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 1177 - 0
ent/sopstage_update.go

@@ -0,0 +1,1177 @@
+// 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/dialect/sql/sqljson"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopStageUpdate is the builder for updating SopStage entities.
+type SopStageUpdate struct {
+	config
+	hooks    []Hook
+	mutation *SopStageMutation
+}
+
+// Where appends a list predicates to the SopStageUpdate builder.
+func (ssu *SopStageUpdate) Where(ps ...predicate.SopStage) *SopStageUpdate {
+	ssu.mutation.Where(ps...)
+	return ssu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (ssu *SopStageUpdate) SetUpdatedAt(t time.Time) *SopStageUpdate {
+	ssu.mutation.SetUpdatedAt(t)
+	return ssu
+}
+
+// SetStatus sets the "status" field.
+func (ssu *SopStageUpdate) SetStatus(u uint8) *SopStageUpdate {
+	ssu.mutation.ResetStatus()
+	ssu.mutation.SetStatus(u)
+	return ssu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableStatus(u *uint8) *SopStageUpdate {
+	if u != nil {
+		ssu.SetStatus(*u)
+	}
+	return ssu
+}
+
+// AddStatus adds u to the "status" field.
+func (ssu *SopStageUpdate) AddStatus(u int8) *SopStageUpdate {
+	ssu.mutation.AddStatus(u)
+	return ssu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (ssu *SopStageUpdate) ClearStatus() *SopStageUpdate {
+	ssu.mutation.ClearStatus()
+	return ssu
+}
+
+// SetTaskID sets the "task_id" field.
+func (ssu *SopStageUpdate) SetTaskID(u uint64) *SopStageUpdate {
+	ssu.mutation.SetTaskID(u)
+	return ssu
+}
+
+// SetNillableTaskID sets the "task_id" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableTaskID(u *uint64) *SopStageUpdate {
+	if u != nil {
+		ssu.SetTaskID(*u)
+	}
+	return ssu
+}
+
+// SetName sets the "name" field.
+func (ssu *SopStageUpdate) SetName(s string) *SopStageUpdate {
+	ssu.mutation.SetName(s)
+	return ssu
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableName(s *string) *SopStageUpdate {
+	if s != nil {
+		ssu.SetName(*s)
+	}
+	return ssu
+}
+
+// SetConditionType sets the "condition_type" field.
+func (ssu *SopStageUpdate) SetConditionType(i int) *SopStageUpdate {
+	ssu.mutation.ResetConditionType()
+	ssu.mutation.SetConditionType(i)
+	return ssu
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableConditionType(i *int) *SopStageUpdate {
+	if i != nil {
+		ssu.SetConditionType(*i)
+	}
+	return ssu
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (ssu *SopStageUpdate) AddConditionType(i int) *SopStageUpdate {
+	ssu.mutation.AddConditionType(i)
+	return ssu
+}
+
+// SetConditionOperator sets the "condition_operator" field.
+func (ssu *SopStageUpdate) SetConditionOperator(i int) *SopStageUpdate {
+	ssu.mutation.ResetConditionOperator()
+	ssu.mutation.SetConditionOperator(i)
+	return ssu
+}
+
+// SetNillableConditionOperator sets the "condition_operator" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableConditionOperator(i *int) *SopStageUpdate {
+	if i != nil {
+		ssu.SetConditionOperator(*i)
+	}
+	return ssu
+}
+
+// AddConditionOperator adds i to the "condition_operator" field.
+func (ssu *SopStageUpdate) AddConditionOperator(i int) *SopStageUpdate {
+	ssu.mutation.AddConditionOperator(i)
+	return ssu
+}
+
+// SetConditionList sets the "condition_list" field.
+func (ssu *SopStageUpdate) SetConditionList(ct []custom_types.Condition) *SopStageUpdate {
+	ssu.mutation.SetConditionList(ct)
+	return ssu
+}
+
+// AppendConditionList appends ct to the "condition_list" field.
+func (ssu *SopStageUpdate) AppendConditionList(ct []custom_types.Condition) *SopStageUpdate {
+	ssu.mutation.AppendConditionList(ct)
+	return ssu
+}
+
+// SetActionMessage sets the "action_message" field.
+func (ssu *SopStageUpdate) SetActionMessage(ct []custom_types.Action) *SopStageUpdate {
+	ssu.mutation.SetActionMessage(ct)
+	return ssu
+}
+
+// AppendActionMessage appends ct to the "action_message" field.
+func (ssu *SopStageUpdate) AppendActionMessage(ct []custom_types.Action) *SopStageUpdate {
+	ssu.mutation.AppendActionMessage(ct)
+	return ssu
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (ssu *SopStageUpdate) ClearActionMessage() *SopStageUpdate {
+	ssu.mutation.ClearActionMessage()
+	return ssu
+}
+
+// SetActionLabel sets the "action_label" field.
+func (ssu *SopStageUpdate) SetActionLabel(u []uint64) *SopStageUpdate {
+	ssu.mutation.SetActionLabel(u)
+	return ssu
+}
+
+// AppendActionLabel appends u to the "action_label" field.
+func (ssu *SopStageUpdate) AppendActionLabel(u []uint64) *SopStageUpdate {
+	ssu.mutation.AppendActionLabel(u)
+	return ssu
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (ssu *SopStageUpdate) ClearActionLabel() *SopStageUpdate {
+	ssu.mutation.ClearActionLabel()
+	return ssu
+}
+
+// SetIndexSort sets the "index_sort" field.
+func (ssu *SopStageUpdate) SetIndexSort(i int) *SopStageUpdate {
+	ssu.mutation.ResetIndexSort()
+	ssu.mutation.SetIndexSort(i)
+	return ssu
+}
+
+// SetNillableIndexSort sets the "index_sort" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableIndexSort(i *int) *SopStageUpdate {
+	if i != nil {
+		ssu.SetIndexSort(*i)
+	}
+	return ssu
+}
+
+// AddIndexSort adds i to the "index_sort" field.
+func (ssu *SopStageUpdate) AddIndexSort(i int) *SopStageUpdate {
+	ssu.mutation.AddIndexSort(i)
+	return ssu
+}
+
+// ClearIndexSort clears the value of the "index_sort" field.
+func (ssu *SopStageUpdate) ClearIndexSort() *SopStageUpdate {
+	ssu.mutation.ClearIndexSort()
+	return ssu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (ssu *SopStageUpdate) SetDeletedAt(t time.Time) *SopStageUpdate {
+	ssu.mutation.SetDeletedAt(t)
+	return ssu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (ssu *SopStageUpdate) SetNillableDeletedAt(t *time.Time) *SopStageUpdate {
+	if t != nil {
+		ssu.SetDeletedAt(*t)
+	}
+	return ssu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (ssu *SopStageUpdate) ClearDeletedAt() *SopStageUpdate {
+	ssu.mutation.ClearDeletedAt()
+	return ssu
+}
+
+// SetSopTaskID sets the "sop_task" edge to the SopTask entity by ID.
+func (ssu *SopStageUpdate) SetSopTaskID(id uint64) *SopStageUpdate {
+	ssu.mutation.SetSopTaskID(id)
+	return ssu
+}
+
+// SetSopTask sets the "sop_task" edge to the SopTask entity.
+func (ssu *SopStageUpdate) SetSopTask(s *SopTask) *SopStageUpdate {
+	return ssu.SetSopTaskID(s.ID)
+}
+
+// AddStageNodeIDs adds the "stage_nodes" edge to the SopNode entity by IDs.
+func (ssu *SopStageUpdate) AddStageNodeIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.AddStageNodeIDs(ids...)
+	return ssu
+}
+
+// AddStageNodes adds the "stage_nodes" edges to the SopNode entity.
+func (ssu *SopStageUpdate) AddStageNodes(s ...*SopNode) *SopStageUpdate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return ssu.AddStageNodeIDs(ids...)
+}
+
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssu *SopStageUpdate) AddStageMessageIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.AddStageMessageIDs(ids...)
+	return ssu
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssu *SopStageUpdate) AddStageMessages(m ...*MessageRecords) *SopStageUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssu.AddStageMessageIDs(ids...)
+}
+
+// Mutation returns the SopStageMutation object of the builder.
+func (ssu *SopStageUpdate) Mutation() *SopStageMutation {
+	return ssu.mutation
+}
+
+// ClearSopTask clears the "sop_task" edge to the SopTask entity.
+func (ssu *SopStageUpdate) ClearSopTask() *SopStageUpdate {
+	ssu.mutation.ClearSopTask()
+	return ssu
+}
+
+// ClearStageNodes clears all "stage_nodes" edges to the SopNode entity.
+func (ssu *SopStageUpdate) ClearStageNodes() *SopStageUpdate {
+	ssu.mutation.ClearStageNodes()
+	return ssu
+}
+
+// RemoveStageNodeIDs removes the "stage_nodes" edge to SopNode entities by IDs.
+func (ssu *SopStageUpdate) RemoveStageNodeIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.RemoveStageNodeIDs(ids...)
+	return ssu
+}
+
+// RemoveStageNodes removes "stage_nodes" edges to SopNode entities.
+func (ssu *SopStageUpdate) RemoveStageNodes(s ...*SopNode) *SopStageUpdate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return ssu.RemoveStageNodeIDs(ids...)
+}
+
+// ClearStageMessages clears all "stage_messages" edges to the MessageRecords entity.
+func (ssu *SopStageUpdate) ClearStageMessages() *SopStageUpdate {
+	ssu.mutation.ClearStageMessages()
+	return ssu
+}
+
+// RemoveStageMessageIDs removes the "stage_messages" edge to MessageRecords entities by IDs.
+func (ssu *SopStageUpdate) RemoveStageMessageIDs(ids ...uint64) *SopStageUpdate {
+	ssu.mutation.RemoveStageMessageIDs(ids...)
+	return ssu
+}
+
+// RemoveStageMessages removes "stage_messages" edges to MessageRecords entities.
+func (ssu *SopStageUpdate) RemoveStageMessages(m ...*MessageRecords) *SopStageUpdate {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssu.RemoveStageMessageIDs(ids...)
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (ssu *SopStageUpdate) Save(ctx context.Context) (int, error) {
+	ssu.defaults()
+	return withHooks(ctx, ssu.sqlSave, ssu.mutation, ssu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (ssu *SopStageUpdate) SaveX(ctx context.Context) int {
+	affected, err := ssu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (ssu *SopStageUpdate) Exec(ctx context.Context) error {
+	_, err := ssu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ssu *SopStageUpdate) ExecX(ctx context.Context) {
+	if err := ssu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (ssu *SopStageUpdate) defaults() {
+	if _, ok := ssu.mutation.UpdatedAt(); !ok {
+		v := sopstage.UpdateDefaultUpdatedAt()
+		ssu.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (ssu *SopStageUpdate) check() error {
+	if _, ok := ssu.mutation.SopTaskID(); ssu.mutation.SopTaskCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "SopStage.sop_task"`)
+	}
+	return nil
+}
+
+func (ssu *SopStageUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	if err := ssu.check(); err != nil {
+		return n, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(sopstage.Table, sopstage.Columns, sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64))
+	if ps := ssu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := ssu.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopstage.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := ssu.mutation.Status(); ok {
+		_spec.SetField(sopstage.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := ssu.mutation.AddedStatus(); ok {
+		_spec.AddField(sopstage.FieldStatus, field.TypeUint8, value)
+	}
+	if ssu.mutation.StatusCleared() {
+		_spec.ClearField(sopstage.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := ssu.mutation.Name(); ok {
+		_spec.SetField(sopstage.FieldName, field.TypeString, value)
+	}
+	if value, ok := ssu.mutation.ConditionType(); ok {
+		_spec.SetField(sopstage.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := ssu.mutation.AddedConditionType(); ok {
+		_spec.AddField(sopstage.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := ssu.mutation.ConditionOperator(); ok {
+		_spec.SetField(sopstage.FieldConditionOperator, field.TypeInt, value)
+	}
+	if value, ok := ssu.mutation.AddedConditionOperator(); ok {
+		_spec.AddField(sopstage.FieldConditionOperator, field.TypeInt, value)
+	}
+	if value, ok := ssu.mutation.ConditionList(); ok {
+		_spec.SetField(sopstage.FieldConditionList, field.TypeJSON, value)
+	}
+	if value, ok := ssu.mutation.AppendedConditionList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldConditionList, value)
+		})
+	}
+	if value, ok := ssu.mutation.ActionMessage(); ok {
+		_spec.SetField(sopstage.FieldActionMessage, field.TypeJSON, value)
+	}
+	if value, ok := ssu.mutation.AppendedActionMessage(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldActionMessage, value)
+		})
+	}
+	if ssu.mutation.ActionMessageCleared() {
+		_spec.ClearField(sopstage.FieldActionMessage, field.TypeJSON)
+	}
+	if value, ok := ssu.mutation.ActionLabel(); ok {
+		_spec.SetField(sopstage.FieldActionLabel, field.TypeJSON, value)
+	}
+	if value, ok := ssu.mutation.AppendedActionLabel(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldActionLabel, value)
+		})
+	}
+	if ssu.mutation.ActionLabelCleared() {
+		_spec.ClearField(sopstage.FieldActionLabel, field.TypeJSON)
+	}
+	if value, ok := ssu.mutation.IndexSort(); ok {
+		_spec.SetField(sopstage.FieldIndexSort, field.TypeInt, value)
+	}
+	if value, ok := ssu.mutation.AddedIndexSort(); ok {
+		_spec.AddField(sopstage.FieldIndexSort, field.TypeInt, value)
+	}
+	if ssu.mutation.IndexSortCleared() {
+		_spec.ClearField(sopstage.FieldIndexSort, field.TypeInt)
+	}
+	if value, ok := ssu.mutation.DeletedAt(); ok {
+		_spec.SetField(sopstage.FieldDeletedAt, field.TypeTime, value)
+	}
+	if ssu.mutation.DeletedAtCleared() {
+		_spec.ClearField(sopstage.FieldDeletedAt, field.TypeTime)
+	}
+	if ssu.mutation.SopTaskCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopstage.SopTaskTable,
+			Columns: []string{sopstage.SopTaskColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.SopTaskIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopstage.SopTaskTable,
+			Columns: []string{sopstage.SopTaskColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if ssu.mutation.StageNodesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.RemovedStageNodesIDs(); len(nodes) > 0 && !ssu.mutation.StageNodesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.StageNodesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if ssu.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.RemovedStageMessagesIDs(); len(nodes) > 0 && !ssu.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssu.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, ssu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{sopstage.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	ssu.mutation.done = true
+	return n, nil
+}
+
+// SopStageUpdateOne is the builder for updating a single SopStage entity.
+type SopStageUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *SopStageMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (ssuo *SopStageUpdateOne) SetUpdatedAt(t time.Time) *SopStageUpdateOne {
+	ssuo.mutation.SetUpdatedAt(t)
+	return ssuo
+}
+
+// SetStatus sets the "status" field.
+func (ssuo *SopStageUpdateOne) SetStatus(u uint8) *SopStageUpdateOne {
+	ssuo.mutation.ResetStatus()
+	ssuo.mutation.SetStatus(u)
+	return ssuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableStatus(u *uint8) *SopStageUpdateOne {
+	if u != nil {
+		ssuo.SetStatus(*u)
+	}
+	return ssuo
+}
+
+// AddStatus adds u to the "status" field.
+func (ssuo *SopStageUpdateOne) AddStatus(u int8) *SopStageUpdateOne {
+	ssuo.mutation.AddStatus(u)
+	return ssuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (ssuo *SopStageUpdateOne) ClearStatus() *SopStageUpdateOne {
+	ssuo.mutation.ClearStatus()
+	return ssuo
+}
+
+// SetTaskID sets the "task_id" field.
+func (ssuo *SopStageUpdateOne) SetTaskID(u uint64) *SopStageUpdateOne {
+	ssuo.mutation.SetTaskID(u)
+	return ssuo
+}
+
+// SetNillableTaskID sets the "task_id" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableTaskID(u *uint64) *SopStageUpdateOne {
+	if u != nil {
+		ssuo.SetTaskID(*u)
+	}
+	return ssuo
+}
+
+// SetName sets the "name" field.
+func (ssuo *SopStageUpdateOne) SetName(s string) *SopStageUpdateOne {
+	ssuo.mutation.SetName(s)
+	return ssuo
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableName(s *string) *SopStageUpdateOne {
+	if s != nil {
+		ssuo.SetName(*s)
+	}
+	return ssuo
+}
+
+// SetConditionType sets the "condition_type" field.
+func (ssuo *SopStageUpdateOne) SetConditionType(i int) *SopStageUpdateOne {
+	ssuo.mutation.ResetConditionType()
+	ssuo.mutation.SetConditionType(i)
+	return ssuo
+}
+
+// SetNillableConditionType sets the "condition_type" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableConditionType(i *int) *SopStageUpdateOne {
+	if i != nil {
+		ssuo.SetConditionType(*i)
+	}
+	return ssuo
+}
+
+// AddConditionType adds i to the "condition_type" field.
+func (ssuo *SopStageUpdateOne) AddConditionType(i int) *SopStageUpdateOne {
+	ssuo.mutation.AddConditionType(i)
+	return ssuo
+}
+
+// SetConditionOperator sets the "condition_operator" field.
+func (ssuo *SopStageUpdateOne) SetConditionOperator(i int) *SopStageUpdateOne {
+	ssuo.mutation.ResetConditionOperator()
+	ssuo.mutation.SetConditionOperator(i)
+	return ssuo
+}
+
+// SetNillableConditionOperator sets the "condition_operator" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableConditionOperator(i *int) *SopStageUpdateOne {
+	if i != nil {
+		ssuo.SetConditionOperator(*i)
+	}
+	return ssuo
+}
+
+// AddConditionOperator adds i to the "condition_operator" field.
+func (ssuo *SopStageUpdateOne) AddConditionOperator(i int) *SopStageUpdateOne {
+	ssuo.mutation.AddConditionOperator(i)
+	return ssuo
+}
+
+// SetConditionList sets the "condition_list" field.
+func (ssuo *SopStageUpdateOne) SetConditionList(ct []custom_types.Condition) *SopStageUpdateOne {
+	ssuo.mutation.SetConditionList(ct)
+	return ssuo
+}
+
+// AppendConditionList appends ct to the "condition_list" field.
+func (ssuo *SopStageUpdateOne) AppendConditionList(ct []custom_types.Condition) *SopStageUpdateOne {
+	ssuo.mutation.AppendConditionList(ct)
+	return ssuo
+}
+
+// SetActionMessage sets the "action_message" field.
+func (ssuo *SopStageUpdateOne) SetActionMessage(ct []custom_types.Action) *SopStageUpdateOne {
+	ssuo.mutation.SetActionMessage(ct)
+	return ssuo
+}
+
+// AppendActionMessage appends ct to the "action_message" field.
+func (ssuo *SopStageUpdateOne) AppendActionMessage(ct []custom_types.Action) *SopStageUpdateOne {
+	ssuo.mutation.AppendActionMessage(ct)
+	return ssuo
+}
+
+// ClearActionMessage clears the value of the "action_message" field.
+func (ssuo *SopStageUpdateOne) ClearActionMessage() *SopStageUpdateOne {
+	ssuo.mutation.ClearActionMessage()
+	return ssuo
+}
+
+// SetActionLabel sets the "action_label" field.
+func (ssuo *SopStageUpdateOne) SetActionLabel(u []uint64) *SopStageUpdateOne {
+	ssuo.mutation.SetActionLabel(u)
+	return ssuo
+}
+
+// AppendActionLabel appends u to the "action_label" field.
+func (ssuo *SopStageUpdateOne) AppendActionLabel(u []uint64) *SopStageUpdateOne {
+	ssuo.mutation.AppendActionLabel(u)
+	return ssuo
+}
+
+// ClearActionLabel clears the value of the "action_label" field.
+func (ssuo *SopStageUpdateOne) ClearActionLabel() *SopStageUpdateOne {
+	ssuo.mutation.ClearActionLabel()
+	return ssuo
+}
+
+// SetIndexSort sets the "index_sort" field.
+func (ssuo *SopStageUpdateOne) SetIndexSort(i int) *SopStageUpdateOne {
+	ssuo.mutation.ResetIndexSort()
+	ssuo.mutation.SetIndexSort(i)
+	return ssuo
+}
+
+// SetNillableIndexSort sets the "index_sort" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableIndexSort(i *int) *SopStageUpdateOne {
+	if i != nil {
+		ssuo.SetIndexSort(*i)
+	}
+	return ssuo
+}
+
+// AddIndexSort adds i to the "index_sort" field.
+func (ssuo *SopStageUpdateOne) AddIndexSort(i int) *SopStageUpdateOne {
+	ssuo.mutation.AddIndexSort(i)
+	return ssuo
+}
+
+// ClearIndexSort clears the value of the "index_sort" field.
+func (ssuo *SopStageUpdateOne) ClearIndexSort() *SopStageUpdateOne {
+	ssuo.mutation.ClearIndexSort()
+	return ssuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (ssuo *SopStageUpdateOne) SetDeletedAt(t time.Time) *SopStageUpdateOne {
+	ssuo.mutation.SetDeletedAt(t)
+	return ssuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (ssuo *SopStageUpdateOne) SetNillableDeletedAt(t *time.Time) *SopStageUpdateOne {
+	if t != nil {
+		ssuo.SetDeletedAt(*t)
+	}
+	return ssuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (ssuo *SopStageUpdateOne) ClearDeletedAt() *SopStageUpdateOne {
+	ssuo.mutation.ClearDeletedAt()
+	return ssuo
+}
+
+// SetSopTaskID sets the "sop_task" edge to the SopTask entity by ID.
+func (ssuo *SopStageUpdateOne) SetSopTaskID(id uint64) *SopStageUpdateOne {
+	ssuo.mutation.SetSopTaskID(id)
+	return ssuo
+}
+
+// SetSopTask sets the "sop_task" edge to the SopTask entity.
+func (ssuo *SopStageUpdateOne) SetSopTask(s *SopTask) *SopStageUpdateOne {
+	return ssuo.SetSopTaskID(s.ID)
+}
+
+// AddStageNodeIDs adds the "stage_nodes" edge to the SopNode entity by IDs.
+func (ssuo *SopStageUpdateOne) AddStageNodeIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.AddStageNodeIDs(ids...)
+	return ssuo
+}
+
+// AddStageNodes adds the "stage_nodes" edges to the SopNode entity.
+func (ssuo *SopStageUpdateOne) AddStageNodes(s ...*SopNode) *SopStageUpdateOne {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return ssuo.AddStageNodeIDs(ids...)
+}
+
+// AddStageMessageIDs adds the "stage_messages" edge to the MessageRecords entity by IDs.
+func (ssuo *SopStageUpdateOne) AddStageMessageIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.AddStageMessageIDs(ids...)
+	return ssuo
+}
+
+// AddStageMessages adds the "stage_messages" edges to the MessageRecords entity.
+func (ssuo *SopStageUpdateOne) AddStageMessages(m ...*MessageRecords) *SopStageUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssuo.AddStageMessageIDs(ids...)
+}
+
+// Mutation returns the SopStageMutation object of the builder.
+func (ssuo *SopStageUpdateOne) Mutation() *SopStageMutation {
+	return ssuo.mutation
+}
+
+// ClearSopTask clears the "sop_task" edge to the SopTask entity.
+func (ssuo *SopStageUpdateOne) ClearSopTask() *SopStageUpdateOne {
+	ssuo.mutation.ClearSopTask()
+	return ssuo
+}
+
+// ClearStageNodes clears all "stage_nodes" edges to the SopNode entity.
+func (ssuo *SopStageUpdateOne) ClearStageNodes() *SopStageUpdateOne {
+	ssuo.mutation.ClearStageNodes()
+	return ssuo
+}
+
+// RemoveStageNodeIDs removes the "stage_nodes" edge to SopNode entities by IDs.
+func (ssuo *SopStageUpdateOne) RemoveStageNodeIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.RemoveStageNodeIDs(ids...)
+	return ssuo
+}
+
+// RemoveStageNodes removes "stage_nodes" edges to SopNode entities.
+func (ssuo *SopStageUpdateOne) RemoveStageNodes(s ...*SopNode) *SopStageUpdateOne {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return ssuo.RemoveStageNodeIDs(ids...)
+}
+
+// ClearStageMessages clears all "stage_messages" edges to the MessageRecords entity.
+func (ssuo *SopStageUpdateOne) ClearStageMessages() *SopStageUpdateOne {
+	ssuo.mutation.ClearStageMessages()
+	return ssuo
+}
+
+// RemoveStageMessageIDs removes the "stage_messages" edge to MessageRecords entities by IDs.
+func (ssuo *SopStageUpdateOne) RemoveStageMessageIDs(ids ...uint64) *SopStageUpdateOne {
+	ssuo.mutation.RemoveStageMessageIDs(ids...)
+	return ssuo
+}
+
+// RemoveStageMessages removes "stage_messages" edges to MessageRecords entities.
+func (ssuo *SopStageUpdateOne) RemoveStageMessages(m ...*MessageRecords) *SopStageUpdateOne {
+	ids := make([]uint64, len(m))
+	for i := range m {
+		ids[i] = m[i].ID
+	}
+	return ssuo.RemoveStageMessageIDs(ids...)
+}
+
+// Where appends a list predicates to the SopStageUpdate builder.
+func (ssuo *SopStageUpdateOne) Where(ps ...predicate.SopStage) *SopStageUpdateOne {
+	ssuo.mutation.Where(ps...)
+	return ssuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (ssuo *SopStageUpdateOne) Select(field string, fields ...string) *SopStageUpdateOne {
+	ssuo.fields = append([]string{field}, fields...)
+	return ssuo
+}
+
+// Save executes the query and returns the updated SopStage entity.
+func (ssuo *SopStageUpdateOne) Save(ctx context.Context) (*SopStage, error) {
+	ssuo.defaults()
+	return withHooks(ctx, ssuo.sqlSave, ssuo.mutation, ssuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (ssuo *SopStageUpdateOne) SaveX(ctx context.Context) *SopStage {
+	node, err := ssuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (ssuo *SopStageUpdateOne) Exec(ctx context.Context) error {
+	_, err := ssuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ssuo *SopStageUpdateOne) ExecX(ctx context.Context) {
+	if err := ssuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (ssuo *SopStageUpdateOne) defaults() {
+	if _, ok := ssuo.mutation.UpdatedAt(); !ok {
+		v := sopstage.UpdateDefaultUpdatedAt()
+		ssuo.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (ssuo *SopStageUpdateOne) check() error {
+	if _, ok := ssuo.mutation.SopTaskID(); ssuo.mutation.SopTaskCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "SopStage.sop_task"`)
+	}
+	return nil
+}
+
+func (ssuo *SopStageUpdateOne) sqlSave(ctx context.Context) (_node *SopStage, err error) {
+	if err := ssuo.check(); err != nil {
+		return _node, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(sopstage.Table, sopstage.Columns, sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64))
+	id, ok := ssuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "SopStage.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := ssuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, sopstage.FieldID)
+		for _, f := range fields {
+			if !sopstage.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != sopstage.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := ssuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := ssuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(sopstage.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := ssuo.mutation.Status(); ok {
+		_spec.SetField(sopstage.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := ssuo.mutation.AddedStatus(); ok {
+		_spec.AddField(sopstage.FieldStatus, field.TypeUint8, value)
+	}
+	if ssuo.mutation.StatusCleared() {
+		_spec.ClearField(sopstage.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := ssuo.mutation.Name(); ok {
+		_spec.SetField(sopstage.FieldName, field.TypeString, value)
+	}
+	if value, ok := ssuo.mutation.ConditionType(); ok {
+		_spec.SetField(sopstage.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := ssuo.mutation.AddedConditionType(); ok {
+		_spec.AddField(sopstage.FieldConditionType, field.TypeInt, value)
+	}
+	if value, ok := ssuo.mutation.ConditionOperator(); ok {
+		_spec.SetField(sopstage.FieldConditionOperator, field.TypeInt, value)
+	}
+	if value, ok := ssuo.mutation.AddedConditionOperator(); ok {
+		_spec.AddField(sopstage.FieldConditionOperator, field.TypeInt, value)
+	}
+	if value, ok := ssuo.mutation.ConditionList(); ok {
+		_spec.SetField(sopstage.FieldConditionList, field.TypeJSON, value)
+	}
+	if value, ok := ssuo.mutation.AppendedConditionList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldConditionList, value)
+		})
+	}
+	if value, ok := ssuo.mutation.ActionMessage(); ok {
+		_spec.SetField(sopstage.FieldActionMessage, field.TypeJSON, value)
+	}
+	if value, ok := ssuo.mutation.AppendedActionMessage(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldActionMessage, value)
+		})
+	}
+	if ssuo.mutation.ActionMessageCleared() {
+		_spec.ClearField(sopstage.FieldActionMessage, field.TypeJSON)
+	}
+	if value, ok := ssuo.mutation.ActionLabel(); ok {
+		_spec.SetField(sopstage.FieldActionLabel, field.TypeJSON, value)
+	}
+	if value, ok := ssuo.mutation.AppendedActionLabel(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, sopstage.FieldActionLabel, value)
+		})
+	}
+	if ssuo.mutation.ActionLabelCleared() {
+		_spec.ClearField(sopstage.FieldActionLabel, field.TypeJSON)
+	}
+	if value, ok := ssuo.mutation.IndexSort(); ok {
+		_spec.SetField(sopstage.FieldIndexSort, field.TypeInt, value)
+	}
+	if value, ok := ssuo.mutation.AddedIndexSort(); ok {
+		_spec.AddField(sopstage.FieldIndexSort, field.TypeInt, value)
+	}
+	if ssuo.mutation.IndexSortCleared() {
+		_spec.ClearField(sopstage.FieldIndexSort, field.TypeInt)
+	}
+	if value, ok := ssuo.mutation.DeletedAt(); ok {
+		_spec.SetField(sopstage.FieldDeletedAt, field.TypeTime, value)
+	}
+	if ssuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(sopstage.FieldDeletedAt, field.TypeTime)
+	}
+	if ssuo.mutation.SopTaskCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopstage.SopTaskTable,
+			Columns: []string{sopstage.SopTaskColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.SopTaskIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   sopstage.SopTaskTable,
+			Columns: []string{sopstage.SopTaskColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if ssuo.mutation.StageNodesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.RemovedStageNodesIDs(); len(nodes) > 0 && !ssuo.mutation.StageNodesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.StageNodesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageNodesTable,
+			Columns: []string{sopstage.StageNodesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopnode.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if ssuo.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.RemovedStageMessagesIDs(); len(nodes) > 0 && !ssuo.mutation.StageMessagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := ssuo.mutation.StageMessagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   sopstage.StageMessagesTable,
+			Columns: []string{sopstage.StageMessagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(messagerecords.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &SopStage{config: ssuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, ssuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{sopstage.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	ssuo.mutation.done = true
+	return _node, nil
+}

+ 236 - 0
ent/soptask.go

@@ -0,0 +1,236 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopTask is the model entity for the SopTask schema.
+type SopTask struct {
+	config `json:"-"`
+	// ID of the ent.
+	ID uint64 `json:"id,omitempty"`
+	// Create Time | 创建日期
+	CreatedAt time.Time `json:"created_at,omitempty"`
+	// Update Time | 修改日期
+	UpdatedAt time.Time `json:"updated_at,omitempty"`
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status uint8 `json:"status,omitempty"`
+	// SOP 任务名称
+	Name string `json:"name,omitempty"`
+	// 机器人微信 id 列表
+	BotWxidList []string `json:"bot_wxid_list,omitempty"`
+	// 标签类型:1好友,2群组,3企业微信联系人
+	Type int `json:"type,omitempty"`
+	// 任务计划开始时间
+	PlanStartTime time.Time `json:"plan_start_time,omitempty"`
+	// 任务计划结束时间
+	PlanEndTime time.Time `json:"plan_end_time,omitempty"`
+	// 创建者 id
+	CreatorID string `json:"creator_id,omitempty"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the SopTaskQuery when eager-loading is set.
+	Edges        SopTaskEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// SopTaskEdges holds the relations/edges for other nodes in the graph.
+type SopTaskEdges struct {
+	// TaskStages holds the value of the task_stages edge.
+	TaskStages []*SopStage `json:"task_stages,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [1]bool
+}
+
+// TaskStagesOrErr returns the TaskStages value or an error if the edge
+// was not loaded in eager-loading.
+func (e SopTaskEdges) TaskStagesOrErr() ([]*SopStage, error) {
+	if e.loadedTypes[0] {
+		return e.TaskStages, nil
+	}
+	return nil, &NotLoadedError{edge: "task_stages"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*SopTask) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case soptask.FieldBotWxidList:
+			values[i] = new([]byte)
+		case soptask.FieldID, soptask.FieldStatus, soptask.FieldType:
+			values[i] = new(sql.NullInt64)
+		case soptask.FieldName, soptask.FieldCreatorID:
+			values[i] = new(sql.NullString)
+		case soptask.FieldCreatedAt, soptask.FieldUpdatedAt, soptask.FieldPlanStartTime, soptask.FieldPlanEndTime, soptask.FieldDeletedAt:
+			values[i] = new(sql.NullTime)
+		default:
+			values[i] = new(sql.UnknownType)
+		}
+	}
+	return values, nil
+}
+
+// assignValues assigns the values that were returned from sql.Rows (after scanning)
+// to the SopTask fields.
+func (st *SopTask) 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 soptask.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			st.ID = uint64(value.Int64)
+		case soptask.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 {
+				st.CreatedAt = value.Time
+			}
+		case soptask.FieldUpdatedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field updated_at", values[i])
+			} else if value.Valid {
+				st.UpdatedAt = value.Time
+			}
+		case soptask.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				st.Status = uint8(value.Int64)
+			}
+		case soptask.FieldName:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field name", values[i])
+			} else if value.Valid {
+				st.Name = value.String
+			}
+		case soptask.FieldBotWxidList:
+			if value, ok := values[i].(*[]byte); !ok {
+				return fmt.Errorf("unexpected type %T for field bot_wxid_list", values[i])
+			} else if value != nil && len(*value) > 0 {
+				if err := json.Unmarshal(*value, &st.BotWxidList); err != nil {
+					return fmt.Errorf("unmarshal field bot_wxid_list: %w", err)
+				}
+			}
+		case soptask.FieldType:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field type", values[i])
+			} else if value.Valid {
+				st.Type = int(value.Int64)
+			}
+		case soptask.FieldPlanStartTime:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field plan_start_time", values[i])
+			} else if value.Valid {
+				st.PlanStartTime = value.Time
+			}
+		case soptask.FieldPlanEndTime:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field plan_end_time", values[i])
+			} else if value.Valid {
+				st.PlanEndTime = value.Time
+			}
+		case soptask.FieldCreatorID:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field creator_id", values[i])
+			} else if value.Valid {
+				st.CreatorID = value.String
+			}
+		case soptask.FieldDeletedAt:
+			if value, ok := values[i].(*sql.NullTime); !ok {
+				return fmt.Errorf("unexpected type %T for field deleted_at", values[i])
+			} else if value.Valid {
+				st.DeletedAt = value.Time
+			}
+		default:
+			st.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the SopTask.
+// This includes values selected through modifiers, order, etc.
+func (st *SopTask) Value(name string) (ent.Value, error) {
+	return st.selectValues.Get(name)
+}
+
+// QueryTaskStages queries the "task_stages" edge of the SopTask entity.
+func (st *SopTask) QueryTaskStages() *SopStageQuery {
+	return NewSopTaskClient(st.config).QueryTaskStages(st)
+}
+
+// Update returns a builder for updating this SopTask.
+// Note that you need to call SopTask.Unwrap() before calling this method if this SopTask
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (st *SopTask) Update() *SopTaskUpdateOne {
+	return NewSopTaskClient(st.config).UpdateOne(st)
+}
+
+// Unwrap unwraps the SopTask 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 (st *SopTask) Unwrap() *SopTask {
+	_tx, ok := st.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: SopTask is not a transactional entity")
+	}
+	st.config.driver = _tx.drv
+	return st
+}
+
+// String implements the fmt.Stringer.
+func (st *SopTask) String() string {
+	var builder strings.Builder
+	builder.WriteString("SopTask(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", st.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(st.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(st.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", st.Status))
+	builder.WriteString(", ")
+	builder.WriteString("name=")
+	builder.WriteString(st.Name)
+	builder.WriteString(", ")
+	builder.WriteString("bot_wxid_list=")
+	builder.WriteString(fmt.Sprintf("%v", st.BotWxidList))
+	builder.WriteString(", ")
+	builder.WriteString("type=")
+	builder.WriteString(fmt.Sprintf("%v", st.Type))
+	builder.WriteString(", ")
+	builder.WriteString("plan_start_time=")
+	builder.WriteString(st.PlanStartTime.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("plan_end_time=")
+	builder.WriteString(st.PlanEndTime.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("creator_id=")
+	builder.WriteString(st.CreatorID)
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(st.DeletedAt.Format(time.ANSIC))
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// SopTasks is a parsable slice of SopTask.
+type SopTasks []*SopTask

+ 162 - 0
ent/soptask/soptask.go

@@ -0,0 +1,162 @@
+// Code generated by ent, DO NOT EDIT.
+
+package soptask
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the soptask type in the database.
+	Label = "sop_task"
+	// FieldID holds the string denoting the id field in the database.
+	FieldID = "id"
+	// FieldCreatedAt holds the string denoting the created_at field in the database.
+	FieldCreatedAt = "created_at"
+	// FieldUpdatedAt holds the string denoting the updated_at field in the database.
+	FieldUpdatedAt = "updated_at"
+	// FieldStatus holds the string denoting the status field in the database.
+	FieldStatus = "status"
+	// FieldName holds the string denoting the name field in the database.
+	FieldName = "name"
+	// FieldBotWxidList holds the string denoting the bot_wxid_list field in the database.
+	FieldBotWxidList = "bot_wxid_list"
+	// FieldType holds the string denoting the type field in the database.
+	FieldType = "type"
+	// FieldPlanStartTime holds the string denoting the plan_start_time field in the database.
+	FieldPlanStartTime = "plan_start_time"
+	// FieldPlanEndTime holds the string denoting the plan_end_time field in the database.
+	FieldPlanEndTime = "plan_end_time"
+	// FieldCreatorID holds the string denoting the creator_id field in the database.
+	FieldCreatorID = "creator_id"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// EdgeTaskStages holds the string denoting the task_stages edge name in mutations.
+	EdgeTaskStages = "task_stages"
+	// Table holds the table name of the soptask in the database.
+	Table = "sop_task"
+	// TaskStagesTable is the table that holds the task_stages relation/edge.
+	TaskStagesTable = "sop_stage"
+	// TaskStagesInverseTable is the table name for the SopStage entity.
+	// It exists in this package in order to avoid circular dependency with the "sopstage" package.
+	TaskStagesInverseTable = "sop_stage"
+	// TaskStagesColumn is the table column denoting the task_stages relation/edge.
+	TaskStagesColumn = "task_id"
+)
+
+// Columns holds all SQL columns for soptask fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldName,
+	FieldBotWxidList,
+	FieldType,
+	FieldPlanStartTime,
+	FieldPlanEndTime,
+	FieldCreatorID,
+	FieldDeletedAt,
+}
+
+// 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 (
+	// DefaultCreatedAt holds the default value on creation for the "created_at" field.
+	DefaultCreatedAt func() time.Time
+	// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
+	DefaultUpdatedAt func() time.Time
+	// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
+	UpdateDefaultUpdatedAt func() time.Time
+	// DefaultStatus holds the default value on creation for the "status" field.
+	DefaultStatus uint8
+	// NameValidator is a validator for the "name" field. It is called by the builders before save.
+	NameValidator func(string) error
+	// DefaultType holds the default value on creation for the "type" field.
+	DefaultType int
+)
+
+// OrderOption defines the ordering options for the SopTask queries.
+type OrderOption func(*sql.Selector)
+
+// ByID orders the results by the id field.
+func ByID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldID, opts...).ToFunc()
+}
+
+// ByCreatedAt orders the results by the created_at field.
+func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
+}
+
+// ByUpdatedAt orders the results by the updated_at field.
+func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
+}
+
+// ByStatus orders the results by the status field.
+func ByStatus(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStatus, opts...).ToFunc()
+}
+
+// ByName orders the results by the name field.
+func ByName(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldName, opts...).ToFunc()
+}
+
+// ByType orders the results by the type field.
+func ByType(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldType, opts...).ToFunc()
+}
+
+// ByPlanStartTime orders the results by the plan_start_time field.
+func ByPlanStartTime(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldPlanStartTime, opts...).ToFunc()
+}
+
+// ByPlanEndTime orders the results by the plan_end_time field.
+func ByPlanEndTime(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldPlanEndTime, opts...).ToFunc()
+}
+
+// ByCreatorID orders the results by the creator_id field.
+func ByCreatorID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCreatorID, opts...).ToFunc()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// ByTaskStagesCount orders the results by task_stages count.
+func ByTaskStagesCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newTaskStagesStep(), opts...)
+	}
+}
+
+// ByTaskStages orders the results by task_stages terms.
+func ByTaskStages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newTaskStagesStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newTaskStagesStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(TaskStagesInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, TaskStagesTable, TaskStagesColumn),
+	)
+}

+ 609 - 0
ent/soptask/where.go

@@ -0,0 +1,609 @@
+// Code generated by ent, DO NOT EDIT.
+
+package soptask
+
+import (
+	"time"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldID, id))
+}
+
+// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
+func CreatedAt(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
+func UpdatedAt(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldStatus, v))
+}
+
+// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
+func Name(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldName, v))
+}
+
+// Type applies equality check predicate on the "type" field. It's identical to TypeEQ.
+func Type(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldType, v))
+}
+
+// PlanStartTime applies equality check predicate on the "plan_start_time" field. It's identical to PlanStartTimeEQ.
+func PlanStartTime(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldPlanStartTime, v))
+}
+
+// PlanEndTime applies equality check predicate on the "plan_end_time" field. It's identical to PlanEndTimeEQ.
+func PlanEndTime(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldPlanEndTime, v))
+}
+
+// CreatorID applies equality check predicate on the "creator_id" field. It's identical to CreatorIDEQ.
+func CreatorID(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldCreatorID, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldStatus))
+}
+
+// NameEQ applies the EQ predicate on the "name" field.
+func NameEQ(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldName, v))
+}
+
+// NameNEQ applies the NEQ predicate on the "name" field.
+func NameNEQ(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldName, v))
+}
+
+// NameIn applies the In predicate on the "name" field.
+func NameIn(vs ...string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldName, vs...))
+}
+
+// NameNotIn applies the NotIn predicate on the "name" field.
+func NameNotIn(vs ...string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldName, vs...))
+}
+
+// NameGT applies the GT predicate on the "name" field.
+func NameGT(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldName, v))
+}
+
+// NameGTE applies the GTE predicate on the "name" field.
+func NameGTE(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldName, v))
+}
+
+// NameLT applies the LT predicate on the "name" field.
+func NameLT(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldName, v))
+}
+
+// NameLTE applies the LTE predicate on the "name" field.
+func NameLTE(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldName, v))
+}
+
+// NameContains applies the Contains predicate on the "name" field.
+func NameContains(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldContains(FieldName, v))
+}
+
+// NameHasPrefix applies the HasPrefix predicate on the "name" field.
+func NameHasPrefix(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldHasPrefix(FieldName, v))
+}
+
+// NameHasSuffix applies the HasSuffix predicate on the "name" field.
+func NameHasSuffix(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldHasSuffix(FieldName, v))
+}
+
+// NameEqualFold applies the EqualFold predicate on the "name" field.
+func NameEqualFold(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEqualFold(FieldName, v))
+}
+
+// NameContainsFold applies the ContainsFold predicate on the "name" field.
+func NameContainsFold(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldContainsFold(FieldName, v))
+}
+
+// BotWxidListIsNil applies the IsNil predicate on the "bot_wxid_list" field.
+func BotWxidListIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldBotWxidList))
+}
+
+// BotWxidListNotNil applies the NotNil predicate on the "bot_wxid_list" field.
+func BotWxidListNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldBotWxidList))
+}
+
+// TypeEQ applies the EQ predicate on the "type" field.
+func TypeEQ(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldType, v))
+}
+
+// TypeNEQ applies the NEQ predicate on the "type" field.
+func TypeNEQ(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldType, v))
+}
+
+// TypeIn applies the In predicate on the "type" field.
+func TypeIn(vs ...int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldType, vs...))
+}
+
+// TypeNotIn applies the NotIn predicate on the "type" field.
+func TypeNotIn(vs ...int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldType, vs...))
+}
+
+// TypeGT applies the GT predicate on the "type" field.
+func TypeGT(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldType, v))
+}
+
+// TypeGTE applies the GTE predicate on the "type" field.
+func TypeGTE(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldType, v))
+}
+
+// TypeLT applies the LT predicate on the "type" field.
+func TypeLT(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldType, v))
+}
+
+// TypeLTE applies the LTE predicate on the "type" field.
+func TypeLTE(v int) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldType, v))
+}
+
+// PlanStartTimeEQ applies the EQ predicate on the "plan_start_time" field.
+func PlanStartTimeEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeNEQ applies the NEQ predicate on the "plan_start_time" field.
+func PlanStartTimeNEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeIn applies the In predicate on the "plan_start_time" field.
+func PlanStartTimeIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldPlanStartTime, vs...))
+}
+
+// PlanStartTimeNotIn applies the NotIn predicate on the "plan_start_time" field.
+func PlanStartTimeNotIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldPlanStartTime, vs...))
+}
+
+// PlanStartTimeGT applies the GT predicate on the "plan_start_time" field.
+func PlanStartTimeGT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeGTE applies the GTE predicate on the "plan_start_time" field.
+func PlanStartTimeGTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeLT applies the LT predicate on the "plan_start_time" field.
+func PlanStartTimeLT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeLTE applies the LTE predicate on the "plan_start_time" field.
+func PlanStartTimeLTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldPlanStartTime, v))
+}
+
+// PlanStartTimeIsNil applies the IsNil predicate on the "plan_start_time" field.
+func PlanStartTimeIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldPlanStartTime))
+}
+
+// PlanStartTimeNotNil applies the NotNil predicate on the "plan_start_time" field.
+func PlanStartTimeNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldPlanStartTime))
+}
+
+// PlanEndTimeEQ applies the EQ predicate on the "plan_end_time" field.
+func PlanEndTimeEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeNEQ applies the NEQ predicate on the "plan_end_time" field.
+func PlanEndTimeNEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeIn applies the In predicate on the "plan_end_time" field.
+func PlanEndTimeIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldPlanEndTime, vs...))
+}
+
+// PlanEndTimeNotIn applies the NotIn predicate on the "plan_end_time" field.
+func PlanEndTimeNotIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldPlanEndTime, vs...))
+}
+
+// PlanEndTimeGT applies the GT predicate on the "plan_end_time" field.
+func PlanEndTimeGT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeGTE applies the GTE predicate on the "plan_end_time" field.
+func PlanEndTimeGTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeLT applies the LT predicate on the "plan_end_time" field.
+func PlanEndTimeLT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeLTE applies the LTE predicate on the "plan_end_time" field.
+func PlanEndTimeLTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldPlanEndTime, v))
+}
+
+// PlanEndTimeIsNil applies the IsNil predicate on the "plan_end_time" field.
+func PlanEndTimeIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldPlanEndTime))
+}
+
+// PlanEndTimeNotNil applies the NotNil predicate on the "plan_end_time" field.
+func PlanEndTimeNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldPlanEndTime))
+}
+
+// CreatorIDEQ applies the EQ predicate on the "creator_id" field.
+func CreatorIDEQ(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldCreatorID, v))
+}
+
+// CreatorIDNEQ applies the NEQ predicate on the "creator_id" field.
+func CreatorIDNEQ(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldCreatorID, v))
+}
+
+// CreatorIDIn applies the In predicate on the "creator_id" field.
+func CreatorIDIn(vs ...string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldCreatorID, vs...))
+}
+
+// CreatorIDNotIn applies the NotIn predicate on the "creator_id" field.
+func CreatorIDNotIn(vs ...string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldCreatorID, vs...))
+}
+
+// CreatorIDGT applies the GT predicate on the "creator_id" field.
+func CreatorIDGT(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldCreatorID, v))
+}
+
+// CreatorIDGTE applies the GTE predicate on the "creator_id" field.
+func CreatorIDGTE(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldCreatorID, v))
+}
+
+// CreatorIDLT applies the LT predicate on the "creator_id" field.
+func CreatorIDLT(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldCreatorID, v))
+}
+
+// CreatorIDLTE applies the LTE predicate on the "creator_id" field.
+func CreatorIDLTE(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldCreatorID, v))
+}
+
+// CreatorIDContains applies the Contains predicate on the "creator_id" field.
+func CreatorIDContains(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldContains(FieldCreatorID, v))
+}
+
+// CreatorIDHasPrefix applies the HasPrefix predicate on the "creator_id" field.
+func CreatorIDHasPrefix(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldHasPrefix(FieldCreatorID, v))
+}
+
+// CreatorIDHasSuffix applies the HasSuffix predicate on the "creator_id" field.
+func CreatorIDHasSuffix(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldHasSuffix(FieldCreatorID, v))
+}
+
+// CreatorIDIsNil applies the IsNil predicate on the "creator_id" field.
+func CreatorIDIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldCreatorID))
+}
+
+// CreatorIDNotNil applies the NotNil predicate on the "creator_id" field.
+func CreatorIDNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldCreatorID))
+}
+
+// CreatorIDEqualFold applies the EqualFold predicate on the "creator_id" field.
+func CreatorIDEqualFold(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEqualFold(FieldCreatorID, v))
+}
+
+// CreatorIDContainsFold applies the ContainsFold predicate on the "creator_id" field.
+func CreatorIDContainsFold(v string) predicate.SopTask {
+	return predicate.SopTask(sql.FieldContainsFold(FieldCreatorID, v))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.SopTask {
+	return predicate.SopTask(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.SopTask {
+	return predicate.SopTask(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// HasTaskStages applies the HasEdge predicate on the "task_stages" edge.
+func HasTaskStages() predicate.SopTask {
+	return predicate.SopTask(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, TaskStagesTable, TaskStagesColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasTaskStagesWith applies the HasEdge predicate on the "task_stages" edge with a given conditions (other predicates).
+func HasTaskStagesWith(preds ...predicate.SopStage) predicate.SopTask {
+	return predicate.SopTask(func(s *sql.Selector) {
+		step := newTaskStagesStep()
+		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.SopTask) predicate.SopTask {
+	return predicate.SopTask(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.SopTask) predicate.SopTask {
+	return predicate.SopTask(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.SopTask) predicate.SopTask {
+	return predicate.SopTask(sql.NotPredicates(p))
+}

+ 418 - 0
ent/soptask_create.go

@@ -0,0 +1,418 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopTaskCreate is the builder for creating a SopTask entity.
+type SopTaskCreate struct {
+	config
+	mutation *SopTaskMutation
+	hooks    []Hook
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (stc *SopTaskCreate) SetCreatedAt(t time.Time) *SopTaskCreate {
+	stc.mutation.SetCreatedAt(t)
+	return stc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableCreatedAt(t *time.Time) *SopTaskCreate {
+	if t != nil {
+		stc.SetCreatedAt(*t)
+	}
+	return stc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (stc *SopTaskCreate) SetUpdatedAt(t time.Time) *SopTaskCreate {
+	stc.mutation.SetUpdatedAt(t)
+	return stc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableUpdatedAt(t *time.Time) *SopTaskCreate {
+	if t != nil {
+		stc.SetUpdatedAt(*t)
+	}
+	return stc
+}
+
+// SetStatus sets the "status" field.
+func (stc *SopTaskCreate) SetStatus(u uint8) *SopTaskCreate {
+	stc.mutation.SetStatus(u)
+	return stc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableStatus(u *uint8) *SopTaskCreate {
+	if u != nil {
+		stc.SetStatus(*u)
+	}
+	return stc
+}
+
+// SetName sets the "name" field.
+func (stc *SopTaskCreate) SetName(s string) *SopTaskCreate {
+	stc.mutation.SetName(s)
+	return stc
+}
+
+// SetBotWxidList sets the "bot_wxid_list" field.
+func (stc *SopTaskCreate) SetBotWxidList(s []string) *SopTaskCreate {
+	stc.mutation.SetBotWxidList(s)
+	return stc
+}
+
+// SetType sets the "type" field.
+func (stc *SopTaskCreate) SetType(i int) *SopTaskCreate {
+	stc.mutation.SetType(i)
+	return stc
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableType(i *int) *SopTaskCreate {
+	if i != nil {
+		stc.SetType(*i)
+	}
+	return stc
+}
+
+// SetPlanStartTime sets the "plan_start_time" field.
+func (stc *SopTaskCreate) SetPlanStartTime(t time.Time) *SopTaskCreate {
+	stc.mutation.SetPlanStartTime(t)
+	return stc
+}
+
+// SetNillablePlanStartTime sets the "plan_start_time" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillablePlanStartTime(t *time.Time) *SopTaskCreate {
+	if t != nil {
+		stc.SetPlanStartTime(*t)
+	}
+	return stc
+}
+
+// SetPlanEndTime sets the "plan_end_time" field.
+func (stc *SopTaskCreate) SetPlanEndTime(t time.Time) *SopTaskCreate {
+	stc.mutation.SetPlanEndTime(t)
+	return stc
+}
+
+// SetNillablePlanEndTime sets the "plan_end_time" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillablePlanEndTime(t *time.Time) *SopTaskCreate {
+	if t != nil {
+		stc.SetPlanEndTime(*t)
+	}
+	return stc
+}
+
+// SetCreatorID sets the "creator_id" field.
+func (stc *SopTaskCreate) SetCreatorID(s string) *SopTaskCreate {
+	stc.mutation.SetCreatorID(s)
+	return stc
+}
+
+// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableCreatorID(s *string) *SopTaskCreate {
+	if s != nil {
+		stc.SetCreatorID(*s)
+	}
+	return stc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (stc *SopTaskCreate) SetDeletedAt(t time.Time) *SopTaskCreate {
+	stc.mutation.SetDeletedAt(t)
+	return stc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (stc *SopTaskCreate) SetNillableDeletedAt(t *time.Time) *SopTaskCreate {
+	if t != nil {
+		stc.SetDeletedAt(*t)
+	}
+	return stc
+}
+
+// SetID sets the "id" field.
+func (stc *SopTaskCreate) SetID(u uint64) *SopTaskCreate {
+	stc.mutation.SetID(u)
+	return stc
+}
+
+// AddTaskStageIDs adds the "task_stages" edge to the SopStage entity by IDs.
+func (stc *SopTaskCreate) AddTaskStageIDs(ids ...uint64) *SopTaskCreate {
+	stc.mutation.AddTaskStageIDs(ids...)
+	return stc
+}
+
+// AddTaskStages adds the "task_stages" edges to the SopStage entity.
+func (stc *SopTaskCreate) AddTaskStages(s ...*SopStage) *SopTaskCreate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return stc.AddTaskStageIDs(ids...)
+}
+
+// Mutation returns the SopTaskMutation object of the builder.
+func (stc *SopTaskCreate) Mutation() *SopTaskMutation {
+	return stc.mutation
+}
+
+// Save creates the SopTask in the database.
+func (stc *SopTaskCreate) Save(ctx context.Context) (*SopTask, error) {
+	stc.defaults()
+	return withHooks(ctx, stc.sqlSave, stc.mutation, stc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (stc *SopTaskCreate) SaveX(ctx context.Context) *SopTask {
+	v, err := stc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (stc *SopTaskCreate) Exec(ctx context.Context) error {
+	_, err := stc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (stc *SopTaskCreate) ExecX(ctx context.Context) {
+	if err := stc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (stc *SopTaskCreate) defaults() {
+	if _, ok := stc.mutation.CreatedAt(); !ok {
+		v := soptask.DefaultCreatedAt()
+		stc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := stc.mutation.UpdatedAt(); !ok {
+		v := soptask.DefaultUpdatedAt()
+		stc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := stc.mutation.Status(); !ok {
+		v := soptask.DefaultStatus
+		stc.mutation.SetStatus(v)
+	}
+	if _, ok := stc.mutation.GetType(); !ok {
+		v := soptask.DefaultType
+		stc.mutation.SetType(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (stc *SopTaskCreate) check() error {
+	if _, ok := stc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "SopTask.created_at"`)}
+	}
+	if _, ok := stc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "SopTask.updated_at"`)}
+	}
+	if _, ok := stc.mutation.Name(); !ok {
+		return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "SopTask.name"`)}
+	}
+	if v, ok := stc.mutation.Name(); ok {
+		if err := soptask.NameValidator(v); err != nil {
+			return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "SopTask.name": %w`, err)}
+		}
+	}
+	if _, ok := stc.mutation.GetType(); !ok {
+		return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "SopTask.type"`)}
+	}
+	return nil
+}
+
+func (stc *SopTaskCreate) sqlSave(ctx context.Context) (*SopTask, error) {
+	if err := stc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := stc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, stc.driver, _spec); err != nil {
+		if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	if _spec.ID.Value != _node.ID {
+		id := _spec.ID.Value.(int64)
+		_node.ID = uint64(id)
+	}
+	stc.mutation.id = &_node.ID
+	stc.mutation.done = true
+	return _node, nil
+}
+
+func (stc *SopTaskCreate) createSpec() (*SopTask, *sqlgraph.CreateSpec) {
+	var (
+		_node = &SopTask{config: stc.config}
+		_spec = sqlgraph.NewCreateSpec(soptask.Table, sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64))
+	)
+	if id, ok := stc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := stc.mutation.CreatedAt(); ok {
+		_spec.SetField(soptask.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := stc.mutation.UpdatedAt(); ok {
+		_spec.SetField(soptask.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := stc.mutation.Status(); ok {
+		_spec.SetField(soptask.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := stc.mutation.Name(); ok {
+		_spec.SetField(soptask.FieldName, field.TypeString, value)
+		_node.Name = value
+	}
+	if value, ok := stc.mutation.BotWxidList(); ok {
+		_spec.SetField(soptask.FieldBotWxidList, field.TypeJSON, value)
+		_node.BotWxidList = value
+	}
+	if value, ok := stc.mutation.GetType(); ok {
+		_spec.SetField(soptask.FieldType, field.TypeInt, value)
+		_node.Type = value
+	}
+	if value, ok := stc.mutation.PlanStartTime(); ok {
+		_spec.SetField(soptask.FieldPlanStartTime, field.TypeTime, value)
+		_node.PlanStartTime = value
+	}
+	if value, ok := stc.mutation.PlanEndTime(); ok {
+		_spec.SetField(soptask.FieldPlanEndTime, field.TypeTime, value)
+		_node.PlanEndTime = value
+	}
+	if value, ok := stc.mutation.CreatorID(); ok {
+		_spec.SetField(soptask.FieldCreatorID, field.TypeString, value)
+		_node.CreatorID = value
+	}
+	if value, ok := stc.mutation.DeletedAt(); ok {
+		_spec.SetField(soptask.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if nodes := stc.mutation.TaskStagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	return _node, _spec
+}
+
+// SopTaskCreateBulk is the builder for creating many SopTask entities in bulk.
+type SopTaskCreateBulk struct {
+	config
+	err      error
+	builders []*SopTaskCreate
+}
+
+// Save creates the SopTask entities in the database.
+func (stcb *SopTaskCreateBulk) Save(ctx context.Context) ([]*SopTask, error) {
+	if stcb.err != nil {
+		return nil, stcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(stcb.builders))
+	nodes := make([]*SopTask, len(stcb.builders))
+	mutators := make([]Mutator, len(stcb.builders))
+	for i := range stcb.builders {
+		func(i int, root context.Context) {
+			builder := stcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*SopTaskMutation)
+				if !ok {
+					return nil, fmt.Errorf("unexpected mutation type %T", m)
+				}
+				if err := builder.check(); err != nil {
+					return nil, err
+				}
+				builder.mutation = mutation
+				var err error
+				nodes[i], specs[i] = builder.createSpec()
+				if i < len(mutators)-1 {
+					_, err = mutators[i+1].Mutate(root, stcb.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, stcb.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 && nodes[i].ID == 0 {
+					id := specs[i].ID.Value.(int64)
+					nodes[i].ID = uint64(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, stcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (stcb *SopTaskCreateBulk) SaveX(ctx context.Context) []*SopTask {
+	v, err := stcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (stcb *SopTaskCreateBulk) Exec(ctx context.Context) error {
+	_, err := stcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (stcb *SopTaskCreateBulk) ExecX(ctx context.Context) {
+	if err := stcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/soptask_delete.go

@@ -0,0 +1,88 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopTaskDelete is the builder for deleting a SopTask entity.
+type SopTaskDelete struct {
+	config
+	hooks    []Hook
+	mutation *SopTaskMutation
+}
+
+// Where appends a list predicates to the SopTaskDelete builder.
+func (std *SopTaskDelete) Where(ps ...predicate.SopTask) *SopTaskDelete {
+	std.mutation.Where(ps...)
+	return std
+}
+
+// Exec executes the deletion query and returns how many vertices were deleted.
+func (std *SopTaskDelete) Exec(ctx context.Context) (int, error) {
+	return withHooks(ctx, std.sqlExec, std.mutation, std.hooks)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (std *SopTaskDelete) ExecX(ctx context.Context) int {
+	n, err := std.Exec(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return n
+}
+
+func (std *SopTaskDelete) sqlExec(ctx context.Context) (int, error) {
+	_spec := sqlgraph.NewDeleteSpec(soptask.Table, sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64))
+	if ps := std.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	affected, err := sqlgraph.DeleteNodes(ctx, std.driver, _spec)
+	if err != nil && sqlgraph.IsConstraintError(err) {
+		err = &ConstraintError{msg: err.Error(), wrap: err}
+	}
+	std.mutation.done = true
+	return affected, err
+}
+
+// SopTaskDeleteOne is the builder for deleting a single SopTask entity.
+type SopTaskDeleteOne struct {
+	std *SopTaskDelete
+}
+
+// Where appends a list predicates to the SopTaskDelete builder.
+func (stdo *SopTaskDeleteOne) Where(ps ...predicate.SopTask) *SopTaskDeleteOne {
+	stdo.std.mutation.Where(ps...)
+	return stdo
+}
+
+// Exec executes the deletion query.
+func (stdo *SopTaskDeleteOne) Exec(ctx context.Context) error {
+	n, err := stdo.std.Exec(ctx)
+	switch {
+	case err != nil:
+		return err
+	case n == 0:
+		return &NotFoundError{soptask.Label}
+	default:
+		return nil
+	}
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (stdo *SopTaskDeleteOne) ExecX(ctx context.Context) {
+	if err := stdo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 605 - 0
ent/soptask_query.go

@@ -0,0 +1,605 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"database/sql/driver"
+	"fmt"
+	"math"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopTaskQuery is the builder for querying SopTask entities.
+type SopTaskQuery struct {
+	config
+	ctx            *QueryContext
+	order          []soptask.OrderOption
+	inters         []Interceptor
+	predicates     []predicate.SopTask
+	withTaskStages *SopStageQuery
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the SopTaskQuery builder.
+func (stq *SopTaskQuery) Where(ps ...predicate.SopTask) *SopTaskQuery {
+	stq.predicates = append(stq.predicates, ps...)
+	return stq
+}
+
+// Limit the number of records to be returned by this query.
+func (stq *SopTaskQuery) Limit(limit int) *SopTaskQuery {
+	stq.ctx.Limit = &limit
+	return stq
+}
+
+// Offset to start from.
+func (stq *SopTaskQuery) Offset(offset int) *SopTaskQuery {
+	stq.ctx.Offset = &offset
+	return stq
+}
+
+// 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 (stq *SopTaskQuery) Unique(unique bool) *SopTaskQuery {
+	stq.ctx.Unique = &unique
+	return stq
+}
+
+// Order specifies how the records should be ordered.
+func (stq *SopTaskQuery) Order(o ...soptask.OrderOption) *SopTaskQuery {
+	stq.order = append(stq.order, o...)
+	return stq
+}
+
+// QueryTaskStages chains the current query on the "task_stages" edge.
+func (stq *SopTaskQuery) QueryTaskStages() *SopStageQuery {
+	query := (&SopStageClient{config: stq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := stq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := stq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(soptask.Table, soptask.FieldID, selector),
+			sqlgraph.To(sopstage.Table, sopstage.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, soptask.TaskStagesTable, soptask.TaskStagesColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(stq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// First returns the first SopTask entity from the query.
+// Returns a *NotFoundError when no SopTask was found.
+func (stq *SopTaskQuery) First(ctx context.Context) (*SopTask, error) {
+	nodes, err := stq.Limit(1).All(setContextOp(ctx, stq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{soptask.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (stq *SopTaskQuery) FirstX(ctx context.Context) *SopTask {
+	node, err := stq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first SopTask ID from the query.
+// Returns a *NotFoundError when no SopTask ID was found.
+func (stq *SopTaskQuery) FirstID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = stq.Limit(1).IDs(setContextOp(ctx, stq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{soptask.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (stq *SopTaskQuery) FirstIDX(ctx context.Context) uint64 {
+	id, err := stq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single SopTask entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one SopTask entity is found.
+// Returns a *NotFoundError when no SopTask entities are found.
+func (stq *SopTaskQuery) Only(ctx context.Context) (*SopTask, error) {
+	nodes, err := stq.Limit(2).All(setContextOp(ctx, stq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{soptask.Label}
+	default:
+		return nil, &NotSingularError{soptask.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (stq *SopTaskQuery) OnlyX(ctx context.Context) *SopTask {
+	node, err := stq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only SopTask ID in the query.
+// Returns a *NotSingularError when more than one SopTask ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (stq *SopTaskQuery) OnlyID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = stq.Limit(2).IDs(setContextOp(ctx, stq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{soptask.Label}
+	default:
+		err = &NotSingularError{soptask.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (stq *SopTaskQuery) OnlyIDX(ctx context.Context) uint64 {
+	id, err := stq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of SopTasks.
+func (stq *SopTaskQuery) All(ctx context.Context) ([]*SopTask, error) {
+	ctx = setContextOp(ctx, stq.ctx, "All")
+	if err := stq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*SopTask, *SopTaskQuery]()
+	return withInterceptors[[]*SopTask](ctx, stq, qr, stq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (stq *SopTaskQuery) AllX(ctx context.Context) []*SopTask {
+	nodes, err := stq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of SopTask IDs.
+func (stq *SopTaskQuery) IDs(ctx context.Context) (ids []uint64, err error) {
+	if stq.ctx.Unique == nil && stq.path != nil {
+		stq.Unique(true)
+	}
+	ctx = setContextOp(ctx, stq.ctx, "IDs")
+	if err = stq.Select(soptask.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (stq *SopTaskQuery) IDsX(ctx context.Context) []uint64 {
+	ids, err := stq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (stq *SopTaskQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, stq.ctx, "Count")
+	if err := stq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, stq, querierCount[*SopTaskQuery](), stq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (stq *SopTaskQuery) CountX(ctx context.Context) int {
+	count, err := stq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (stq *SopTaskQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, stq.ctx, "Exist")
+	switch _, err := stq.FirstID(ctx); {
+	case IsNotFound(err):
+		return false, nil
+	case err != nil:
+		return false, fmt.Errorf("ent: check existence: %w", err)
+	default:
+		return true, nil
+	}
+}
+
+// ExistX is like Exist, but panics if an error occurs.
+func (stq *SopTaskQuery) ExistX(ctx context.Context) bool {
+	exist, err := stq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the SopTaskQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (stq *SopTaskQuery) Clone() *SopTaskQuery {
+	if stq == nil {
+		return nil
+	}
+	return &SopTaskQuery{
+		config:         stq.config,
+		ctx:            stq.ctx.Clone(),
+		order:          append([]soptask.OrderOption{}, stq.order...),
+		inters:         append([]Interceptor{}, stq.inters...),
+		predicates:     append([]predicate.SopTask{}, stq.predicates...),
+		withTaskStages: stq.withTaskStages.Clone(),
+		// clone intermediate query.
+		sql:  stq.sql.Clone(),
+		path: stq.path,
+	}
+}
+
+// WithTaskStages tells the query-builder to eager-load the nodes that are connected to
+// the "task_stages" edge. The optional arguments are used to configure the query builder of the edge.
+func (stq *SopTaskQuery) WithTaskStages(opts ...func(*SopStageQuery)) *SopTaskQuery {
+	query := (&SopStageClient{config: stq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	stq.withTaskStages = query
+	return stq
+}
+
+// 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//		Count int `json:"count,omitempty"`
+//	}
+//
+//	client.SopTask.Query().
+//		GroupBy(soptask.FieldCreatedAt).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (stq *SopTaskQuery) GroupBy(field string, fields ...string) *SopTaskGroupBy {
+	stq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &SopTaskGroupBy{build: stq}
+	grbuild.flds = &stq.ctx.Fields
+	grbuild.label = soptask.Label
+	grbuild.scan = 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 {
+//		CreatedAt time.Time `json:"created_at,omitempty"`
+//	}
+//
+//	client.SopTask.Query().
+//		Select(soptask.FieldCreatedAt).
+//		Scan(ctx, &v)
+func (stq *SopTaskQuery) Select(fields ...string) *SopTaskSelect {
+	stq.ctx.Fields = append(stq.ctx.Fields, fields...)
+	sbuild := &SopTaskSelect{SopTaskQuery: stq}
+	sbuild.label = soptask.Label
+	sbuild.flds, sbuild.scan = &stq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a SopTaskSelect configured with the given aggregations.
+func (stq *SopTaskQuery) Aggregate(fns ...AggregateFunc) *SopTaskSelect {
+	return stq.Select().Aggregate(fns...)
+}
+
+func (stq *SopTaskQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range stq.inters {
+		if inter == nil {
+			return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
+		}
+		if trv, ok := inter.(Traverser); ok {
+			if err := trv.Traverse(ctx, stq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range stq.ctx.Fields {
+		if !soptask.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if stq.path != nil {
+		prev, err := stq.path(ctx)
+		if err != nil {
+			return err
+		}
+		stq.sql = prev
+	}
+	return nil
+}
+
+func (stq *SopTaskQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*SopTask, error) {
+	var (
+		nodes       = []*SopTask{}
+		_spec       = stq.querySpec()
+		loadedTypes = [1]bool{
+			stq.withTaskStages != nil,
+		}
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*SopTask).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &SopTask{config: stq.config}
+		nodes = append(nodes, node)
+		node.Edges.loadedTypes = loadedTypes
+		return node.assignValues(columns, values)
+	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
+	if err := sqlgraph.QueryNodes(ctx, stq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	if query := stq.withTaskStages; query != nil {
+		if err := stq.loadTaskStages(ctx, query, nodes,
+			func(n *SopTask) { n.Edges.TaskStages = []*SopStage{} },
+			func(n *SopTask, e *SopStage) { n.Edges.TaskStages = append(n.Edges.TaskStages, e) }); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+func (stq *SopTaskQuery) loadTaskStages(ctx context.Context, query *SopStageQuery, nodes []*SopTask, init func(*SopTask), assign func(*SopTask, *SopStage)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*SopTask)
+	for i := range nodes {
+		fks = append(fks, nodes[i].ID)
+		nodeids[nodes[i].ID] = nodes[i]
+		if init != nil {
+			init(nodes[i])
+		}
+	}
+	if len(query.ctx.Fields) > 0 {
+		query.ctx.AppendFieldOnce(sopstage.FieldTaskID)
+	}
+	query.Where(predicate.SopStage(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(soptask.TaskStagesColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.TaskID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "task_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
+
+func (stq *SopTaskQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := stq.querySpec()
+	_spec.Node.Columns = stq.ctx.Fields
+	if len(stq.ctx.Fields) > 0 {
+		_spec.Unique = stq.ctx.Unique != nil && *stq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, stq.driver, _spec)
+}
+
+func (stq *SopTaskQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(soptask.Table, soptask.Columns, sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64))
+	_spec.From = stq.sql
+	if unique := stq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if stq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := stq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, soptask.FieldID)
+		for i := range fields {
+			if fields[i] != soptask.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+	}
+	if ps := stq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := stq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := stq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := stq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (stq *SopTaskQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(stq.driver.Dialect())
+	t1 := builder.Table(soptask.Table)
+	columns := stq.ctx.Fields
+	if len(columns) == 0 {
+		columns = soptask.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if stq.sql != nil {
+		selector = stq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if stq.ctx.Unique != nil && *stq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range stq.predicates {
+		p(selector)
+	}
+	for _, p := range stq.order {
+		p(selector)
+	}
+	if offset := stq.ctx.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 := stq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// SopTaskGroupBy is the group-by builder for SopTask entities.
+type SopTaskGroupBy struct {
+	selector
+	build *SopTaskQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (stgb *SopTaskGroupBy) Aggregate(fns ...AggregateFunc) *SopTaskGroupBy {
+	stgb.fns = append(stgb.fns, fns...)
+	return stgb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (stgb *SopTaskGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, stgb.build.ctx, "GroupBy")
+	if err := stgb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopTaskQuery, *SopTaskGroupBy](ctx, stgb.build, stgb, stgb.build.inters, v)
+}
+
+func (stgb *SopTaskGroupBy) sqlScan(ctx context.Context, root *SopTaskQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(stgb.fns))
+	for _, fn := range stgb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*stgb.flds)+len(stgb.fns))
+		for _, f := range *stgb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*stgb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := stgb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// SopTaskSelect is the builder for selecting fields of SopTask entities.
+type SopTaskSelect struct {
+	*SopTaskQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (sts *SopTaskSelect) Aggregate(fns ...AggregateFunc) *SopTaskSelect {
+	sts.fns = append(sts.fns, fns...)
+	return sts
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (sts *SopTaskSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, sts.ctx, "Select")
+	if err := sts.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*SopTaskQuery, *SopTaskSelect](ctx, sts.SopTaskQuery, sts, sts.inters, v)
+}
+
+func (sts *SopTaskSelect) sqlScan(ctx context.Context, root *SopTaskQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(sts.fns))
+	for _, fn := range sts.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*sts.selector.flds); {
+	case n == 0 && len(aggregation) > 0:
+		selector.Select(aggregation...)
+	case n != 0 && len(aggregation) > 0:
+		selector.AppendSelect(aggregation...)
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := sts.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 828 - 0
ent/soptask_update.go

@@ -0,0 +1,828 @@
+// 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/dialect/sql/sqljson"
+	"entgo.io/ent/schema/field"
+	"github.com/suyuan32/simple-admin-job/ent/predicate"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+)
+
+// SopTaskUpdate is the builder for updating SopTask entities.
+type SopTaskUpdate struct {
+	config
+	hooks    []Hook
+	mutation *SopTaskMutation
+}
+
+// Where appends a list predicates to the SopTaskUpdate builder.
+func (stu *SopTaskUpdate) Where(ps ...predicate.SopTask) *SopTaskUpdate {
+	stu.mutation.Where(ps...)
+	return stu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (stu *SopTaskUpdate) SetUpdatedAt(t time.Time) *SopTaskUpdate {
+	stu.mutation.SetUpdatedAt(t)
+	return stu
+}
+
+// SetStatus sets the "status" field.
+func (stu *SopTaskUpdate) SetStatus(u uint8) *SopTaskUpdate {
+	stu.mutation.ResetStatus()
+	stu.mutation.SetStatus(u)
+	return stu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillableStatus(u *uint8) *SopTaskUpdate {
+	if u != nil {
+		stu.SetStatus(*u)
+	}
+	return stu
+}
+
+// AddStatus adds u to the "status" field.
+func (stu *SopTaskUpdate) AddStatus(u int8) *SopTaskUpdate {
+	stu.mutation.AddStatus(u)
+	return stu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (stu *SopTaskUpdate) ClearStatus() *SopTaskUpdate {
+	stu.mutation.ClearStatus()
+	return stu
+}
+
+// SetName sets the "name" field.
+func (stu *SopTaskUpdate) SetName(s string) *SopTaskUpdate {
+	stu.mutation.SetName(s)
+	return stu
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillableName(s *string) *SopTaskUpdate {
+	if s != nil {
+		stu.SetName(*s)
+	}
+	return stu
+}
+
+// SetBotWxidList sets the "bot_wxid_list" field.
+func (stu *SopTaskUpdate) SetBotWxidList(s []string) *SopTaskUpdate {
+	stu.mutation.SetBotWxidList(s)
+	return stu
+}
+
+// AppendBotWxidList appends s to the "bot_wxid_list" field.
+func (stu *SopTaskUpdate) AppendBotWxidList(s []string) *SopTaskUpdate {
+	stu.mutation.AppendBotWxidList(s)
+	return stu
+}
+
+// ClearBotWxidList clears the value of the "bot_wxid_list" field.
+func (stu *SopTaskUpdate) ClearBotWxidList() *SopTaskUpdate {
+	stu.mutation.ClearBotWxidList()
+	return stu
+}
+
+// SetType sets the "type" field.
+func (stu *SopTaskUpdate) SetType(i int) *SopTaskUpdate {
+	stu.mutation.ResetType()
+	stu.mutation.SetType(i)
+	return stu
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillableType(i *int) *SopTaskUpdate {
+	if i != nil {
+		stu.SetType(*i)
+	}
+	return stu
+}
+
+// AddType adds i to the "type" field.
+func (stu *SopTaskUpdate) AddType(i int) *SopTaskUpdate {
+	stu.mutation.AddType(i)
+	return stu
+}
+
+// SetPlanStartTime sets the "plan_start_time" field.
+func (stu *SopTaskUpdate) SetPlanStartTime(t time.Time) *SopTaskUpdate {
+	stu.mutation.SetPlanStartTime(t)
+	return stu
+}
+
+// SetNillablePlanStartTime sets the "plan_start_time" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillablePlanStartTime(t *time.Time) *SopTaskUpdate {
+	if t != nil {
+		stu.SetPlanStartTime(*t)
+	}
+	return stu
+}
+
+// ClearPlanStartTime clears the value of the "plan_start_time" field.
+func (stu *SopTaskUpdate) ClearPlanStartTime() *SopTaskUpdate {
+	stu.mutation.ClearPlanStartTime()
+	return stu
+}
+
+// SetPlanEndTime sets the "plan_end_time" field.
+func (stu *SopTaskUpdate) SetPlanEndTime(t time.Time) *SopTaskUpdate {
+	stu.mutation.SetPlanEndTime(t)
+	return stu
+}
+
+// SetNillablePlanEndTime sets the "plan_end_time" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillablePlanEndTime(t *time.Time) *SopTaskUpdate {
+	if t != nil {
+		stu.SetPlanEndTime(*t)
+	}
+	return stu
+}
+
+// ClearPlanEndTime clears the value of the "plan_end_time" field.
+func (stu *SopTaskUpdate) ClearPlanEndTime() *SopTaskUpdate {
+	stu.mutation.ClearPlanEndTime()
+	return stu
+}
+
+// SetCreatorID sets the "creator_id" field.
+func (stu *SopTaskUpdate) SetCreatorID(s string) *SopTaskUpdate {
+	stu.mutation.SetCreatorID(s)
+	return stu
+}
+
+// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillableCreatorID(s *string) *SopTaskUpdate {
+	if s != nil {
+		stu.SetCreatorID(*s)
+	}
+	return stu
+}
+
+// ClearCreatorID clears the value of the "creator_id" field.
+func (stu *SopTaskUpdate) ClearCreatorID() *SopTaskUpdate {
+	stu.mutation.ClearCreatorID()
+	return stu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (stu *SopTaskUpdate) SetDeletedAt(t time.Time) *SopTaskUpdate {
+	stu.mutation.SetDeletedAt(t)
+	return stu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (stu *SopTaskUpdate) SetNillableDeletedAt(t *time.Time) *SopTaskUpdate {
+	if t != nil {
+		stu.SetDeletedAt(*t)
+	}
+	return stu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (stu *SopTaskUpdate) ClearDeletedAt() *SopTaskUpdate {
+	stu.mutation.ClearDeletedAt()
+	return stu
+}
+
+// AddTaskStageIDs adds the "task_stages" edge to the SopStage entity by IDs.
+func (stu *SopTaskUpdate) AddTaskStageIDs(ids ...uint64) *SopTaskUpdate {
+	stu.mutation.AddTaskStageIDs(ids...)
+	return stu
+}
+
+// AddTaskStages adds the "task_stages" edges to the SopStage entity.
+func (stu *SopTaskUpdate) AddTaskStages(s ...*SopStage) *SopTaskUpdate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return stu.AddTaskStageIDs(ids...)
+}
+
+// Mutation returns the SopTaskMutation object of the builder.
+func (stu *SopTaskUpdate) Mutation() *SopTaskMutation {
+	return stu.mutation
+}
+
+// ClearTaskStages clears all "task_stages" edges to the SopStage entity.
+func (stu *SopTaskUpdate) ClearTaskStages() *SopTaskUpdate {
+	stu.mutation.ClearTaskStages()
+	return stu
+}
+
+// RemoveTaskStageIDs removes the "task_stages" edge to SopStage entities by IDs.
+func (stu *SopTaskUpdate) RemoveTaskStageIDs(ids ...uint64) *SopTaskUpdate {
+	stu.mutation.RemoveTaskStageIDs(ids...)
+	return stu
+}
+
+// RemoveTaskStages removes "task_stages" edges to SopStage entities.
+func (stu *SopTaskUpdate) RemoveTaskStages(s ...*SopStage) *SopTaskUpdate {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return stu.RemoveTaskStageIDs(ids...)
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (stu *SopTaskUpdate) Save(ctx context.Context) (int, error) {
+	stu.defaults()
+	return withHooks(ctx, stu.sqlSave, stu.mutation, stu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (stu *SopTaskUpdate) SaveX(ctx context.Context) int {
+	affected, err := stu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (stu *SopTaskUpdate) Exec(ctx context.Context) error {
+	_, err := stu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (stu *SopTaskUpdate) ExecX(ctx context.Context) {
+	if err := stu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (stu *SopTaskUpdate) defaults() {
+	if _, ok := stu.mutation.UpdatedAt(); !ok {
+		v := soptask.UpdateDefaultUpdatedAt()
+		stu.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (stu *SopTaskUpdate) check() error {
+	if v, ok := stu.mutation.Name(); ok {
+		if err := soptask.NameValidator(v); err != nil {
+			return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "SopTask.name": %w`, err)}
+		}
+	}
+	return nil
+}
+
+func (stu *SopTaskUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	if err := stu.check(); err != nil {
+		return n, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(soptask.Table, soptask.Columns, sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64))
+	if ps := stu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := stu.mutation.UpdatedAt(); ok {
+		_spec.SetField(soptask.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := stu.mutation.Status(); ok {
+		_spec.SetField(soptask.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := stu.mutation.AddedStatus(); ok {
+		_spec.AddField(soptask.FieldStatus, field.TypeUint8, value)
+	}
+	if stu.mutation.StatusCleared() {
+		_spec.ClearField(soptask.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := stu.mutation.Name(); ok {
+		_spec.SetField(soptask.FieldName, field.TypeString, value)
+	}
+	if value, ok := stu.mutation.BotWxidList(); ok {
+		_spec.SetField(soptask.FieldBotWxidList, field.TypeJSON, value)
+	}
+	if value, ok := stu.mutation.AppendedBotWxidList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, soptask.FieldBotWxidList, value)
+		})
+	}
+	if stu.mutation.BotWxidListCleared() {
+		_spec.ClearField(soptask.FieldBotWxidList, field.TypeJSON)
+	}
+	if value, ok := stu.mutation.GetType(); ok {
+		_spec.SetField(soptask.FieldType, field.TypeInt, value)
+	}
+	if value, ok := stu.mutation.AddedType(); ok {
+		_spec.AddField(soptask.FieldType, field.TypeInt, value)
+	}
+	if value, ok := stu.mutation.PlanStartTime(); ok {
+		_spec.SetField(soptask.FieldPlanStartTime, field.TypeTime, value)
+	}
+	if stu.mutation.PlanStartTimeCleared() {
+		_spec.ClearField(soptask.FieldPlanStartTime, field.TypeTime)
+	}
+	if value, ok := stu.mutation.PlanEndTime(); ok {
+		_spec.SetField(soptask.FieldPlanEndTime, field.TypeTime, value)
+	}
+	if stu.mutation.PlanEndTimeCleared() {
+		_spec.ClearField(soptask.FieldPlanEndTime, field.TypeTime)
+	}
+	if value, ok := stu.mutation.CreatorID(); ok {
+		_spec.SetField(soptask.FieldCreatorID, field.TypeString, value)
+	}
+	if stu.mutation.CreatorIDCleared() {
+		_spec.ClearField(soptask.FieldCreatorID, field.TypeString)
+	}
+	if value, ok := stu.mutation.DeletedAt(); ok {
+		_spec.SetField(soptask.FieldDeletedAt, field.TypeTime, value)
+	}
+	if stu.mutation.DeletedAtCleared() {
+		_spec.ClearField(soptask.FieldDeletedAt, field.TypeTime)
+	}
+	if stu.mutation.TaskStagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := stu.mutation.RemovedTaskStagesIDs(); len(nodes) > 0 && !stu.mutation.TaskStagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := stu.mutation.TaskStagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, stu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{soptask.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	stu.mutation.done = true
+	return n, nil
+}
+
+// SopTaskUpdateOne is the builder for updating a single SopTask entity.
+type SopTaskUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *SopTaskMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (stuo *SopTaskUpdateOne) SetUpdatedAt(t time.Time) *SopTaskUpdateOne {
+	stuo.mutation.SetUpdatedAt(t)
+	return stuo
+}
+
+// SetStatus sets the "status" field.
+func (stuo *SopTaskUpdateOne) SetStatus(u uint8) *SopTaskUpdateOne {
+	stuo.mutation.ResetStatus()
+	stuo.mutation.SetStatus(u)
+	return stuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillableStatus(u *uint8) *SopTaskUpdateOne {
+	if u != nil {
+		stuo.SetStatus(*u)
+	}
+	return stuo
+}
+
+// AddStatus adds u to the "status" field.
+func (stuo *SopTaskUpdateOne) AddStatus(u int8) *SopTaskUpdateOne {
+	stuo.mutation.AddStatus(u)
+	return stuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (stuo *SopTaskUpdateOne) ClearStatus() *SopTaskUpdateOne {
+	stuo.mutation.ClearStatus()
+	return stuo
+}
+
+// SetName sets the "name" field.
+func (stuo *SopTaskUpdateOne) SetName(s string) *SopTaskUpdateOne {
+	stuo.mutation.SetName(s)
+	return stuo
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillableName(s *string) *SopTaskUpdateOne {
+	if s != nil {
+		stuo.SetName(*s)
+	}
+	return stuo
+}
+
+// SetBotWxidList sets the "bot_wxid_list" field.
+func (stuo *SopTaskUpdateOne) SetBotWxidList(s []string) *SopTaskUpdateOne {
+	stuo.mutation.SetBotWxidList(s)
+	return stuo
+}
+
+// AppendBotWxidList appends s to the "bot_wxid_list" field.
+func (stuo *SopTaskUpdateOne) AppendBotWxidList(s []string) *SopTaskUpdateOne {
+	stuo.mutation.AppendBotWxidList(s)
+	return stuo
+}
+
+// ClearBotWxidList clears the value of the "bot_wxid_list" field.
+func (stuo *SopTaskUpdateOne) ClearBotWxidList() *SopTaskUpdateOne {
+	stuo.mutation.ClearBotWxidList()
+	return stuo
+}
+
+// SetType sets the "type" field.
+func (stuo *SopTaskUpdateOne) SetType(i int) *SopTaskUpdateOne {
+	stuo.mutation.ResetType()
+	stuo.mutation.SetType(i)
+	return stuo
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillableType(i *int) *SopTaskUpdateOne {
+	if i != nil {
+		stuo.SetType(*i)
+	}
+	return stuo
+}
+
+// AddType adds i to the "type" field.
+func (stuo *SopTaskUpdateOne) AddType(i int) *SopTaskUpdateOne {
+	stuo.mutation.AddType(i)
+	return stuo
+}
+
+// SetPlanStartTime sets the "plan_start_time" field.
+func (stuo *SopTaskUpdateOne) SetPlanStartTime(t time.Time) *SopTaskUpdateOne {
+	stuo.mutation.SetPlanStartTime(t)
+	return stuo
+}
+
+// SetNillablePlanStartTime sets the "plan_start_time" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillablePlanStartTime(t *time.Time) *SopTaskUpdateOne {
+	if t != nil {
+		stuo.SetPlanStartTime(*t)
+	}
+	return stuo
+}
+
+// ClearPlanStartTime clears the value of the "plan_start_time" field.
+func (stuo *SopTaskUpdateOne) ClearPlanStartTime() *SopTaskUpdateOne {
+	stuo.mutation.ClearPlanStartTime()
+	return stuo
+}
+
+// SetPlanEndTime sets the "plan_end_time" field.
+func (stuo *SopTaskUpdateOne) SetPlanEndTime(t time.Time) *SopTaskUpdateOne {
+	stuo.mutation.SetPlanEndTime(t)
+	return stuo
+}
+
+// SetNillablePlanEndTime sets the "plan_end_time" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillablePlanEndTime(t *time.Time) *SopTaskUpdateOne {
+	if t != nil {
+		stuo.SetPlanEndTime(*t)
+	}
+	return stuo
+}
+
+// ClearPlanEndTime clears the value of the "plan_end_time" field.
+func (stuo *SopTaskUpdateOne) ClearPlanEndTime() *SopTaskUpdateOne {
+	stuo.mutation.ClearPlanEndTime()
+	return stuo
+}
+
+// SetCreatorID sets the "creator_id" field.
+func (stuo *SopTaskUpdateOne) SetCreatorID(s string) *SopTaskUpdateOne {
+	stuo.mutation.SetCreatorID(s)
+	return stuo
+}
+
+// SetNillableCreatorID sets the "creator_id" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillableCreatorID(s *string) *SopTaskUpdateOne {
+	if s != nil {
+		stuo.SetCreatorID(*s)
+	}
+	return stuo
+}
+
+// ClearCreatorID clears the value of the "creator_id" field.
+func (stuo *SopTaskUpdateOne) ClearCreatorID() *SopTaskUpdateOne {
+	stuo.mutation.ClearCreatorID()
+	return stuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (stuo *SopTaskUpdateOne) SetDeletedAt(t time.Time) *SopTaskUpdateOne {
+	stuo.mutation.SetDeletedAt(t)
+	return stuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (stuo *SopTaskUpdateOne) SetNillableDeletedAt(t *time.Time) *SopTaskUpdateOne {
+	if t != nil {
+		stuo.SetDeletedAt(*t)
+	}
+	return stuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (stuo *SopTaskUpdateOne) ClearDeletedAt() *SopTaskUpdateOne {
+	stuo.mutation.ClearDeletedAt()
+	return stuo
+}
+
+// AddTaskStageIDs adds the "task_stages" edge to the SopStage entity by IDs.
+func (stuo *SopTaskUpdateOne) AddTaskStageIDs(ids ...uint64) *SopTaskUpdateOne {
+	stuo.mutation.AddTaskStageIDs(ids...)
+	return stuo
+}
+
+// AddTaskStages adds the "task_stages" edges to the SopStage entity.
+func (stuo *SopTaskUpdateOne) AddTaskStages(s ...*SopStage) *SopTaskUpdateOne {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return stuo.AddTaskStageIDs(ids...)
+}
+
+// Mutation returns the SopTaskMutation object of the builder.
+func (stuo *SopTaskUpdateOne) Mutation() *SopTaskMutation {
+	return stuo.mutation
+}
+
+// ClearTaskStages clears all "task_stages" edges to the SopStage entity.
+func (stuo *SopTaskUpdateOne) ClearTaskStages() *SopTaskUpdateOne {
+	stuo.mutation.ClearTaskStages()
+	return stuo
+}
+
+// RemoveTaskStageIDs removes the "task_stages" edge to SopStage entities by IDs.
+func (stuo *SopTaskUpdateOne) RemoveTaskStageIDs(ids ...uint64) *SopTaskUpdateOne {
+	stuo.mutation.RemoveTaskStageIDs(ids...)
+	return stuo
+}
+
+// RemoveTaskStages removes "task_stages" edges to SopStage entities.
+func (stuo *SopTaskUpdateOne) RemoveTaskStages(s ...*SopStage) *SopTaskUpdateOne {
+	ids := make([]uint64, len(s))
+	for i := range s {
+		ids[i] = s[i].ID
+	}
+	return stuo.RemoveTaskStageIDs(ids...)
+}
+
+// Where appends a list predicates to the SopTaskUpdate builder.
+func (stuo *SopTaskUpdateOne) Where(ps ...predicate.SopTask) *SopTaskUpdateOne {
+	stuo.mutation.Where(ps...)
+	return stuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (stuo *SopTaskUpdateOne) Select(field string, fields ...string) *SopTaskUpdateOne {
+	stuo.fields = append([]string{field}, fields...)
+	return stuo
+}
+
+// Save executes the query and returns the updated SopTask entity.
+func (stuo *SopTaskUpdateOne) Save(ctx context.Context) (*SopTask, error) {
+	stuo.defaults()
+	return withHooks(ctx, stuo.sqlSave, stuo.mutation, stuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (stuo *SopTaskUpdateOne) SaveX(ctx context.Context) *SopTask {
+	node, err := stuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (stuo *SopTaskUpdateOne) Exec(ctx context.Context) error {
+	_, err := stuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (stuo *SopTaskUpdateOne) ExecX(ctx context.Context) {
+	if err := stuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (stuo *SopTaskUpdateOne) defaults() {
+	if _, ok := stuo.mutation.UpdatedAt(); !ok {
+		v := soptask.UpdateDefaultUpdatedAt()
+		stuo.mutation.SetUpdatedAt(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (stuo *SopTaskUpdateOne) check() error {
+	if v, ok := stuo.mutation.Name(); ok {
+		if err := soptask.NameValidator(v); err != nil {
+			return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "SopTask.name": %w`, err)}
+		}
+	}
+	return nil
+}
+
+func (stuo *SopTaskUpdateOne) sqlSave(ctx context.Context) (_node *SopTask, err error) {
+	if err := stuo.check(); err != nil {
+		return _node, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(soptask.Table, soptask.Columns, sqlgraph.NewFieldSpec(soptask.FieldID, field.TypeUint64))
+	id, ok := stuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "SopTask.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := stuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, soptask.FieldID)
+		for _, f := range fields {
+			if !soptask.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != soptask.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := stuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := stuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(soptask.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := stuo.mutation.Status(); ok {
+		_spec.SetField(soptask.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := stuo.mutation.AddedStatus(); ok {
+		_spec.AddField(soptask.FieldStatus, field.TypeUint8, value)
+	}
+	if stuo.mutation.StatusCleared() {
+		_spec.ClearField(soptask.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := stuo.mutation.Name(); ok {
+		_spec.SetField(soptask.FieldName, field.TypeString, value)
+	}
+	if value, ok := stuo.mutation.BotWxidList(); ok {
+		_spec.SetField(soptask.FieldBotWxidList, field.TypeJSON, value)
+	}
+	if value, ok := stuo.mutation.AppendedBotWxidList(); ok {
+		_spec.AddModifier(func(u *sql.UpdateBuilder) {
+			sqljson.Append(u, soptask.FieldBotWxidList, value)
+		})
+	}
+	if stuo.mutation.BotWxidListCleared() {
+		_spec.ClearField(soptask.FieldBotWxidList, field.TypeJSON)
+	}
+	if value, ok := stuo.mutation.GetType(); ok {
+		_spec.SetField(soptask.FieldType, field.TypeInt, value)
+	}
+	if value, ok := stuo.mutation.AddedType(); ok {
+		_spec.AddField(soptask.FieldType, field.TypeInt, value)
+	}
+	if value, ok := stuo.mutation.PlanStartTime(); ok {
+		_spec.SetField(soptask.FieldPlanStartTime, field.TypeTime, value)
+	}
+	if stuo.mutation.PlanStartTimeCleared() {
+		_spec.ClearField(soptask.FieldPlanStartTime, field.TypeTime)
+	}
+	if value, ok := stuo.mutation.PlanEndTime(); ok {
+		_spec.SetField(soptask.FieldPlanEndTime, field.TypeTime, value)
+	}
+	if stuo.mutation.PlanEndTimeCleared() {
+		_spec.ClearField(soptask.FieldPlanEndTime, field.TypeTime)
+	}
+	if value, ok := stuo.mutation.CreatorID(); ok {
+		_spec.SetField(soptask.FieldCreatorID, field.TypeString, value)
+	}
+	if stuo.mutation.CreatorIDCleared() {
+		_spec.ClearField(soptask.FieldCreatorID, field.TypeString)
+	}
+	if value, ok := stuo.mutation.DeletedAt(); ok {
+		_spec.SetField(soptask.FieldDeletedAt, field.TypeTime, value)
+	}
+	if stuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(soptask.FieldDeletedAt, field.TypeTime)
+	}
+	if stuo.mutation.TaskStagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := stuo.mutation.RemovedTaskStagesIDs(); len(nodes) > 0 && !stuo.mutation.TaskStagesCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := stuo.mutation.TaskStagesIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   soptask.TaskStagesTable,
+			Columns: []string{soptask.TaskStagesColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(sopstage.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &SopTask{config: stuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, stuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{soptask.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	stuo.mutation.done = true
+	return _node, nil
+}

+ 9 - 0
ent/tx.go

@@ -16,6 +16,12 @@ type Tx struct {
 	config
 	// MessageRecords is the client for interacting with the MessageRecords builders.
 	MessageRecords *MessageRecordsClient
+	// SopNode is the client for interacting with the SopNode builders.
+	SopNode *SopNodeClient
+	// SopStage is the client for interacting with the SopStage builders.
+	SopStage *SopStageClient
+	// SopTask is the client for interacting with the SopTask builders.
+	SopTask *SopTaskClient
 	// Task is the client for interacting with the Task builders.
 	Task *TaskClient
 	// TaskLog is the client for interacting with the TaskLog builders.
@@ -152,6 +158,9 @@ func (tx *Tx) Client() *Client {
 
 func (tx *Tx) init() {
 	tx.MessageRecords = NewMessageRecordsClient(tx.config)
+	tx.SopNode = NewSopNodeClient(tx.config)
+	tx.SopStage = NewSopStageClient(tx.config)
+	tx.SopTask = NewSopTaskClient(tx.config)
 	tx.Task = NewTaskClient(tx.config)
 	tx.TaskLog = NewTaskLogClient(tx.config)
 }

+ 2 - 2
internal/mqs/amq/handler/amq/wxhook/send_wx.go

@@ -105,12 +105,12 @@ func (l *SendWxHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
 		}
 
 		if err != nil {
-			_, err := l.svcCtx.WX_DB.MessageRecords.UpdateOneID(v.ID).SetStatus(4).Save(ctx)
+			_, err := l.svcCtx.WX_DB.MessageRecords.UpdateOneID(v.ID).SetStatus(4).SetSendTime(time.Now()).Save(ctx)
 			if err != nil {
 				// 处理错误
 			}
 		} else {
-			_, err := l.svcCtx.WX_DB.MessageRecords.UpdateOneID(v.ID).SetStatus(3).Save(ctx)
+			_, err := l.svcCtx.WX_DB.MessageRecords.UpdateOneID(v.ID).SetStatus(3).SetSendTime(time.Now()).Save(ctx)
 			if err != nil {
 				// 处理错误
 			}

+ 162 - 0
internal/mqs/amq/handler/amq/wxhook/send_wx_on_timeout.go

@@ -0,0 +1,162 @@
+package wxhook
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/suyuan32/simple-admin-common/i18n"
+	"github.com/suyuan32/simple-admin-job/ent/custom_types"
+	"github.com/suyuan32/simple-admin-job/ent/messagerecords"
+	"github.com/suyuan32/simple-admin-job/ent/sopnode"
+	"github.com/suyuan32/simple-admin-job/ent/sopstage"
+	"github.com/suyuan32/simple-admin-job/ent/soptask"
+	"github.com/suyuan32/simple-admin-job/ent/task"
+	"github.com/suyuan32/simple-admin-job/internal/enum/taskresult"
+	"github.com/suyuan32/simple-admin-job/internal/mqs/amq/types/pattern"
+	"github.com/suyuan32/simple-admin-job/internal/utils/dberrorhandler"
+	"github.com/zeromicro/go-zero/core/errorx"
+	"github.com/zeromicro/go-zero/core/logx"
+	"time"
+
+	"github.com/hibiken/asynq"
+
+	"github.com/suyuan32/simple-admin-job/internal/mqs/amq/types/payload"
+	"github.com/suyuan32/simple-admin-job/internal/svc"
+)
+
+type SendWxOnTimeoutHandler struct {
+	svcCtx *svc.ServiceContext
+	taskId uint64
+}
+
+func NewSendWxOnTimeoutHandler(svcCtx *svc.ServiceContext) *SendWxOnTimeoutHandler {
+	task, err := svcCtx.DB.Task.Query().Where(task.PatternEQ(pattern.RecordSendWxOnTimeout)).First(context.Background())
+	if err != nil || task == nil {
+		return nil
+	}
+
+	return &SendWxOnTimeoutHandler{
+		svcCtx: svcCtx,
+		taskId: task.ID,
+	}
+}
+
+// ProcessTask if return err != nil , asynq will retry | 如果返回错误不为空则会重试
+func (l *SendWxOnTimeoutHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
+	if l.taskId == 0 {
+		logx.Errorw("failed to load task info")
+		return errorx.NewInternalError(i18n.DatabaseError)
+	}
+
+	var p payload.SendWxOnTimeoutPayload
+	if err := json.Unmarshal(t.Payload(), &p); err != nil {
+		return errors.Join(err, fmt.Errorf("failed to umarshal the payload :%s", string(t.Payload())))
+	}
+
+	startTime := time.Now()
+
+	// 查询所有 no_reply_condition 值非 0  的 sop_node 记录
+	nodes, err := l.svcCtx.WX_DB.SopNode.Query().
+		Where(sopnode.NoReplyConditionNEQ(0)).
+		Where(sopnode.HasSopStageWith(
+			sopstage.StatusEQ(1),
+			sopstage.DeletedAtIsNil(),
+			sopstage.HasSopTaskWith(
+				soptask.StatusEQ(3),
+				soptask.DeletedAtIsNil(),
+			),
+		)).
+		All(ctx)
+	fmt.Printf("---------------nodes----------------: %+v\n\n", nodes)
+	// 遍历 nodes,将其各记录 parent_id 的值存入一个新的数组 parent_nodes 中
+	//parentNodes := make([]uint64, 0)
+	//stages := make([]uint64, 0)
+	for _, node := range nodes {
+		lowerBound := startTime.Add(-time.Minute * time.Duration(node.NoReplyCondition+5))
+		upperBound := startTime.Add(-time.Minute * time.Duration(node.NoReplyCondition))
+		fmt.Printf("---------------lowerBound----------------: %+v\n\n", lowerBound)
+		fmt.Printf("---------------upperBound----------------: %+v\n\n", upperBound)
+		if node.ParentID == 0 {
+			messagesStage, _ := l.svcCtx.WX_DB.MessageRecords.Query().
+				Where(messagerecords.StatusEQ(3)).
+				Where(messagerecords.SourceTypeEQ(3)).
+				Where(messagerecords.SourceIDEQ(node.StageID)).
+				Where(messagerecords.SubSourceIDEQ(0)).
+				Where(messagerecords.SendTimeGTE(lowerBound)).
+				Where(messagerecords.SendTimeLTE(upperBound)).
+				All(ctx)
+			fmt.Printf("---------------messagesStage----------------: %+v\n\n", messagesStage)
+			for _, s := range messagesStage {
+				// 创建 MessageRecords 记录
+				for i1, c1 := range node.ActionMessage {
+					meta := custom_types.Meta{}
+					if c1.Meta != nil {
+						meta.Filename = c1.Meta.Filename
+					}
+					_, _ = l.svcCtx.WX_DB.MessageRecords.Create().
+						SetStatus(1).
+						SetBotWxid(s.BotWxid).
+						SetContactID(s.ContactID).
+						SetContactType(s.ContactType).
+						SetContactWxid(s.ContactWxid).
+						SetContentType(c1.Type).
+						SetContent(c1.Content).
+						SetMeta(meta).
+						SetSourceType(4).
+						SetSourceID(node.ID).
+						SetSubSourceID(uint64(i1)).
+						Save(ctx)
+				}
+			}
+		} else {
+			messagesNode, _ := l.svcCtx.WX_DB.MessageRecords.Query().
+				Where(messagerecords.StatusEQ(3)).
+				Where(messagerecords.SourceTypeEQ(4)).
+				Where(messagerecords.SourceIDIn(node.ParentID)).
+				Where(messagerecords.SubSourceIDEQ(0)).
+				Where(messagerecords.SendTimeGTE(lowerBound)).
+				Where(messagerecords.SendTimeLTE(upperBound)).
+				All(ctx)
+
+			for _, n := range messagesNode {
+				// 创建 MessageRecords 记录
+				for i2, c2 := range node.ActionMessage {
+					meta := custom_types.Meta{}
+					if c2.Meta != nil {
+						meta.Filename = c2.Meta.Filename
+					}
+					_, _ = l.svcCtx.WX_DB.MessageRecords.Create().
+						SetStatus(1).
+						SetBotWxid(n.BotWxid).
+						SetContactID(n.ContactID).
+						SetContactType(n.ContactType).
+						SetContactWxid(n.ContactWxid).
+						SetContentType(c2.Type).
+						SetContent(c2.Content).
+						SetMeta(meta).
+						SetSourceType(4).
+						SetSourceID(node.ID).
+						SetSubSourceID(uint64(i2)).
+						Save(ctx)
+				}
+			}
+		}
+	}
+
+	finishTime := time.Now()
+
+	err = l.svcCtx.DB.TaskLog.Create().
+		SetStartedAt(startTime).
+		SetFinishedAt(finishTime).
+		SetResult(taskresult.Success).
+		SetTasksID(l.taskId).
+		Exec(context.Background())
+
+	if err != nil {
+		return dberrorhandler.DefaultEntError(logx.WithContext(context.Background()), err,
+			"failed to save task log to database")
+	}
+
+	return nil
+}

+ 2 - 0
internal/mqs/amq/task/mqtask/register.go

@@ -19,5 +19,7 @@ func (m *MQTask) Register() {
 
 	mux.Handle(pattern.RecordSendWx, wxhook.NewSendWxHandler(m.svcCtx))
 
+	mux.Handle(pattern.RecordSendWxOnTimeout, wxhook.NewSendWxOnTimeoutHandler(m.svcCtx))
+
 	m.mux = mux
 }

+ 1 - 0
internal/mqs/amq/types/pattern/pattern.go

@@ -4,3 +4,4 @@ package pattern
 const RecordHelloWorld = "hello_world"
 const RecordSayMorning = "say_morning"
 const RecordSendWx = "send_wx"
+const RecordSendWxOnTimeout = "send_wx_on_timeout"

+ 3 - 0
internal/mqs/amq/types/payload/payload.go

@@ -24,3 +24,6 @@ type WxList struct {
 	Wxid     string `json:"wxid"`
 	Nickname string `json:"nickname"`
 }
+
+type SendWxOnTimeoutPayload struct {
+}