Browse Source

增加标签管理相关功能,以及标签与联系人的关联表

boweniac 9 tháng trước cách đây
mục cha
commit
92b6a70504
88 tập tin đã thay đổi với 15188 bổ sung212 xóa
  1. 1 0
      .gitignore
  2. 3 1
      desc/all.api
  3. 0 1
      desc/base.api
  4. 6 55
      desc/wechat/contact.api
  5. 101 0
      desc/wechat/label.api
  6. 186 0
      desc/wechat/label_relationship.api
  7. 513 18
      ent/client.go
  8. 27 1
      ent/contact.go
  9. 31 0
      ent/contact/contact.go
  10. 24 0
      ent/contact/where.go
  11. 32 0
      ent/contact_create.go
  12. 92 11
      ent/contact_query.go
  13. 163 0
      ent/contact_update.go
  14. 9 3
      ent/ent.go
  15. 36 0
      ent/hook/hook.go
  16. 90 0
      ent/intercept/intercept.go
  17. 220 0
      ent/label.go
  18. 173 0
      ent/label/label.go
  19. 579 0
      ent/label/where.go
  20. 1157 0
      ent/label_create.go
  21. 88 0
      ent/label_delete.go
  22. 607 0
      ent/label_query.go
  23. 759 0
      ent/label_update.go
  24. 207 0
      ent/labelrelationship.go
  25. 159 0
      ent/labelrelationship/labelrelationship.go
  26. 367 0
      ent/labelrelationship/where.go
  27. 909 0
      ent/labelrelationship_create.go
  28. 88 0
      ent/labelrelationship_delete.go
  29. 680 0
      ent/labelrelationship_query.go
  30. 618 0
      ent/labelrelationship_update.go
  31. 125 0
      ent/message.go
  32. 72 0
      ent/message/message.go
  33. 289 0
      ent/message/where.go
  34. 619 0
      ent/message_create.go
  35. 88 0
      ent/message_delete.go
  36. 526 0
      ent/message_query.go
  37. 295 0
      ent/message_update.go
  38. 95 0
      ent/migrate/schema.go
  39. 2451 37
      ent/mutation.go
  40. 255 3
      ent/pagination.go
  41. 9 0
      ent/predicate/predicate.go
  42. 95 0
      ent/runtime/runtime.go
  43. 4 1
      ent/schema/contact.go
  44. 59 0
      ent/schema/label.go
  45. 60 0
      ent/schema/label_relationship.go
  46. 384 0
      ent/set_not_nil.go
  47. 3 1
      ent/template/pagination.tmpl
  48. 9 0
      ent/tx.go
  49. 4 0
      go.sum
  50. 4 4
      internal/handler/Contact/create_contact_handler.go
  51. 4 4
      internal/handler/Contact/delete_contact_handler.go
  52. 4 4
      internal/handler/Contact/get_contact_by_id_handler.go
  53. 4 4
      internal/handler/Contact/get_contact_list_handler.go
  54. 4 4
      internal/handler/Contact/update_contact_handler.go
  55. 44 0
      internal/handler/label/create_label_handler.go
  56. 44 0
      internal/handler/label/delete_label_handler.go
  57. 44 0
      internal/handler/label/get_label_by_id_handler.go
  58. 44 0
      internal/handler/label/get_label_contacts_handler.go
  59. 44 0
      internal/handler/label/get_label_list_handler.go
  60. 44 0
      internal/handler/label/get_label_select_list_handler.go
  61. 44 0
      internal/handler/label/update_label_handler.go
  62. 44 0
      internal/handler/label_relationship/create_label_relationship_handler.go
  63. 44 0
      internal/handler/label_relationship/delete_label_relationship_handler.go
  64. 44 0
      internal/handler/label_relationship/get_label_relationship_by_id_handler.go
  65. 44 0
      internal/handler/label_relationship/get_label_relationship_list_handler.go
  66. 44 0
      internal/handler/label_relationship/update_label_relationship_handler.go
  67. 44 0
      internal/handler/label_relationship/update_label_relationships_handler.go
  68. 91 6
      internal/handler/routes.go
  69. 1 1
      internal/logic/Contact/create_contact_logic.go
  70. 1 1
      internal/logic/Contact/delete_contact_logic.go
  71. 1 1
      internal/logic/Contact/get_contact_by_id_logic.go
  72. 64 26
      internal/logic/Contact/get_contact_list_logic.go
  73. 1 1
      internal/logic/Contact/update_contact_logic.go
  74. 124 0
      internal/logic/base/init_api_data.go
  75. 44 0
      internal/logic/label/create_label_logic.go
  76. 37 0
      internal/logic/label/delete_label_logic.go
  77. 56 0
      internal/logic/label/get_label_by_id_logic.go
  78. 100 0
      internal/logic/label/get_label_contacts_logic.go
  79. 101 0
      internal/logic/label/get_label_list_logic.go
  80. 61 0
      internal/logic/label/get_label_select_list_logic.go
  81. 44 0
      internal/logic/label/update_label_logic.go
  82. 41 0
      internal/logic/label_relationship/create_label_relationship_logic.go
  83. 37 0
      internal/logic/label_relationship/delete_label_relationship_logic.go
  84. 53 0
      internal/logic/label_relationship/get_label_relationship_by_id_logic.go
  85. 58 0
      internal/logic/label_relationship/get_label_relationship_list_logic.go
  86. 41 0
      internal/logic/label_relationship/update_label_relationship_logic.go
  87. 103 0
      internal/logic/label_relationship/update_label_relationships_logic.go
  88. 170 24
      internal/types/types.go

+ 1 - 0
.gitignore

@@ -31,3 +31,4 @@
 *_api
 *_rpc
 /wechat-api
+/etc/wechat.yaml

+ 3 - 1
desc/all.api

@@ -3,4 +3,6 @@ import "./wechat/server.api"
 import "./wechat/wx.api"
 import "./wechat/wxhook.api"
 import "./wechat/contact.api"
-import "./wechat/message.api"
+import "./wechat/message.api"
+import "./wechat/label.api"
+import "./wechat/label_relationship.api"

+ 0 - 1
desc/base.api

@@ -206,7 +206,6 @@ type BaseUUIDInfo {
     UpdatedAt *int64     `json:"updatedAt,optional"`
 }
 
-
 @server(
 	group: base
 )

+ 6 - 55
desc/wechat/contact.api

@@ -1,59 +1,7 @@
 import "../base.api"
+import "./label_relationship.api"
 
 type (
-    // The response data of contact information | Contact信息
-    ContactInfo {
-        BaseIDInfo
-
-        // Status 1: normal 2: ban | 状态 1 正常 2 禁用 
-        Status  *uint8 `json:"status,optional"`
-
-        // 属主微信id 
-        WxWxid  *string `json:"wxWxid,optional"`
-
-        // 联系人类型:1好友,2群组,3公众号,4企业微信联系人 
-        Type  *int `json:"type,optional"`
-
-        // 微信id 公众号微信ID 
-        Wxid  *string `json:"wxid,optional"`
-
-        // 微信账号 
-        Account  *string `json:"account,optional"`
-
-        // 微信昵称 群备注名称 
-        Nickname  *string `json:"nickname,optional"`
-
-        // 备注名 
-        Markname  *string `json:"markname,optional"`
-
-        // 头像 
-        Headimg  *string `json:"headimg,optional"`
-
-        // 性别 0未知 1男 2女 
-        Sex  *int `json:"sex,optional"`
-
-        // 星标 65/67=星标 1/3=未星标 
-        Starrole  *string `json:"starrole,optional"`
-
-        // 不让他看我的朋友圈 0可以看 1不让看 
-        Dontseeit  *int `json:"dontseeit,optional"`
-
-        // 不看他的朋友圈 0可以看 1不看 1=开启了不看他 128/129=仅聊天 
-        Dontseeme  *int `json:"dontseeme,optional"`
-
-        // 所属标签id清单,多开会用逗号隔开 
-        Lag  *string `json:"lag,optional"`
-
-        // 群组id 
-        Gid  *string `json:"gid,optional"`
-
-        // 群组名称 
-        Gname  *string `json:"gname,optional"`
-
-        // v3数据 
-        V3  *string `json:"v3,optional"`
-    }
-
     // The response data of contact list | Contact列表数据
     ContactListResp {
         BaseDataInfo
@@ -74,7 +22,10 @@ type (
     ContactListReq {
         PageInfo
 
-        // 属主微信id 
+        // Label ID list | 标签ID列表
+        LabelIDs []uint64 `json:"labelIDs,optional"`
+
+        // 属主微信id
         WxWxid  *string `json:"wxWxid,optional"`
 
         // 微信id 公众号微信ID 
@@ -95,7 +46,7 @@ type (
 
 @server(
     jwt: Auth
-    group: Contact
+    group: contact
     middleware: Authority
 )
 

+ 101 - 0
desc/wechat/label.api

@@ -0,0 +1,101 @@
+import "../base.api"
+import "./label_relationship.api"
+
+type (
+
+    // The response data of label list | Label列表数据
+    LabelSelectListResp {
+        BaseDataInfo
+
+        // Label list data | Label列表数据
+        Data []LabelSelectListInfo `json:"data"`
+    }
+
+    // The response data of label list | Label列表数据
+    LabelListResp {
+        BaseDataInfo
+
+        // Label list data | Label列表数据
+        Data LabelListInfo `json:"data"`
+    }
+
+    // Label list data | Label列表数据
+    LabelListInfo {
+        BaseListInfo
+
+        // The API list data | Label列表数据
+        Data  []LabelInfo  `json:"data"`
+    }
+
+    // Get label list request params | Label列表请求参数
+    LabelListReq {
+        PageInfo
+
+        // Label ID list | Label ID列表
+        LabelIDs  []uint64 `json:"labelIDs,optional"`
+
+        // 标签类型:1好友,2群组,3公众号,4企业微信联系人
+        Type  *int `json:"type,optional"`
+
+        // 标签名称
+        Name  *string `json:"name,optional"`
+
+        // 标签来源:1后台创建 2个微同步
+        From  *int `json:"from,optional"`
+
+        // 标签模式:1动态 2静态
+        Mode  *int `json:"mode,optional"`
+    }
+
+    // Label information response | Label信息返回体
+    LabelInfoResp {
+        BaseDataInfo
+
+        // Label information | Label数据
+        Data LabelInfo `json:"data"`
+    }
+
+    LabelSelectListInfo {
+        // label
+        Label  *string `json:"label,optional"`
+
+        // value
+        Value  *uint64 `json:"value,optional"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: label
+    middleware: Authority
+)
+
+service Wechat {
+    // Create label information | 创建Label
+    @handler createLabel
+    post /label/create (LabelInfo) returns (BaseMsgResp)
+
+    // Update label information | 更新Label
+    @handler updateLabel
+    post /label/update (LabelInfo) returns (BaseMsgResp)
+
+    // Delete label information | 删除Label信息
+    @handler deleteLabel
+    post /label/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get label list | 获取Label列表
+    @handler getLabelList
+    post /label/list (LabelListReq) returns (LabelListResp)
+
+    // Get label select list | 获取Label列表
+    @handler getLabelSelectList
+    post /label/select_list (LabelListReq) returns (LabelSelectListResp)
+
+    // Get label contacts | 获取Label联系人
+    @handler getLabelContacts
+    post /label/contacts (LabelListReq) returns (LabelListResp)
+
+    // Get label by ID | 通过ID获取Label
+    @handler getLabelById
+    post /label (IDReq) returns (LabelInfoResp)
+}

+ 186 - 0
desc/wechat/label_relationship.api

@@ -0,0 +1,186 @@
+import "../base.api"
+
+type (
+    // ContactLabelList | Contact标签列表
+    ContactLabelList {
+        // label
+        Label  *string `json:"label,optional"`
+
+        // value
+        Value  *uint64 `json:"value,optional"`
+    }
+
+    // The response data of contact information | Contact信息
+    ContactInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用
+        Status  *uint8 `json:"status,optional"`
+
+        // 属主微信id
+        WxWxid  *string `json:"wxWxid,optional"`
+
+        // 联系人类型:1好友,2群组,3公众号,4企业微信联系人
+        Type  *int `json:"type,optional"`
+
+        // 微信id 公众号微信ID
+        Wxid  *string `json:"wxid,optional"`
+
+        // 微信账号
+        Account  *string `json:"account,optional"`
+
+        // 微信昵称 群备注名称
+        Nickname  *string `json:"nickname,optional"`
+
+        // 备注名
+        Markname  *string `json:"markname,optional"`
+
+        // 头像
+        Headimg  *string `json:"headimg,optional"`
+
+        // 性别 0未知 1男 2女
+        Sex  *int `json:"sex,optional"`
+
+        // 星标 65/67=星标 1/3=未星标
+        Starrole  *string `json:"starrole,optional"`
+
+        // 不让他看我的朋友圈 0可以看 1不让看
+        Dontseeit  *int `json:"dontseeit,optional"`
+
+        // 不看他的朋友圈 0可以看 1不看 1=开启了不看他 128/129=仅聊天
+        Dontseeme  *int `json:"dontseeme,optional"`
+
+        // 所属标签id清单,多开会用逗号隔开
+        Lag  *string `json:"lag,optional"`
+
+        // 群组id
+        Gid  *string `json:"gid,optional"`
+
+        // 群组名称
+        Gname  *string `json:"gname,optional"`
+
+        // v3数据
+        V3  *string `json:"v3,optional"`
+
+        // Label Relationships | 标签关系
+        LabelRelationships []ContactLabelList `json:"labelRelationships,optional"`
+    }
+    // The response data of label information | Label信息
+    LabelInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用
+        Status  *uint8 `json:"status,optional"`
+
+        // 标签类型:1好友,2群组,3公众号,4企业微信联系人
+        Type  *int `json:"type,optional"`
+
+        // 标签名称
+        Name  *string `json:"name,optional"`
+
+        // 标签来源:1后台创建 2个微同步
+        From  *int `json:"from,optional"`
+
+        // 标签模式:1动态 2静态
+        Mode  *int `json:"mode,optional"`
+
+        // 标签的触达条件
+        Conditions  *string `json:"conditions,optional"`
+
+        // Label Relationships | 标签关系
+        LabelRelationships []LabelRelationshipInfo `json:"labelRelationships,optional"`
+    }
+    // The response data of label relationship information | LabelRelationship信息
+    LabelRelationshipInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用
+        Status  *uint8 `json:"status,optional"`
+
+        // 标签 ID
+        LabelId  *uint64 `json:"labelId,optional"`
+
+        // 联系人 ID
+        ContactId  *uint64 `json:"contactId,optional"`
+
+        // Contact information | 联系人信息
+        Contact ContactInfo `json:"contact,optional"`
+
+        // Label information | 标签信息
+        Label LabelInfo `json:"label,optional"`
+    }
+    // The response data of label relationship information | LabelRelationship信息
+    LabelRelationshipsInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用
+        Status  *uint8 `json:"status,optional"`
+
+        // 标签 ID
+        LabelIds  []uint64 `json:"labelIds,optional"`
+
+        // 联系人 ID
+        ContactId  *uint64 `json:"contactId,optional"`
+    }
+
+    // The response data of label relationship list | LabelRelationship列表数据
+    LabelRelationshipListResp {
+        BaseDataInfo
+
+        // LabelRelationship list data | LabelRelationship列表数据
+        Data LabelRelationshipListInfo `json:"data"`
+    }
+
+    // LabelRelationship list data | LabelRelationship列表数据
+    LabelRelationshipListInfo {
+        BaseListInfo
+
+        // The API list data | LabelRelationship列表数据
+        Data  []LabelRelationshipInfo  `json:"data"`
+    }
+
+    // Get label relationship list request params | LabelRelationship列表请求参数
+    LabelRelationshipListReq {
+        PageInfo
+    }
+
+    // LabelRelationship information response | LabelRelationship信息返回体
+    LabelRelationshipInfoResp {
+        BaseDataInfo
+
+        // LabelRelationship information | LabelRelationship数据
+        Data LabelRelationshipInfo `json:"data"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: label_relationship
+    middleware: Authority
+)
+
+service Wechat {
+    // Create label relationship information | 创建LabelRelationship
+    @handler createLabelRelationship
+    post /label_relationship/create (LabelRelationshipInfo) returns (BaseMsgResp)
+
+    // Update label relationship information | 更新LabelRelationship
+    @handler updateLabelRelationship
+    post /label_relationship/update (LabelRelationshipInfo) returns (BaseMsgResp)
+
+    // Update label relationships information | 批量更新LabelRelationship
+    @handler updateLabelRelationships
+    post /label_relationship/update_contact_labels (LabelRelationshipsInfo) returns (BaseMsgResp)
+
+    // Delete label relationship information | 删除LabelRelationship信息
+    @handler deleteLabelRelationship
+    post /label_relationship/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get label relationship list | 获取LabelRelationship列表
+    @handler getLabelRelationshipList
+    post /label_relationship/list (LabelRelationshipListReq) returns (LabelRelationshipListResp)
+
+    // Get label relationship by ID | 通过ID获取LabelRelationship
+    @handler getLabelRelationshipById
+    post /label_relationship (IDReq) returns (LabelRelationshipInfoResp)
+}

+ 513 - 18
ent/client.go

@@ -12,6 +12,9 @@ import (
 	"wechat-api/ent/migrate"
 
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
 
@@ -30,6 +33,12 @@ type Client struct {
 	Schema *migrate.Schema
 	// Contact is the client for interacting with the Contact builders.
 	Contact *ContactClient
+	// Label is the client for interacting with the Label builders.
+	Label *LabelClient
+	// LabelRelationship is the client for interacting with the LabelRelationship builders.
+	LabelRelationship *LabelRelationshipClient
+	// Message is the client for interacting with the Message builders.
+	Message *MessageClient
 	// Server is the client for interacting with the Server builders.
 	Server *ServerClient
 	// Wx is the client for interacting with the Wx builders.
@@ -46,6 +55,9 @@ func NewClient(opts ...Option) *Client {
 func (c *Client) init() {
 	c.Schema = migrate.NewSchema(c.driver)
 	c.Contact = NewContactClient(c.config)
+	c.Label = NewLabelClient(c.config)
+	c.LabelRelationship = NewLabelRelationshipClient(c.config)
+	c.Message = NewMessageClient(c.config)
 	c.Server = NewServerClient(c.config)
 	c.Wx = NewWxClient(c.config)
 }
@@ -138,11 +150,14 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
 	cfg := c.config
 	cfg.driver = tx
 	return &Tx{
-		ctx:     ctx,
-		config:  cfg,
-		Contact: NewContactClient(cfg),
-		Server:  NewServerClient(cfg),
-		Wx:      NewWxClient(cfg),
+		ctx:               ctx,
+		config:            cfg,
+		Contact:           NewContactClient(cfg),
+		Label:             NewLabelClient(cfg),
+		LabelRelationship: NewLabelRelationshipClient(cfg),
+		Message:           NewMessageClient(cfg),
+		Server:            NewServerClient(cfg),
+		Wx:                NewWxClient(cfg),
 	}, nil
 }
 
@@ -160,11 +175,14 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
 	cfg := c.config
 	cfg.driver = &txDriver{tx: tx, drv: c.driver}
 	return &Tx{
-		ctx:     ctx,
-		config:  cfg,
-		Contact: NewContactClient(cfg),
-		Server:  NewServerClient(cfg),
-		Wx:      NewWxClient(cfg),
+		ctx:               ctx,
+		config:            cfg,
+		Contact:           NewContactClient(cfg),
+		Label:             NewLabelClient(cfg),
+		LabelRelationship: NewLabelRelationshipClient(cfg),
+		Message:           NewMessageClient(cfg),
+		Server:            NewServerClient(cfg),
+		Wx:                NewWxClient(cfg),
 	}, nil
 }
 
@@ -193,17 +211,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.Contact.Use(hooks...)
-	c.Server.Use(hooks...)
-	c.Wx.Use(hooks...)
+	for _, n := range []interface{ Use(...Hook) }{
+		c.Contact, c.Label, c.LabelRelationship, c.Message, c.Server, c.Wx,
+	} {
+		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.Contact.Intercept(interceptors...)
-	c.Server.Intercept(interceptors...)
-	c.Wx.Intercept(interceptors...)
+	for _, n := range []interface{ Intercept(...Interceptor) }{
+		c.Contact, c.Label, c.LabelRelationship, c.Message, c.Server, c.Wx,
+	} {
+		n.Intercept(interceptors...)
+	}
 }
 
 // Mutate implements the ent.Mutator interface.
@@ -211,6 +233,12 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
 	switch m := m.(type) {
 	case *ContactMutation:
 		return c.Contact.mutate(ctx, m)
+	case *LabelMutation:
+		return c.Label.mutate(ctx, m)
+	case *LabelRelationshipMutation:
+		return c.LabelRelationship.mutate(ctx, m)
+	case *MessageMutation:
+		return c.Message.mutate(ctx, m)
 	case *ServerMutation:
 		return c.Server.mutate(ctx, m)
 	case *WxMutation:
@@ -328,6 +356,22 @@ func (c *ContactClient) GetX(ctx context.Context, id uint64) *Contact {
 	return obj
 }
 
+// QueryContactRelationships queries the contact_relationships edge of a Contact.
+func (c *ContactClient) QueryContactRelationships(co *Contact) *LabelRelationshipQuery {
+	query := (&LabelRelationshipClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := co.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(contact.Table, contact.FieldID, id),
+			sqlgraph.To(labelrelationship.Table, labelrelationship.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, contact.ContactRelationshipsTable, contact.ContactRelationshipsColumn),
+		)
+		fromV = sqlgraph.Neighbors(co.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
 // Hooks returns the client hooks.
 func (c *ContactClient) Hooks() []Hook {
 	hooks := c.hooks.Contact
@@ -355,6 +399,457 @@ func (c *ContactClient) mutate(ctx context.Context, m *ContactMutation) (Value,
 	}
 }
 
+// LabelClient is a client for the Label schema.
+type LabelClient struct {
+	config
+}
+
+// NewLabelClient returns a client for the Label from the given config.
+func NewLabelClient(c config) *LabelClient {
+	return &LabelClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `label.Hooks(f(g(h())))`.
+func (c *LabelClient) Use(hooks ...Hook) {
+	c.hooks.Label = append(c.hooks.Label, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `label.Intercept(f(g(h())))`.
+func (c *LabelClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Label = append(c.inters.Label, interceptors...)
+}
+
+// Create returns a builder for creating a Label entity.
+func (c *LabelClient) Create() *LabelCreate {
+	mutation := newLabelMutation(c.config, OpCreate)
+	return &LabelCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Label entities.
+func (c *LabelClient) CreateBulk(builders ...*LabelCreate) *LabelCreateBulk {
+	return &LabelCreateBulk{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 *LabelClient) MapCreateBulk(slice any, setFunc func(*LabelCreate, int)) *LabelCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &LabelCreateBulk{err: fmt.Errorf("calling to LabelClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*LabelCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &LabelCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Label.
+func (c *LabelClient) Update() *LabelUpdate {
+	mutation := newLabelMutation(c.config, OpUpdate)
+	return &LabelUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *LabelClient) UpdateOne(l *Label) *LabelUpdateOne {
+	mutation := newLabelMutation(c.config, OpUpdateOne, withLabel(l))
+	return &LabelUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *LabelClient) UpdateOneID(id uint64) *LabelUpdateOne {
+	mutation := newLabelMutation(c.config, OpUpdateOne, withLabelID(id))
+	return &LabelUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Label.
+func (c *LabelClient) Delete() *LabelDelete {
+	mutation := newLabelMutation(c.config, OpDelete)
+	return &LabelDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *LabelClient) DeleteOne(l *Label) *LabelDeleteOne {
+	return c.DeleteOneID(l.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *LabelClient) DeleteOneID(id uint64) *LabelDeleteOne {
+	builder := c.Delete().Where(label.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &LabelDeleteOne{builder}
+}
+
+// Query returns a query builder for Label.
+func (c *LabelClient) Query() *LabelQuery {
+	return &LabelQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeLabel},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Label entity by its id.
+func (c *LabelClient) Get(ctx context.Context, id uint64) (*Label, error) {
+	return c.Query().Where(label.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *LabelClient) GetX(ctx context.Context, id uint64) *Label {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QueryLabelRelationships queries the label_relationships edge of a Label.
+func (c *LabelClient) QueryLabelRelationships(l *Label) *LabelRelationshipQuery {
+	query := (&LabelRelationshipClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := l.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(label.Table, label.FieldID, id),
+			sqlgraph.To(labelrelationship.Table, labelrelationship.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, label.LabelRelationshipsTable, label.LabelRelationshipsColumn),
+		)
+		fromV = sqlgraph.Neighbors(l.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *LabelClient) Hooks() []Hook {
+	hooks := c.hooks.Label
+	return append(hooks[:len(hooks):len(hooks)], label.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *LabelClient) Interceptors() []Interceptor {
+	inters := c.inters.Label
+	return append(inters[:len(inters):len(inters)], label.Interceptors[:]...)
+}
+
+func (c *LabelClient) mutate(ctx context.Context, m *LabelMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&LabelCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&LabelUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&LabelUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&LabelDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Label mutation op: %q", m.Op())
+	}
+}
+
+// LabelRelationshipClient is a client for the LabelRelationship schema.
+type LabelRelationshipClient struct {
+	config
+}
+
+// NewLabelRelationshipClient returns a client for the LabelRelationship from the given config.
+func NewLabelRelationshipClient(c config) *LabelRelationshipClient {
+	return &LabelRelationshipClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `labelrelationship.Hooks(f(g(h())))`.
+func (c *LabelRelationshipClient) Use(hooks ...Hook) {
+	c.hooks.LabelRelationship = append(c.hooks.LabelRelationship, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `labelrelationship.Intercept(f(g(h())))`.
+func (c *LabelRelationshipClient) Intercept(interceptors ...Interceptor) {
+	c.inters.LabelRelationship = append(c.inters.LabelRelationship, interceptors...)
+}
+
+// Create returns a builder for creating a LabelRelationship entity.
+func (c *LabelRelationshipClient) Create() *LabelRelationshipCreate {
+	mutation := newLabelRelationshipMutation(c.config, OpCreate)
+	return &LabelRelationshipCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of LabelRelationship entities.
+func (c *LabelRelationshipClient) CreateBulk(builders ...*LabelRelationshipCreate) *LabelRelationshipCreateBulk {
+	return &LabelRelationshipCreateBulk{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 *LabelRelationshipClient) MapCreateBulk(slice any, setFunc func(*LabelRelationshipCreate, int)) *LabelRelationshipCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &LabelRelationshipCreateBulk{err: fmt.Errorf("calling to LabelRelationshipClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*LabelRelationshipCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &LabelRelationshipCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for LabelRelationship.
+func (c *LabelRelationshipClient) Update() *LabelRelationshipUpdate {
+	mutation := newLabelRelationshipMutation(c.config, OpUpdate)
+	return &LabelRelationshipUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *LabelRelationshipClient) UpdateOne(lr *LabelRelationship) *LabelRelationshipUpdateOne {
+	mutation := newLabelRelationshipMutation(c.config, OpUpdateOne, withLabelRelationship(lr))
+	return &LabelRelationshipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *LabelRelationshipClient) UpdateOneID(id uint64) *LabelRelationshipUpdateOne {
+	mutation := newLabelRelationshipMutation(c.config, OpUpdateOne, withLabelRelationshipID(id))
+	return &LabelRelationshipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for LabelRelationship.
+func (c *LabelRelationshipClient) Delete() *LabelRelationshipDelete {
+	mutation := newLabelRelationshipMutation(c.config, OpDelete)
+	return &LabelRelationshipDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *LabelRelationshipClient) DeleteOne(lr *LabelRelationship) *LabelRelationshipDeleteOne {
+	return c.DeleteOneID(lr.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *LabelRelationshipClient) DeleteOneID(id uint64) *LabelRelationshipDeleteOne {
+	builder := c.Delete().Where(labelrelationship.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &LabelRelationshipDeleteOne{builder}
+}
+
+// Query returns a query builder for LabelRelationship.
+func (c *LabelRelationshipClient) Query() *LabelRelationshipQuery {
+	return &LabelRelationshipQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeLabelRelationship},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a LabelRelationship entity by its id.
+func (c *LabelRelationshipClient) Get(ctx context.Context, id uint64) (*LabelRelationship, error) {
+	return c.Query().Where(labelrelationship.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *LabelRelationshipClient) GetX(ctx context.Context, id uint64) *LabelRelationship {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QueryContacts queries the contacts edge of a LabelRelationship.
+func (c *LabelRelationshipClient) QueryContacts(lr *LabelRelationship) *ContactQuery {
+	query := (&ContactClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := lr.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(labelrelationship.Table, labelrelationship.FieldID, id),
+			sqlgraph.To(contact.Table, contact.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, labelrelationship.ContactsTable, labelrelationship.ContactsColumn),
+		)
+		fromV = sqlgraph.Neighbors(lr.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// QueryLabels queries the labels edge of a LabelRelationship.
+func (c *LabelRelationshipClient) QueryLabels(lr *LabelRelationship) *LabelQuery {
+	query := (&LabelClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := lr.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(labelrelationship.Table, labelrelationship.FieldID, id),
+			sqlgraph.To(label.Table, label.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, labelrelationship.LabelsTable, labelrelationship.LabelsColumn),
+		)
+		fromV = sqlgraph.Neighbors(lr.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *LabelRelationshipClient) Hooks() []Hook {
+	hooks := c.hooks.LabelRelationship
+	return append(hooks[:len(hooks):len(hooks)], labelrelationship.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *LabelRelationshipClient) Interceptors() []Interceptor {
+	inters := c.inters.LabelRelationship
+	return append(inters[:len(inters):len(inters)], labelrelationship.Interceptors[:]...)
+}
+
+func (c *LabelRelationshipClient) mutate(ctx context.Context, m *LabelRelationshipMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&LabelRelationshipCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&LabelRelationshipUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&LabelRelationshipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&LabelRelationshipDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown LabelRelationship mutation op: %q", m.Op())
+	}
+}
+
+// MessageClient is a client for the Message schema.
+type MessageClient struct {
+	config
+}
+
+// NewMessageClient returns a client for the Message from the given config.
+func NewMessageClient(c config) *MessageClient {
+	return &MessageClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `message.Hooks(f(g(h())))`.
+func (c *MessageClient) Use(hooks ...Hook) {
+	c.hooks.Message = append(c.hooks.Message, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `message.Intercept(f(g(h())))`.
+func (c *MessageClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Message = append(c.inters.Message, interceptors...)
+}
+
+// Create returns a builder for creating a Message entity.
+func (c *MessageClient) Create() *MessageCreate {
+	mutation := newMessageMutation(c.config, OpCreate)
+	return &MessageCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Message entities.
+func (c *MessageClient) CreateBulk(builders ...*MessageCreate) *MessageCreateBulk {
+	return &MessageCreateBulk{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 *MessageClient) MapCreateBulk(slice any, setFunc func(*MessageCreate, int)) *MessageCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &MessageCreateBulk{err: fmt.Errorf("calling to MessageClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*MessageCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &MessageCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Message.
+func (c *MessageClient) Update() *MessageUpdate {
+	mutation := newMessageMutation(c.config, OpUpdate)
+	return &MessageUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *MessageClient) UpdateOne(m *Message) *MessageUpdateOne {
+	mutation := newMessageMutation(c.config, OpUpdateOne, withMessage(m))
+	return &MessageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *MessageClient) UpdateOneID(id int) *MessageUpdateOne {
+	mutation := newMessageMutation(c.config, OpUpdateOne, withMessageID(id))
+	return &MessageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Message.
+func (c *MessageClient) Delete() *MessageDelete {
+	mutation := newMessageMutation(c.config, OpDelete)
+	return &MessageDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *MessageClient) DeleteOne(m *Message) *MessageDeleteOne {
+	return c.DeleteOneID(m.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *MessageClient) DeleteOneID(id int) *MessageDeleteOne {
+	builder := c.Delete().Where(message.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &MessageDeleteOne{builder}
+}
+
+// Query returns a query builder for Message.
+func (c *MessageClient) Query() *MessageQuery {
+	return &MessageQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeMessage},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Message entity by its id.
+func (c *MessageClient) Get(ctx context.Context, id int) (*Message, error) {
+	return c.Query().Where(message.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *MessageClient) GetX(ctx context.Context, id int) *Message {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// Hooks returns the client hooks.
+func (c *MessageClient) Hooks() []Hook {
+	return c.hooks.Message
+}
+
+// Interceptors returns the client interceptors.
+func (c *MessageClient) Interceptors() []Interceptor {
+	return c.inters.Message
+}
+
+func (c *MessageClient) mutate(ctx context.Context, m *MessageMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&MessageCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&MessageUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&MessageUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&MessageDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Message mutation op: %q", m.Op())
+	}
+}
+
 // ServerClient is a client for the Server schema.
 type ServerClient struct {
 	config
@@ -660,10 +1155,10 @@ func (c *WxClient) mutate(ctx context.Context, m *WxMutation) (Value, error) {
 // hooks and interceptors per client, for fast access.
 type (
 	hooks struct {
-		Contact, Server, Wx []ent.Hook
+		Contact, Label, LabelRelationship, Message, Server, Wx []ent.Hook
 	}
 	inters struct {
-		Contact, Server, Wx []ent.Interceptor
+		Contact, Label, LabelRelationship, Message, Server, Wx []ent.Interceptor
 	}
 )
 

+ 27 - 1
ent/contact.go

@@ -54,10 +54,31 @@ type Contact struct {
 	// 群组名称
 	Gname string `json:"gname,omitempty"`
 	// v3数据
-	V3           string `json:"v3,omitempty"`
+	V3 string `json:"v3,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the ContactQuery when eager-loading is set.
+	Edges        ContactEdges `json:"edges"`
 	selectValues sql.SelectValues
 }
 
+// ContactEdges holds the relations/edges for other nodes in the graph.
+type ContactEdges struct {
+	// ContactRelationships holds the value of the contact_relationships edge.
+	ContactRelationships []*LabelRelationship `json:"contact_relationships,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [1]bool
+}
+
+// ContactRelationshipsOrErr returns the ContactRelationships value or an error if the edge
+// was not loaded in eager-loading.
+func (e ContactEdges) ContactRelationshipsOrErr() ([]*LabelRelationship, error) {
+	if e.loadedTypes[0] {
+		return e.ContactRelationships, nil
+	}
+	return nil, &NotLoadedError{edge: "contact_relationships"}
+}
+
 // scanValues returns the types for scanning values from sql.Rows.
 func (*Contact) scanValues(columns []string) ([]any, error) {
 	values := make([]any, len(columns))
@@ -217,6 +238,11 @@ func (c *Contact) Value(name string) (ent.Value, error) {
 	return c.selectValues.Get(name)
 }
 
+// QueryContactRelationships queries the "contact_relationships" edge of the Contact entity.
+func (c *Contact) QueryContactRelationships() *LabelRelationshipQuery {
+	return NewContactClient(c.config).QueryContactRelationships(c)
+}
+
 // Update returns a builder for updating this Contact.
 // Note that you need to call Contact.Unwrap() before calling this method if this Contact
 // was returned from a transaction, and the transaction was committed or rolled back.

+ 31 - 0
ent/contact/contact.go

@@ -7,6 +7,7 @@ import (
 
 	"entgo.io/ent"
 	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
 )
 
 const (
@@ -52,8 +53,17 @@ const (
 	FieldGname = "gname"
 	// FieldV3 holds the string denoting the v3 field in the database.
 	FieldV3 = "v3"
+	// EdgeContactRelationships holds the string denoting the contact_relationships edge name in mutations.
+	EdgeContactRelationships = "contact_relationships"
 	// Table holds the table name of the contact in the database.
 	Table = "contact"
+	// ContactRelationshipsTable is the table that holds the contact_relationships relation/edge.
+	ContactRelationshipsTable = "label_relationship"
+	// ContactRelationshipsInverseTable is the table name for the LabelRelationship entity.
+	// It exists in this package in order to avoid circular dependency with the "labelrelationship" package.
+	ContactRelationshipsInverseTable = "label_relationship"
+	// ContactRelationshipsColumn is the table column denoting the contact_relationships relation/edge.
+	ContactRelationshipsColumn = "contact_id"
 )
 
 // Columns holds all SQL columns for contact fields.
@@ -240,3 +250,24 @@ func ByGname(opts ...sql.OrderTermOption) OrderOption {
 func ByV3(opts ...sql.OrderTermOption) OrderOption {
 	return sql.OrderByField(FieldV3, opts...).ToFunc()
 }
+
+// ByContactRelationshipsCount orders the results by contact_relationships count.
+func ByContactRelationshipsCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newContactRelationshipsStep(), opts...)
+	}
+}
+
+// ByContactRelationships orders the results by contact_relationships terms.
+func ByContactRelationships(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newContactRelationshipsStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newContactRelationshipsStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(ContactRelationshipsInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, ContactRelationshipsTable, ContactRelationshipsColumn),
+	)
+}

+ 24 - 0
ent/contact/where.go

@@ -7,6 +7,7 @@ import (
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
 )
 
 // ID filters vertices based on their ID field.
@@ -1224,6 +1225,29 @@ func V3ContainsFold(v string) predicate.Contact {
 	return predicate.Contact(sql.FieldContainsFold(FieldV3, v))
 }
 
+// HasContactRelationships applies the HasEdge predicate on the "contact_relationships" edge.
+func HasContactRelationships() predicate.Contact {
+	return predicate.Contact(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, ContactRelationshipsTable, ContactRelationshipsColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasContactRelationshipsWith applies the HasEdge predicate on the "contact_relationships" edge with a given conditions (other predicates).
+func HasContactRelationshipsWith(preds ...predicate.LabelRelationship) predicate.Contact {
+	return predicate.Contact(func(s *sql.Selector) {
+		step := newContactRelationshipsStep()
+		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.Contact) predicate.Contact {
 	return predicate.Contact(sql.AndPredicates(predicates...))

+ 32 - 0
ent/contact_create.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/labelrelationship"
 
 	"entgo.io/ent/dialect/sql"
 	"entgo.io/ent/dialect/sql/sqlgraph"
@@ -294,6 +295,21 @@ func (cc *ContactCreate) SetID(u uint64) *ContactCreate {
 	return cc
 }
 
+// AddContactRelationshipIDs adds the "contact_relationships" edge to the LabelRelationship entity by IDs.
+func (cc *ContactCreate) AddContactRelationshipIDs(ids ...uint64) *ContactCreate {
+	cc.mutation.AddContactRelationshipIDs(ids...)
+	return cc
+}
+
+// AddContactRelationships adds the "contact_relationships" edges to the LabelRelationship entity.
+func (cc *ContactCreate) AddContactRelationships(l ...*LabelRelationship) *ContactCreate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return cc.AddContactRelationshipIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cc *ContactCreate) Mutation() *ContactMutation {
 	return cc.mutation
@@ -568,6 +584,22 @@ func (cc *ContactCreate) createSpec() (*Contact, *sqlgraph.CreateSpec) {
 		_spec.SetField(contact.FieldV3, field.TypeString, value)
 		_node.V3 = value
 	}
+	if nodes := cc.mutation.ContactRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
 	return _node, _spec
 }
 

+ 92 - 11
ent/contact_query.go

@@ -4,9 +4,11 @@ package ent
 
 import (
 	"context"
+	"database/sql/driver"
 	"fmt"
 	"math"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/labelrelationship"
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
@@ -17,10 +19,11 @@ import (
 // ContactQuery is the builder for querying Contact entities.
 type ContactQuery struct {
 	config
-	ctx        *QueryContext
-	order      []contact.OrderOption
-	inters     []Interceptor
-	predicates []predicate.Contact
+	ctx                      *QueryContext
+	order                    []contact.OrderOption
+	inters                   []Interceptor
+	predicates               []predicate.Contact
+	withContactRelationships *LabelRelationshipQuery
 	// intermediate query (i.e. traversal path).
 	sql  *sql.Selector
 	path func(context.Context) (*sql.Selector, error)
@@ -57,6 +60,28 @@ func (cq *ContactQuery) Order(o ...contact.OrderOption) *ContactQuery {
 	return cq
 }
 
+// QueryContactRelationships chains the current query on the "contact_relationships" edge.
+func (cq *ContactQuery) QueryContactRelationships() *LabelRelationshipQuery {
+	query := (&LabelRelationshipClient{config: cq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := cq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := cq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(contact.Table, contact.FieldID, selector),
+			sqlgraph.To(labelrelationship.Table, labelrelationship.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, contact.ContactRelationshipsTable, contact.ContactRelationshipsColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(cq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
 // First returns the first Contact entity from the query.
 // Returns a *NotFoundError when no Contact was found.
 func (cq *ContactQuery) First(ctx context.Context) (*Contact, error) {
@@ -244,17 +269,29 @@ func (cq *ContactQuery) Clone() *ContactQuery {
 		return nil
 	}
 	return &ContactQuery{
-		config:     cq.config,
-		ctx:        cq.ctx.Clone(),
-		order:      append([]contact.OrderOption{}, cq.order...),
-		inters:     append([]Interceptor{}, cq.inters...),
-		predicates: append([]predicate.Contact{}, cq.predicates...),
+		config:                   cq.config,
+		ctx:                      cq.ctx.Clone(),
+		order:                    append([]contact.OrderOption{}, cq.order...),
+		inters:                   append([]Interceptor{}, cq.inters...),
+		predicates:               append([]predicate.Contact{}, cq.predicates...),
+		withContactRelationships: cq.withContactRelationships.Clone(),
 		// clone intermediate query.
 		sql:  cq.sql.Clone(),
 		path: cq.path,
 	}
 }
 
+// WithContactRelationships tells the query-builder to eager-load the nodes that are connected to
+// the "contact_relationships" edge. The optional arguments are used to configure the query builder of the edge.
+func (cq *ContactQuery) WithContactRelationships(opts ...func(*LabelRelationshipQuery)) *ContactQuery {
+	query := (&LabelRelationshipClient{config: cq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	cq.withContactRelationships = query
+	return cq
+}
+
 // 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.
 //
@@ -331,8 +368,11 @@ func (cq *ContactQuery) prepareQuery(ctx context.Context) error {
 
 func (cq *ContactQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Contact, error) {
 	var (
-		nodes = []*Contact{}
-		_spec = cq.querySpec()
+		nodes       = []*Contact{}
+		_spec       = cq.querySpec()
+		loadedTypes = [1]bool{
+			cq.withContactRelationships != nil,
+		}
 	)
 	_spec.ScanValues = func(columns []string) ([]any, error) {
 		return (*Contact).scanValues(nil, columns)
@@ -340,6 +380,7 @@ func (cq *ContactQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Cont
 	_spec.Assign = func(columns []string, values []any) error {
 		node := &Contact{config: cq.config}
 		nodes = append(nodes, node)
+		node.Edges.loadedTypes = loadedTypes
 		return node.assignValues(columns, values)
 	}
 	for i := range hooks {
@@ -351,9 +392,49 @@ func (cq *ContactQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Cont
 	if len(nodes) == 0 {
 		return nodes, nil
 	}
+	if query := cq.withContactRelationships; query != nil {
+		if err := cq.loadContactRelationships(ctx, query, nodes,
+			func(n *Contact) { n.Edges.ContactRelationships = []*LabelRelationship{} },
+			func(n *Contact, e *LabelRelationship) {
+				n.Edges.ContactRelationships = append(n.Edges.ContactRelationships, e)
+			}); err != nil {
+			return nil, err
+		}
+	}
 	return nodes, nil
 }
 
+func (cq *ContactQuery) loadContactRelationships(ctx context.Context, query *LabelRelationshipQuery, nodes []*Contact, init func(*Contact), assign func(*Contact, *LabelRelationship)) error {
+	fks := make([]driver.Value, 0, len(nodes))
+	nodeids := make(map[uint64]*Contact)
+	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(labelrelationship.FieldContactID)
+	}
+	query.Where(predicate.LabelRelationship(func(s *sql.Selector) {
+		s.Where(sql.InValues(s.C(contact.ContactRelationshipsColumn), fks...))
+	}))
+	neighbors, err := query.All(ctx)
+	if err != nil {
+		return err
+	}
+	for _, n := range neighbors {
+		fk := n.ContactID
+		node, ok := nodeids[fk]
+		if !ok {
+			return fmt.Errorf(`unexpected referenced foreign-key "contact_id" returned %v for node %v`, fk, n.ID)
+		}
+		assign(node, n)
+	}
+	return nil
+}
+
 func (cq *ContactQuery) sqlCount(ctx context.Context) (int, error) {
 	_spec := cq.querySpec()
 	_spec.Node.Columns = cq.ctx.Fields

+ 163 - 0
ent/contact_update.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/labelrelationship"
 	"wechat-api/ent/predicate"
 
 	"entgo.io/ent/dialect/sql"
@@ -331,11 +332,47 @@ func (cu *ContactUpdate) SetNillableV3(s *string) *ContactUpdate {
 	return cu
 }
 
+// AddContactRelationshipIDs adds the "contact_relationships" edge to the LabelRelationship entity by IDs.
+func (cu *ContactUpdate) AddContactRelationshipIDs(ids ...uint64) *ContactUpdate {
+	cu.mutation.AddContactRelationshipIDs(ids...)
+	return cu
+}
+
+// AddContactRelationships adds the "contact_relationships" edges to the LabelRelationship entity.
+func (cu *ContactUpdate) AddContactRelationships(l ...*LabelRelationship) *ContactUpdate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return cu.AddContactRelationshipIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cu *ContactUpdate) Mutation() *ContactMutation {
 	return cu.mutation
 }
 
+// ClearContactRelationships clears all "contact_relationships" edges to the LabelRelationship entity.
+func (cu *ContactUpdate) ClearContactRelationships() *ContactUpdate {
+	cu.mutation.ClearContactRelationships()
+	return cu
+}
+
+// RemoveContactRelationshipIDs removes the "contact_relationships" edge to LabelRelationship entities by IDs.
+func (cu *ContactUpdate) RemoveContactRelationshipIDs(ids ...uint64) *ContactUpdate {
+	cu.mutation.RemoveContactRelationshipIDs(ids...)
+	return cu
+}
+
+// RemoveContactRelationships removes "contact_relationships" edges to LabelRelationship entities.
+func (cu *ContactUpdate) RemoveContactRelationships(l ...*LabelRelationship) *ContactUpdate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return cu.RemoveContactRelationshipIDs(ids...)
+}
+
 // Save executes the query and returns the number of nodes affected by the update operation.
 func (cu *ContactUpdate) Save(ctx context.Context) (int, error) {
 	if err := cu.defaults(); err != nil {
@@ -468,6 +505,51 @@ func (cu *ContactUpdate) sqlSave(ctx context.Context) (n int, err error) {
 	if value, ok := cu.mutation.V3(); ok {
 		_spec.SetField(contact.FieldV3, field.TypeString, value)
 	}
+	if cu.mutation.ContactRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cu.mutation.RemovedContactRelationshipsIDs(); len(nodes) > 0 && !cu.mutation.ContactRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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 := cu.mutation.ContactRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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, cu.driver, _spec); err != nil {
 		if _, ok := err.(*sqlgraph.NotFoundError); ok {
 			err = &NotFoundError{contact.Label}
@@ -791,11 +873,47 @@ func (cuo *ContactUpdateOne) SetNillableV3(s *string) *ContactUpdateOne {
 	return cuo
 }
 
+// AddContactRelationshipIDs adds the "contact_relationships" edge to the LabelRelationship entity by IDs.
+func (cuo *ContactUpdateOne) AddContactRelationshipIDs(ids ...uint64) *ContactUpdateOne {
+	cuo.mutation.AddContactRelationshipIDs(ids...)
+	return cuo
+}
+
+// AddContactRelationships adds the "contact_relationships" edges to the LabelRelationship entity.
+func (cuo *ContactUpdateOne) AddContactRelationships(l ...*LabelRelationship) *ContactUpdateOne {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return cuo.AddContactRelationshipIDs(ids...)
+}
+
 // Mutation returns the ContactMutation object of the builder.
 func (cuo *ContactUpdateOne) Mutation() *ContactMutation {
 	return cuo.mutation
 }
 
+// ClearContactRelationships clears all "contact_relationships" edges to the LabelRelationship entity.
+func (cuo *ContactUpdateOne) ClearContactRelationships() *ContactUpdateOne {
+	cuo.mutation.ClearContactRelationships()
+	return cuo
+}
+
+// RemoveContactRelationshipIDs removes the "contact_relationships" edge to LabelRelationship entities by IDs.
+func (cuo *ContactUpdateOne) RemoveContactRelationshipIDs(ids ...uint64) *ContactUpdateOne {
+	cuo.mutation.RemoveContactRelationshipIDs(ids...)
+	return cuo
+}
+
+// RemoveContactRelationships removes "contact_relationships" edges to LabelRelationship entities.
+func (cuo *ContactUpdateOne) RemoveContactRelationships(l ...*LabelRelationship) *ContactUpdateOne {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return cuo.RemoveContactRelationshipIDs(ids...)
+}
+
 // Where appends a list predicates to the ContactUpdate builder.
 func (cuo *ContactUpdateOne) Where(ps ...predicate.Contact) *ContactUpdateOne {
 	cuo.mutation.Where(ps...)
@@ -958,6 +1076,51 @@ func (cuo *ContactUpdateOne) sqlSave(ctx context.Context) (_node *Contact, err e
 	if value, ok := cuo.mutation.V3(); ok {
 		_spec.SetField(contact.FieldV3, field.TypeString, value)
 	}
+	if cuo.mutation.ContactRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := cuo.mutation.RemovedContactRelationshipsIDs(); len(nodes) > 0 && !cuo.mutation.ContactRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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 := cuo.mutation.ContactRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   contact.ContactRelationshipsTable,
+			Columns: []string{contact.ContactRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
 	_node = &Contact{config: cuo.config}
 	_spec.Assign = _node.assignValues
 	_spec.ScanValues = _node.scanValues

+ 9 - 3
ent/ent.go

@@ -9,6 +9,9 @@ import (
 	"reflect"
 	"sync"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
 
@@ -75,9 +78,12 @@ var (
 func checkColumn(table, column string) error {
 	initCheck.Do(func() {
 		columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
-			contact.Table: contact.ValidColumn,
-			server.Table:  server.ValidColumn,
-			wx.Table:      wx.ValidColumn,
+			contact.Table:           contact.ValidColumn,
+			label.Table:             label.ValidColumn,
+			labelrelationship.Table: labelrelationship.ValidColumn,
+			message.Table:           message.ValidColumn,
+			server.Table:            server.ValidColumn,
+			wx.Table:                wx.ValidColumn,
 		})
 	})
 	return columnCheck(table, column)

+ 36 - 0
ent/hook/hook.go

@@ -20,6 +20,42 @@ func (f ContactFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, err
 	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ContactMutation", m)
 }
 
+// The LabelFunc type is an adapter to allow the use of ordinary
+// function as Label mutator.
+type LabelFunc func(context.Context, *ent.LabelMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f LabelFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.LabelMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.LabelMutation", m)
+}
+
+// The LabelRelationshipFunc type is an adapter to allow the use of ordinary
+// function as LabelRelationship mutator.
+type LabelRelationshipFunc func(context.Context, *ent.LabelRelationshipMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f LabelRelationshipFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.LabelRelationshipMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.LabelRelationshipMutation", m)
+}
+
+// The MessageFunc type is an adapter to allow the use of ordinary
+// function as Message mutator.
+type MessageFunc func(context.Context, *ent.MessageMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f MessageFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.MessageMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MessageMutation", m)
+}
+
 // The ServerFunc type is an adapter to allow the use of ordinary
 // function as Server mutator.
 type ServerFunc func(context.Context, *ent.ServerMutation) (ent.Value, error)

+ 90 - 0
ent/intercept/intercept.go

@@ -7,6 +7,9 @@ import (
 	"fmt"
 	"wechat-api/ent"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
@@ -97,6 +100,87 @@ func (f TraverseContact) Traverse(ctx context.Context, q ent.Query) error {
 	return fmt.Errorf("unexpected query type %T. expect *ent.ContactQuery", q)
 }
 
+// The LabelFunc type is an adapter to allow the use of ordinary function as a Querier.
+type LabelFunc func(context.Context, *ent.LabelQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f LabelFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.LabelQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.LabelQuery", q)
+}
+
+// The TraverseLabel type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseLabel func(context.Context, *ent.LabelQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseLabel) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseLabel) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.LabelQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.LabelQuery", q)
+}
+
+// The LabelRelationshipFunc type is an adapter to allow the use of ordinary function as a Querier.
+type LabelRelationshipFunc func(context.Context, *ent.LabelRelationshipQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f LabelRelationshipFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.LabelRelationshipQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.LabelRelationshipQuery", q)
+}
+
+// The TraverseLabelRelationship type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseLabelRelationship func(context.Context, *ent.LabelRelationshipQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseLabelRelationship) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseLabelRelationship) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.LabelRelationshipQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.LabelRelationshipQuery", q)
+}
+
+// The MessageFunc type is an adapter to allow the use of ordinary function as a Querier.
+type MessageFunc func(context.Context, *ent.MessageQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f MessageFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.MessageQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.MessageQuery", q)
+}
+
+// The TraverseMessage type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseMessage func(context.Context, *ent.MessageQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseMessage) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseMessage) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.MessageQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.MessageQuery", q)
+}
+
 // The ServerFunc type is an adapter to allow the use of ordinary function as a Querier.
 type ServerFunc func(context.Context, *ent.ServerQuery) (ent.Value, error)
 
@@ -156,6 +240,12 @@ func NewQuery(q ent.Query) (Query, error) {
 	switch q := q.(type) {
 	case *ent.ContactQuery:
 		return &query[*ent.ContactQuery, predicate.Contact, contact.OrderOption]{typ: ent.TypeContact, tq: q}, nil
+	case *ent.LabelQuery:
+		return &query[*ent.LabelQuery, predicate.Label, label.OrderOption]{typ: ent.TypeLabel, tq: q}, nil
+	case *ent.LabelRelationshipQuery:
+		return &query[*ent.LabelRelationshipQuery, predicate.LabelRelationship, labelrelationship.OrderOption]{typ: ent.TypeLabelRelationship, tq: q}, nil
+	case *ent.MessageQuery:
+		return &query[*ent.MessageQuery, predicate.Message, message.OrderOption]{typ: ent.TypeMessage, tq: q}, nil
 	case *ent.ServerQuery:
 		return &query[*ent.ServerQuery, predicate.Server, server.OrderOption]{typ: ent.TypeServer, tq: q}, nil
 	case *ent.WxQuery:

+ 220 - 0
ent/label.go

@@ -0,0 +1,220 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/label"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Label is the model entity for the Label schema.
+type Label 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"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// 标签类型:1好友,2群组,3公众号,4企业微信联系人
+	Type int `json:"type,omitempty"`
+	// 标签名称
+	Name string `json:"name,omitempty"`
+	// 标签来源:1后台创建 2个微同步
+	From int `json:"from,omitempty"`
+	// 标签模式:1动态 2静态
+	Mode int `json:"mode,omitempty"`
+	// 标签的触达条件
+	Conditions string `json:"conditions,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the LabelQuery when eager-loading is set.
+	Edges        LabelEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// LabelEdges holds the relations/edges for other nodes in the graph.
+type LabelEdges struct {
+	// LabelRelationships holds the value of the label_relationships edge.
+	LabelRelationships []*LabelRelationship `json:"label_relationships,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [1]bool
+}
+
+// LabelRelationshipsOrErr returns the LabelRelationships value or an error if the edge
+// was not loaded in eager-loading.
+func (e LabelEdges) LabelRelationshipsOrErr() ([]*LabelRelationship, error) {
+	if e.loadedTypes[0] {
+		return e.LabelRelationships, nil
+	}
+	return nil, &NotLoadedError{edge: "label_relationships"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Label) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case label.FieldID, label.FieldStatus, label.FieldType, label.FieldFrom, label.FieldMode:
+			values[i] = new(sql.NullInt64)
+		case label.FieldName, label.FieldConditions:
+			values[i] = new(sql.NullString)
+		case label.FieldCreatedAt, label.FieldUpdatedAt, label.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 Label fields.
+func (l *Label) 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 label.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			l.ID = uint64(value.Int64)
+		case label.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 {
+				l.CreatedAt = value.Time
+			}
+		case label.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 {
+				l.UpdatedAt = value.Time
+			}
+		case label.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				l.Status = uint8(value.Int64)
+			}
+		case label.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 {
+				l.DeletedAt = value.Time
+			}
+		case label.FieldType:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field type", values[i])
+			} else if value.Valid {
+				l.Type = int(value.Int64)
+			}
+		case label.FieldName:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field name", values[i])
+			} else if value.Valid {
+				l.Name = value.String
+			}
+		case label.FieldFrom:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field from", values[i])
+			} else if value.Valid {
+				l.From = int(value.Int64)
+			}
+		case label.FieldMode:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field mode", values[i])
+			} else if value.Valid {
+				l.Mode = int(value.Int64)
+			}
+		case label.FieldConditions:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field conditions", values[i])
+			} else if value.Valid {
+				l.Conditions = value.String
+			}
+		default:
+			l.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Label.
+// This includes values selected through modifiers, order, etc.
+func (l *Label) Value(name string) (ent.Value, error) {
+	return l.selectValues.Get(name)
+}
+
+// QueryLabelRelationships queries the "label_relationships" edge of the Label entity.
+func (l *Label) QueryLabelRelationships() *LabelRelationshipQuery {
+	return NewLabelClient(l.config).QueryLabelRelationships(l)
+}
+
+// Update returns a builder for updating this Label.
+// Note that you need to call Label.Unwrap() before calling this method if this Label
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (l *Label) Update() *LabelUpdateOne {
+	return NewLabelClient(l.config).UpdateOne(l)
+}
+
+// Unwrap unwraps the Label 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 (l *Label) Unwrap() *Label {
+	_tx, ok := l.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Label is not a transactional entity")
+	}
+	l.config.driver = _tx.drv
+	return l
+}
+
+// String implements the fmt.Stringer.
+func (l *Label) String() string {
+	var builder strings.Builder
+	builder.WriteString("Label(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", l.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(l.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(l.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", l.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(l.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("type=")
+	builder.WriteString(fmt.Sprintf("%v", l.Type))
+	builder.WriteString(", ")
+	builder.WriteString("name=")
+	builder.WriteString(l.Name)
+	builder.WriteString(", ")
+	builder.WriteString("from=")
+	builder.WriteString(fmt.Sprintf("%v", l.From))
+	builder.WriteString(", ")
+	builder.WriteString("mode=")
+	builder.WriteString(fmt.Sprintf("%v", l.Mode))
+	builder.WriteString(", ")
+	builder.WriteString("conditions=")
+	builder.WriteString(l.Conditions)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Labels is a parsable slice of Label.
+type Labels []*Label

+ 173 - 0
ent/label/label.go

@@ -0,0 +1,173 @@
+// Code generated by ent, DO NOT EDIT.
+
+package label
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the label type in the database.
+	Label = "label"
+	// 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"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// FieldType holds the string denoting the type field in the database.
+	FieldType = "type"
+	// FieldName holds the string denoting the name field in the database.
+	FieldName = "name"
+	// FieldFrom holds the string denoting the from field in the database.
+	FieldFrom = "from"
+	// FieldMode holds the string denoting the mode field in the database.
+	FieldMode = "mode"
+	// FieldConditions holds the string denoting the conditions field in the database.
+	FieldConditions = "conditions"
+	// EdgeLabelRelationships holds the string denoting the label_relationships edge name in mutations.
+	EdgeLabelRelationships = "label_relationships"
+	// Table holds the table name of the label in the database.
+	Table = "label"
+	// LabelRelationshipsTable is the table that holds the label_relationships relation/edge.
+	LabelRelationshipsTable = "label_relationship"
+	// LabelRelationshipsInverseTable is the table name for the LabelRelationship entity.
+	// It exists in this package in order to avoid circular dependency with the "labelrelationship" package.
+	LabelRelationshipsInverseTable = "label_relationship"
+	// LabelRelationshipsColumn is the table column denoting the label_relationships relation/edge.
+	LabelRelationshipsColumn = "label_id"
+)
+
+// Columns holds all SQL columns for label fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldType,
+	FieldName,
+	FieldFrom,
+	FieldMode,
+	FieldConditions,
+}
+
+// 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
+}
+
+// Note that the variables below are initialized by the runtime
+// package on the initialization of the application. Therefore,
+// it should be imported in the main as follows:
+//
+//	import _ "wechat-api/ent/runtime"
+var (
+	Hooks        [1]ent.Hook
+	Interceptors [1]ent.Interceptor
+	// 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
+	// DefaultType holds the default value on creation for the "type" field.
+	DefaultType int
+	// DefaultName holds the default value on creation for the "name" field.
+	DefaultName string
+	// DefaultFrom holds the default value on creation for the "from" field.
+	DefaultFrom int
+	// DefaultMode holds the default value on creation for the "mode" field.
+	DefaultMode int
+	// DefaultConditions holds the default value on creation for the "conditions" field.
+	DefaultConditions string
+)
+
+// OrderOption defines the ordering options for the Label 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()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// ByType orders the results by the type field.
+func ByType(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldType, opts...).ToFunc()
+}
+
+// ByName orders the results by the name field.
+func ByName(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldName, opts...).ToFunc()
+}
+
+// ByFrom orders the results by the from field.
+func ByFrom(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldFrom, opts...).ToFunc()
+}
+
+// ByMode orders the results by the mode field.
+func ByMode(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldMode, opts...).ToFunc()
+}
+
+// ByConditions orders the results by the conditions field.
+func ByConditions(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldConditions, opts...).ToFunc()
+}
+
+// ByLabelRelationshipsCount orders the results by label_relationships count.
+func ByLabelRelationshipsCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newLabelRelationshipsStep(), opts...)
+	}
+}
+
+// ByLabelRelationships orders the results by label_relationships terms.
+func ByLabelRelationships(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newLabelRelationshipsStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newLabelRelationshipsStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(LabelRelationshipsInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, LabelRelationshipsTable, LabelRelationshipsColumn),
+	)
+}

+ 579 - 0
ent/label/where.go

@@ -0,0 +1,579 @@
+// Code generated by ent, DO NOT EDIT.
+
+package label
+
+import (
+	"time"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.Label {
+	return predicate.Label(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.Label {
+	return predicate.Label(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.Label {
+	return predicate.Label(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldStatus, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// Type applies equality check predicate on the "type" field. It's identical to TypeEQ.
+func Type(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldType, v))
+}
+
+// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
+func Name(v string) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldName, v))
+}
+
+// From applies equality check predicate on the "from" field. It's identical to FromEQ.
+func From(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldFrom, v))
+}
+
+// Mode applies equality check predicate on the "mode" field. It's identical to ModeEQ.
+func Mode(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldMode, v))
+}
+
+// Conditions applies equality check predicate on the "conditions" field. It's identical to ConditionsEQ.
+func Conditions(v string) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldConditions, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.Label {
+	return predicate.Label(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.Label {
+	return predicate.Label(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.Label {
+	return predicate.Label(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.Label {
+	return predicate.Label(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// TypeEQ applies the EQ predicate on the "type" field.
+func TypeEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldType, v))
+}
+
+// TypeNEQ applies the NEQ predicate on the "type" field.
+func TypeNEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldType, v))
+}
+
+// TypeIn applies the In predicate on the "type" field.
+func TypeIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldType, vs...))
+}
+
+// TypeNotIn applies the NotIn predicate on the "type" field.
+func TypeNotIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldType, vs...))
+}
+
+// TypeGT applies the GT predicate on the "type" field.
+func TypeGT(v int) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldType, v))
+}
+
+// TypeGTE applies the GTE predicate on the "type" field.
+func TypeGTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldType, v))
+}
+
+// TypeLT applies the LT predicate on the "type" field.
+func TypeLT(v int) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldType, v))
+}
+
+// TypeLTE applies the LTE predicate on the "type" field.
+func TypeLTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldType, v))
+}
+
+// NameEQ applies the EQ predicate on the "name" field.
+func NameEQ(v string) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldName, v))
+}
+
+// NameNEQ applies the NEQ predicate on the "name" field.
+func NameNEQ(v string) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldName, v))
+}
+
+// NameIn applies the In predicate on the "name" field.
+func NameIn(vs ...string) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldName, vs...))
+}
+
+// NameNotIn applies the NotIn predicate on the "name" field.
+func NameNotIn(vs ...string) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldName, vs...))
+}
+
+// NameGT applies the GT predicate on the "name" field.
+func NameGT(v string) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldName, v))
+}
+
+// NameGTE applies the GTE predicate on the "name" field.
+func NameGTE(v string) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldName, v))
+}
+
+// NameLT applies the LT predicate on the "name" field.
+func NameLT(v string) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldName, v))
+}
+
+// NameLTE applies the LTE predicate on the "name" field.
+func NameLTE(v string) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldName, v))
+}
+
+// NameContains applies the Contains predicate on the "name" field.
+func NameContains(v string) predicate.Label {
+	return predicate.Label(sql.FieldContains(FieldName, v))
+}
+
+// NameHasPrefix applies the HasPrefix predicate on the "name" field.
+func NameHasPrefix(v string) predicate.Label {
+	return predicate.Label(sql.FieldHasPrefix(FieldName, v))
+}
+
+// NameHasSuffix applies the HasSuffix predicate on the "name" field.
+func NameHasSuffix(v string) predicate.Label {
+	return predicate.Label(sql.FieldHasSuffix(FieldName, v))
+}
+
+// NameEqualFold applies the EqualFold predicate on the "name" field.
+func NameEqualFold(v string) predicate.Label {
+	return predicate.Label(sql.FieldEqualFold(FieldName, v))
+}
+
+// NameContainsFold applies the ContainsFold predicate on the "name" field.
+func NameContainsFold(v string) predicate.Label {
+	return predicate.Label(sql.FieldContainsFold(FieldName, v))
+}
+
+// FromEQ applies the EQ predicate on the "from" field.
+func FromEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldFrom, v))
+}
+
+// FromNEQ applies the NEQ predicate on the "from" field.
+func FromNEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldFrom, v))
+}
+
+// FromIn applies the In predicate on the "from" field.
+func FromIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldFrom, vs...))
+}
+
+// FromNotIn applies the NotIn predicate on the "from" field.
+func FromNotIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldFrom, vs...))
+}
+
+// FromGT applies the GT predicate on the "from" field.
+func FromGT(v int) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldFrom, v))
+}
+
+// FromGTE applies the GTE predicate on the "from" field.
+func FromGTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldFrom, v))
+}
+
+// FromLT applies the LT predicate on the "from" field.
+func FromLT(v int) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldFrom, v))
+}
+
+// FromLTE applies the LTE predicate on the "from" field.
+func FromLTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldFrom, v))
+}
+
+// ModeEQ applies the EQ predicate on the "mode" field.
+func ModeEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldMode, v))
+}
+
+// ModeNEQ applies the NEQ predicate on the "mode" field.
+func ModeNEQ(v int) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldMode, v))
+}
+
+// ModeIn applies the In predicate on the "mode" field.
+func ModeIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldMode, vs...))
+}
+
+// ModeNotIn applies the NotIn predicate on the "mode" field.
+func ModeNotIn(vs ...int) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldMode, vs...))
+}
+
+// ModeGT applies the GT predicate on the "mode" field.
+func ModeGT(v int) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldMode, v))
+}
+
+// ModeGTE applies the GTE predicate on the "mode" field.
+func ModeGTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldMode, v))
+}
+
+// ModeLT applies the LT predicate on the "mode" field.
+func ModeLT(v int) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldMode, v))
+}
+
+// ModeLTE applies the LTE predicate on the "mode" field.
+func ModeLTE(v int) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldMode, v))
+}
+
+// ConditionsEQ applies the EQ predicate on the "conditions" field.
+func ConditionsEQ(v string) predicate.Label {
+	return predicate.Label(sql.FieldEQ(FieldConditions, v))
+}
+
+// ConditionsNEQ applies the NEQ predicate on the "conditions" field.
+func ConditionsNEQ(v string) predicate.Label {
+	return predicate.Label(sql.FieldNEQ(FieldConditions, v))
+}
+
+// ConditionsIn applies the In predicate on the "conditions" field.
+func ConditionsIn(vs ...string) predicate.Label {
+	return predicate.Label(sql.FieldIn(FieldConditions, vs...))
+}
+
+// ConditionsNotIn applies the NotIn predicate on the "conditions" field.
+func ConditionsNotIn(vs ...string) predicate.Label {
+	return predicate.Label(sql.FieldNotIn(FieldConditions, vs...))
+}
+
+// ConditionsGT applies the GT predicate on the "conditions" field.
+func ConditionsGT(v string) predicate.Label {
+	return predicate.Label(sql.FieldGT(FieldConditions, v))
+}
+
+// ConditionsGTE applies the GTE predicate on the "conditions" field.
+func ConditionsGTE(v string) predicate.Label {
+	return predicate.Label(sql.FieldGTE(FieldConditions, v))
+}
+
+// ConditionsLT applies the LT predicate on the "conditions" field.
+func ConditionsLT(v string) predicate.Label {
+	return predicate.Label(sql.FieldLT(FieldConditions, v))
+}
+
+// ConditionsLTE applies the LTE predicate on the "conditions" field.
+func ConditionsLTE(v string) predicate.Label {
+	return predicate.Label(sql.FieldLTE(FieldConditions, v))
+}
+
+// ConditionsContains applies the Contains predicate on the "conditions" field.
+func ConditionsContains(v string) predicate.Label {
+	return predicate.Label(sql.FieldContains(FieldConditions, v))
+}
+
+// ConditionsHasPrefix applies the HasPrefix predicate on the "conditions" field.
+func ConditionsHasPrefix(v string) predicate.Label {
+	return predicate.Label(sql.FieldHasPrefix(FieldConditions, v))
+}
+
+// ConditionsHasSuffix applies the HasSuffix predicate on the "conditions" field.
+func ConditionsHasSuffix(v string) predicate.Label {
+	return predicate.Label(sql.FieldHasSuffix(FieldConditions, v))
+}
+
+// ConditionsIsNil applies the IsNil predicate on the "conditions" field.
+func ConditionsIsNil() predicate.Label {
+	return predicate.Label(sql.FieldIsNull(FieldConditions))
+}
+
+// ConditionsNotNil applies the NotNil predicate on the "conditions" field.
+func ConditionsNotNil() predicate.Label {
+	return predicate.Label(sql.FieldNotNull(FieldConditions))
+}
+
+// ConditionsEqualFold applies the EqualFold predicate on the "conditions" field.
+func ConditionsEqualFold(v string) predicate.Label {
+	return predicate.Label(sql.FieldEqualFold(FieldConditions, v))
+}
+
+// ConditionsContainsFold applies the ContainsFold predicate on the "conditions" field.
+func ConditionsContainsFold(v string) predicate.Label {
+	return predicate.Label(sql.FieldContainsFold(FieldConditions, v))
+}
+
+// HasLabelRelationships applies the HasEdge predicate on the "label_relationships" edge.
+func HasLabelRelationships() predicate.Label {
+	return predicate.Label(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, LabelRelationshipsTable, LabelRelationshipsColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasLabelRelationshipsWith applies the HasEdge predicate on the "label_relationships" edge with a given conditions (other predicates).
+func HasLabelRelationshipsWith(preds ...predicate.LabelRelationship) predicate.Label {
+	return predicate.Label(func(s *sql.Selector) {
+		step := newLabelRelationshipsStep()
+		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.Label) predicate.Label {
+	return predicate.Label(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Label) predicate.Label {
+	return predicate.Label(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Label) predicate.Label {
+	return predicate.Label(sql.NotPredicates(p))
+}

+ 1157 - 0
ent/label_create.go

@@ -0,0 +1,1157 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// LabelCreate is the builder for creating a Label entity.
+type LabelCreate struct {
+	config
+	mutation *LabelMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (lc *LabelCreate) SetCreatedAt(t time.Time) *LabelCreate {
+	lc.mutation.SetCreatedAt(t)
+	return lc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableCreatedAt(t *time.Time) *LabelCreate {
+	if t != nil {
+		lc.SetCreatedAt(*t)
+	}
+	return lc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (lc *LabelCreate) SetUpdatedAt(t time.Time) *LabelCreate {
+	lc.mutation.SetUpdatedAt(t)
+	return lc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableUpdatedAt(t *time.Time) *LabelCreate {
+	if t != nil {
+		lc.SetUpdatedAt(*t)
+	}
+	return lc
+}
+
+// SetStatus sets the "status" field.
+func (lc *LabelCreate) SetStatus(u uint8) *LabelCreate {
+	lc.mutation.SetStatus(u)
+	return lc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableStatus(u *uint8) *LabelCreate {
+	if u != nil {
+		lc.SetStatus(*u)
+	}
+	return lc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (lc *LabelCreate) SetDeletedAt(t time.Time) *LabelCreate {
+	lc.mutation.SetDeletedAt(t)
+	return lc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableDeletedAt(t *time.Time) *LabelCreate {
+	if t != nil {
+		lc.SetDeletedAt(*t)
+	}
+	return lc
+}
+
+// SetType sets the "type" field.
+func (lc *LabelCreate) SetType(i int) *LabelCreate {
+	lc.mutation.SetType(i)
+	return lc
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableType(i *int) *LabelCreate {
+	if i != nil {
+		lc.SetType(*i)
+	}
+	return lc
+}
+
+// SetName sets the "name" field.
+func (lc *LabelCreate) SetName(s string) *LabelCreate {
+	lc.mutation.SetName(s)
+	return lc
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableName(s *string) *LabelCreate {
+	if s != nil {
+		lc.SetName(*s)
+	}
+	return lc
+}
+
+// SetFrom sets the "from" field.
+func (lc *LabelCreate) SetFrom(i int) *LabelCreate {
+	lc.mutation.SetFrom(i)
+	return lc
+}
+
+// SetNillableFrom sets the "from" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableFrom(i *int) *LabelCreate {
+	if i != nil {
+		lc.SetFrom(*i)
+	}
+	return lc
+}
+
+// SetMode sets the "mode" field.
+func (lc *LabelCreate) SetMode(i int) *LabelCreate {
+	lc.mutation.SetMode(i)
+	return lc
+}
+
+// SetNillableMode sets the "mode" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableMode(i *int) *LabelCreate {
+	if i != nil {
+		lc.SetMode(*i)
+	}
+	return lc
+}
+
+// SetConditions sets the "conditions" field.
+func (lc *LabelCreate) SetConditions(s string) *LabelCreate {
+	lc.mutation.SetConditions(s)
+	return lc
+}
+
+// SetNillableConditions sets the "conditions" field if the given value is not nil.
+func (lc *LabelCreate) SetNillableConditions(s *string) *LabelCreate {
+	if s != nil {
+		lc.SetConditions(*s)
+	}
+	return lc
+}
+
+// SetID sets the "id" field.
+func (lc *LabelCreate) SetID(u uint64) *LabelCreate {
+	lc.mutation.SetID(u)
+	return lc
+}
+
+// AddLabelRelationshipIDs adds the "label_relationships" edge to the LabelRelationship entity by IDs.
+func (lc *LabelCreate) AddLabelRelationshipIDs(ids ...uint64) *LabelCreate {
+	lc.mutation.AddLabelRelationshipIDs(ids...)
+	return lc
+}
+
+// AddLabelRelationships adds the "label_relationships" edges to the LabelRelationship entity.
+func (lc *LabelCreate) AddLabelRelationships(l ...*LabelRelationship) *LabelCreate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return lc.AddLabelRelationshipIDs(ids...)
+}
+
+// Mutation returns the LabelMutation object of the builder.
+func (lc *LabelCreate) Mutation() *LabelMutation {
+	return lc.mutation
+}
+
+// Save creates the Label in the database.
+func (lc *LabelCreate) Save(ctx context.Context) (*Label, error) {
+	if err := lc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, lc.sqlSave, lc.mutation, lc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (lc *LabelCreate) SaveX(ctx context.Context) *Label {
+	v, err := lc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (lc *LabelCreate) Exec(ctx context.Context) error {
+	_, err := lc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lc *LabelCreate) ExecX(ctx context.Context) {
+	if err := lc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (lc *LabelCreate) defaults() error {
+	if _, ok := lc.mutation.CreatedAt(); !ok {
+		if label.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized label.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := label.DefaultCreatedAt()
+		lc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := lc.mutation.UpdatedAt(); !ok {
+		if label.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized label.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := label.DefaultUpdatedAt()
+		lc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := lc.mutation.Status(); !ok {
+		v := label.DefaultStatus
+		lc.mutation.SetStatus(v)
+	}
+	if _, ok := lc.mutation.GetType(); !ok {
+		v := label.DefaultType
+		lc.mutation.SetType(v)
+	}
+	if _, ok := lc.mutation.Name(); !ok {
+		v := label.DefaultName
+		lc.mutation.SetName(v)
+	}
+	if _, ok := lc.mutation.From(); !ok {
+		v := label.DefaultFrom
+		lc.mutation.SetFrom(v)
+	}
+	if _, ok := lc.mutation.Mode(); !ok {
+		v := label.DefaultMode
+		lc.mutation.SetMode(v)
+	}
+	if _, ok := lc.mutation.Conditions(); !ok {
+		v := label.DefaultConditions
+		lc.mutation.SetConditions(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (lc *LabelCreate) check() error {
+	if _, ok := lc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Label.created_at"`)}
+	}
+	if _, ok := lc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Label.updated_at"`)}
+	}
+	if _, ok := lc.mutation.GetType(); !ok {
+		return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "Label.type"`)}
+	}
+	if _, ok := lc.mutation.Name(); !ok {
+		return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Label.name"`)}
+	}
+	if _, ok := lc.mutation.From(); !ok {
+		return &ValidationError{Name: "from", err: errors.New(`ent: missing required field "Label.from"`)}
+	}
+	if _, ok := lc.mutation.Mode(); !ok {
+		return &ValidationError{Name: "mode", err: errors.New(`ent: missing required field "Label.mode"`)}
+	}
+	return nil
+}
+
+func (lc *LabelCreate) sqlSave(ctx context.Context) (*Label, error) {
+	if err := lc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := lc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, lc.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)
+	}
+	lc.mutation.id = &_node.ID
+	lc.mutation.done = true
+	return _node, nil
+}
+
+func (lc *LabelCreate) createSpec() (*Label, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Label{config: lc.config}
+		_spec = sqlgraph.NewCreateSpec(label.Table, sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = lc.conflict
+	if id, ok := lc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := lc.mutation.CreatedAt(); ok {
+		_spec.SetField(label.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := lc.mutation.UpdatedAt(); ok {
+		_spec.SetField(label.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := lc.mutation.Status(); ok {
+		_spec.SetField(label.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := lc.mutation.DeletedAt(); ok {
+		_spec.SetField(label.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if value, ok := lc.mutation.GetType(); ok {
+		_spec.SetField(label.FieldType, field.TypeInt, value)
+		_node.Type = value
+	}
+	if value, ok := lc.mutation.Name(); ok {
+		_spec.SetField(label.FieldName, field.TypeString, value)
+		_node.Name = value
+	}
+	if value, ok := lc.mutation.From(); ok {
+		_spec.SetField(label.FieldFrom, field.TypeInt, value)
+		_node.From = value
+	}
+	if value, ok := lc.mutation.Mode(); ok {
+		_spec.SetField(label.FieldMode, field.TypeInt, value)
+		_node.Mode = value
+	}
+	if value, ok := lc.mutation.Conditions(); ok {
+		_spec.SetField(label.FieldConditions, field.TypeString, value)
+		_node.Conditions = value
+	}
+	if nodes := lc.mutation.LabelRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	return _node, _spec
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Label.Create().
+//		SetCreatedAt(v).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.LabelUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (lc *LabelCreate) OnConflict(opts ...sql.ConflictOption) *LabelUpsertOne {
+	lc.conflict = opts
+	return &LabelUpsertOne{
+		create: lc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (lc *LabelCreate) OnConflictColumns(columns ...string) *LabelUpsertOne {
+	lc.conflict = append(lc.conflict, sql.ConflictColumns(columns...))
+	return &LabelUpsertOne{
+		create: lc,
+	}
+}
+
+type (
+	// LabelUpsertOne is the builder for "upsert"-ing
+	//  one Label node.
+	LabelUpsertOne struct {
+		create *LabelCreate
+	}
+
+	// LabelUpsert is the "OnConflict" setter.
+	LabelUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelUpsert) SetUpdatedAt(v time.Time) *LabelUpsert {
+	u.Set(label.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateUpdatedAt() *LabelUpsert {
+	u.SetExcluded(label.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelUpsert) SetStatus(v uint8) *LabelUpsert {
+	u.Set(label.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateStatus() *LabelUpsert {
+	u.SetExcluded(label.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelUpsert) AddStatus(v uint8) *LabelUpsert {
+	u.Add(label.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelUpsert) ClearStatus() *LabelUpsert {
+	u.SetNull(label.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelUpsert) SetDeletedAt(v time.Time) *LabelUpsert {
+	u.Set(label.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateDeletedAt() *LabelUpsert {
+	u.SetExcluded(label.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelUpsert) ClearDeletedAt() *LabelUpsert {
+	u.SetNull(label.FieldDeletedAt)
+	return u
+}
+
+// SetType sets the "type" field.
+func (u *LabelUpsert) SetType(v int) *LabelUpsert {
+	u.Set(label.FieldType, v)
+	return u
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateType() *LabelUpsert {
+	u.SetExcluded(label.FieldType)
+	return u
+}
+
+// AddType adds v to the "type" field.
+func (u *LabelUpsert) AddType(v int) *LabelUpsert {
+	u.Add(label.FieldType, v)
+	return u
+}
+
+// SetName sets the "name" field.
+func (u *LabelUpsert) SetName(v string) *LabelUpsert {
+	u.Set(label.FieldName, v)
+	return u
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateName() *LabelUpsert {
+	u.SetExcluded(label.FieldName)
+	return u
+}
+
+// SetFrom sets the "from" field.
+func (u *LabelUpsert) SetFrom(v int) *LabelUpsert {
+	u.Set(label.FieldFrom, v)
+	return u
+}
+
+// UpdateFrom sets the "from" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateFrom() *LabelUpsert {
+	u.SetExcluded(label.FieldFrom)
+	return u
+}
+
+// AddFrom adds v to the "from" field.
+func (u *LabelUpsert) AddFrom(v int) *LabelUpsert {
+	u.Add(label.FieldFrom, v)
+	return u
+}
+
+// SetMode sets the "mode" field.
+func (u *LabelUpsert) SetMode(v int) *LabelUpsert {
+	u.Set(label.FieldMode, v)
+	return u
+}
+
+// UpdateMode sets the "mode" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateMode() *LabelUpsert {
+	u.SetExcluded(label.FieldMode)
+	return u
+}
+
+// AddMode adds v to the "mode" field.
+func (u *LabelUpsert) AddMode(v int) *LabelUpsert {
+	u.Add(label.FieldMode, v)
+	return u
+}
+
+// SetConditions sets the "conditions" field.
+func (u *LabelUpsert) SetConditions(v string) *LabelUpsert {
+	u.Set(label.FieldConditions, v)
+	return u
+}
+
+// UpdateConditions sets the "conditions" field to the value that was provided on create.
+func (u *LabelUpsert) UpdateConditions() *LabelUpsert {
+	u.SetExcluded(label.FieldConditions)
+	return u
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (u *LabelUpsert) ClearConditions() *LabelUpsert {
+	u.SetNull(label.FieldConditions)
+	return u
+}
+
+// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
+// Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(label.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *LabelUpsertOne) UpdateNewValues() *LabelUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		if _, exists := u.create.mutation.ID(); exists {
+			s.SetIgnore(label.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(label.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *LabelUpsertOne) Ignore() *LabelUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *LabelUpsertOne) DoNothing() *LabelUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the LabelCreate.OnConflict
+// documentation for more info.
+func (u *LabelUpsertOne) Update(set func(*LabelUpsert)) *LabelUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&LabelUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelUpsertOne) SetUpdatedAt(v time.Time) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateUpdatedAt() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelUpsertOne) SetStatus(v uint8) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelUpsertOne) AddStatus(v uint8) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateStatus() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelUpsertOne) ClearStatus() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelUpsertOne) SetDeletedAt(v time.Time) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateDeletedAt() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelUpsertOne) ClearDeletedAt() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetType sets the "type" field.
+func (u *LabelUpsertOne) SetType(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetType(v)
+	})
+}
+
+// AddType adds v to the "type" field.
+func (u *LabelUpsertOne) AddType(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddType(v)
+	})
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateType() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateType()
+	})
+}
+
+// SetName sets the "name" field.
+func (u *LabelUpsertOne) SetName(v string) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetName(v)
+	})
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateName() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateName()
+	})
+}
+
+// SetFrom sets the "from" field.
+func (u *LabelUpsertOne) SetFrom(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetFrom(v)
+	})
+}
+
+// AddFrom adds v to the "from" field.
+func (u *LabelUpsertOne) AddFrom(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddFrom(v)
+	})
+}
+
+// UpdateFrom sets the "from" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateFrom() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateFrom()
+	})
+}
+
+// SetMode sets the "mode" field.
+func (u *LabelUpsertOne) SetMode(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetMode(v)
+	})
+}
+
+// AddMode adds v to the "mode" field.
+func (u *LabelUpsertOne) AddMode(v int) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddMode(v)
+	})
+}
+
+// UpdateMode sets the "mode" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateMode() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateMode()
+	})
+}
+
+// SetConditions sets the "conditions" field.
+func (u *LabelUpsertOne) SetConditions(v string) *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetConditions(v)
+	})
+}
+
+// UpdateConditions sets the "conditions" field to the value that was provided on create.
+func (u *LabelUpsertOne) UpdateConditions() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateConditions()
+	})
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (u *LabelUpsertOne) ClearConditions() *LabelUpsertOne {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearConditions()
+	})
+}
+
+// Exec executes the query.
+func (u *LabelUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for LabelCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *LabelUpsertOne) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// Exec executes the UPSERT query and returns the inserted/updated ID.
+func (u *LabelUpsertOne) ID(ctx context.Context) (id uint64, err error) {
+	node, err := u.create.Save(ctx)
+	if err != nil {
+		return id, err
+	}
+	return node.ID, nil
+}
+
+// IDX is like ID, but panics if an error occurs.
+func (u *LabelUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// LabelCreateBulk is the builder for creating many Label entities in bulk.
+type LabelCreateBulk struct {
+	config
+	err      error
+	builders []*LabelCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Label entities in the database.
+func (lcb *LabelCreateBulk) Save(ctx context.Context) ([]*Label, error) {
+	if lcb.err != nil {
+		return nil, lcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(lcb.builders))
+	nodes := make([]*Label, len(lcb.builders))
+	mutators := make([]Mutator, len(lcb.builders))
+	for i := range lcb.builders {
+		func(i int, root context.Context) {
+			builder := lcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*LabelMutation)
+				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, lcb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = lcb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, lcb.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, lcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (lcb *LabelCreateBulk) SaveX(ctx context.Context) []*Label {
+	v, err := lcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (lcb *LabelCreateBulk) Exec(ctx context.Context) error {
+	_, err := lcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lcb *LabelCreateBulk) ExecX(ctx context.Context) {
+	if err := lcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Label.CreateBulk(builders...).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.LabelUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (lcb *LabelCreateBulk) OnConflict(opts ...sql.ConflictOption) *LabelUpsertBulk {
+	lcb.conflict = opts
+	return &LabelUpsertBulk{
+		create: lcb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (lcb *LabelCreateBulk) OnConflictColumns(columns ...string) *LabelUpsertBulk {
+	lcb.conflict = append(lcb.conflict, sql.ConflictColumns(columns...))
+	return &LabelUpsertBulk{
+		create: lcb,
+	}
+}
+
+// LabelUpsertBulk is the builder for "upsert"-ing
+// a bulk of Label nodes.
+type LabelUpsertBulk struct {
+	create *LabelCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(label.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *LabelUpsertBulk) UpdateNewValues() *LabelUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		for _, b := range u.create.builders {
+			if _, exists := b.mutation.ID(); exists {
+				s.SetIgnore(label.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(label.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Label.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *LabelUpsertBulk) Ignore() *LabelUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *LabelUpsertBulk) DoNothing() *LabelUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the LabelCreateBulk.OnConflict
+// documentation for more info.
+func (u *LabelUpsertBulk) Update(set func(*LabelUpsert)) *LabelUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&LabelUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelUpsertBulk) SetUpdatedAt(v time.Time) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateUpdatedAt() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelUpsertBulk) SetStatus(v uint8) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelUpsertBulk) AddStatus(v uint8) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateStatus() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelUpsertBulk) ClearStatus() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelUpsertBulk) SetDeletedAt(v time.Time) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateDeletedAt() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelUpsertBulk) ClearDeletedAt() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetType sets the "type" field.
+func (u *LabelUpsertBulk) SetType(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetType(v)
+	})
+}
+
+// AddType adds v to the "type" field.
+func (u *LabelUpsertBulk) AddType(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddType(v)
+	})
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateType() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateType()
+	})
+}
+
+// SetName sets the "name" field.
+func (u *LabelUpsertBulk) SetName(v string) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetName(v)
+	})
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateName() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateName()
+	})
+}
+
+// SetFrom sets the "from" field.
+func (u *LabelUpsertBulk) SetFrom(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetFrom(v)
+	})
+}
+
+// AddFrom adds v to the "from" field.
+func (u *LabelUpsertBulk) AddFrom(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddFrom(v)
+	})
+}
+
+// UpdateFrom sets the "from" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateFrom() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateFrom()
+	})
+}
+
+// SetMode sets the "mode" field.
+func (u *LabelUpsertBulk) SetMode(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetMode(v)
+	})
+}
+
+// AddMode adds v to the "mode" field.
+func (u *LabelUpsertBulk) AddMode(v int) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.AddMode(v)
+	})
+}
+
+// UpdateMode sets the "mode" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateMode() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateMode()
+	})
+}
+
+// SetConditions sets the "conditions" field.
+func (u *LabelUpsertBulk) SetConditions(v string) *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.SetConditions(v)
+	})
+}
+
+// UpdateConditions sets the "conditions" field to the value that was provided on create.
+func (u *LabelUpsertBulk) UpdateConditions() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.UpdateConditions()
+	})
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (u *LabelUpsertBulk) ClearConditions() *LabelUpsertBulk {
+	return u.Update(func(s *LabelUpsert) {
+		s.ClearConditions()
+	})
+}
+
+// Exec executes the query.
+func (u *LabelUpsertBulk) Exec(ctx context.Context) error {
+	if u.create.err != nil {
+		return u.create.err
+	}
+	for i, b := range u.create.builders {
+		if len(b.conflict) != 0 {
+			return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the LabelCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for LabelCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *LabelUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/label_delete.go

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

+ 607 - 0
ent/label_query.go

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

+ 759 - 0
ent/label_update.go

@@ -0,0 +1,759 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// LabelUpdate is the builder for updating Label entities.
+type LabelUpdate struct {
+	config
+	hooks    []Hook
+	mutation *LabelMutation
+}
+
+// Where appends a list predicates to the LabelUpdate builder.
+func (lu *LabelUpdate) Where(ps ...predicate.Label) *LabelUpdate {
+	lu.mutation.Where(ps...)
+	return lu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (lu *LabelUpdate) SetUpdatedAt(t time.Time) *LabelUpdate {
+	lu.mutation.SetUpdatedAt(t)
+	return lu
+}
+
+// SetStatus sets the "status" field.
+func (lu *LabelUpdate) SetStatus(u uint8) *LabelUpdate {
+	lu.mutation.ResetStatus()
+	lu.mutation.SetStatus(u)
+	return lu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableStatus(u *uint8) *LabelUpdate {
+	if u != nil {
+		lu.SetStatus(*u)
+	}
+	return lu
+}
+
+// AddStatus adds u to the "status" field.
+func (lu *LabelUpdate) AddStatus(u int8) *LabelUpdate {
+	lu.mutation.AddStatus(u)
+	return lu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (lu *LabelUpdate) ClearStatus() *LabelUpdate {
+	lu.mutation.ClearStatus()
+	return lu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (lu *LabelUpdate) SetDeletedAt(t time.Time) *LabelUpdate {
+	lu.mutation.SetDeletedAt(t)
+	return lu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableDeletedAt(t *time.Time) *LabelUpdate {
+	if t != nil {
+		lu.SetDeletedAt(*t)
+	}
+	return lu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (lu *LabelUpdate) ClearDeletedAt() *LabelUpdate {
+	lu.mutation.ClearDeletedAt()
+	return lu
+}
+
+// SetType sets the "type" field.
+func (lu *LabelUpdate) SetType(i int) *LabelUpdate {
+	lu.mutation.ResetType()
+	lu.mutation.SetType(i)
+	return lu
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableType(i *int) *LabelUpdate {
+	if i != nil {
+		lu.SetType(*i)
+	}
+	return lu
+}
+
+// AddType adds i to the "type" field.
+func (lu *LabelUpdate) AddType(i int) *LabelUpdate {
+	lu.mutation.AddType(i)
+	return lu
+}
+
+// SetName sets the "name" field.
+func (lu *LabelUpdate) SetName(s string) *LabelUpdate {
+	lu.mutation.SetName(s)
+	return lu
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableName(s *string) *LabelUpdate {
+	if s != nil {
+		lu.SetName(*s)
+	}
+	return lu
+}
+
+// SetFrom sets the "from" field.
+func (lu *LabelUpdate) SetFrom(i int) *LabelUpdate {
+	lu.mutation.ResetFrom()
+	lu.mutation.SetFrom(i)
+	return lu
+}
+
+// SetNillableFrom sets the "from" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableFrom(i *int) *LabelUpdate {
+	if i != nil {
+		lu.SetFrom(*i)
+	}
+	return lu
+}
+
+// AddFrom adds i to the "from" field.
+func (lu *LabelUpdate) AddFrom(i int) *LabelUpdate {
+	lu.mutation.AddFrom(i)
+	return lu
+}
+
+// SetMode sets the "mode" field.
+func (lu *LabelUpdate) SetMode(i int) *LabelUpdate {
+	lu.mutation.ResetMode()
+	lu.mutation.SetMode(i)
+	return lu
+}
+
+// SetNillableMode sets the "mode" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableMode(i *int) *LabelUpdate {
+	if i != nil {
+		lu.SetMode(*i)
+	}
+	return lu
+}
+
+// AddMode adds i to the "mode" field.
+func (lu *LabelUpdate) AddMode(i int) *LabelUpdate {
+	lu.mutation.AddMode(i)
+	return lu
+}
+
+// SetConditions sets the "conditions" field.
+func (lu *LabelUpdate) SetConditions(s string) *LabelUpdate {
+	lu.mutation.SetConditions(s)
+	return lu
+}
+
+// SetNillableConditions sets the "conditions" field if the given value is not nil.
+func (lu *LabelUpdate) SetNillableConditions(s *string) *LabelUpdate {
+	if s != nil {
+		lu.SetConditions(*s)
+	}
+	return lu
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (lu *LabelUpdate) ClearConditions() *LabelUpdate {
+	lu.mutation.ClearConditions()
+	return lu
+}
+
+// AddLabelRelationshipIDs adds the "label_relationships" edge to the LabelRelationship entity by IDs.
+func (lu *LabelUpdate) AddLabelRelationshipIDs(ids ...uint64) *LabelUpdate {
+	lu.mutation.AddLabelRelationshipIDs(ids...)
+	return lu
+}
+
+// AddLabelRelationships adds the "label_relationships" edges to the LabelRelationship entity.
+func (lu *LabelUpdate) AddLabelRelationships(l ...*LabelRelationship) *LabelUpdate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return lu.AddLabelRelationshipIDs(ids...)
+}
+
+// Mutation returns the LabelMutation object of the builder.
+func (lu *LabelUpdate) Mutation() *LabelMutation {
+	return lu.mutation
+}
+
+// ClearLabelRelationships clears all "label_relationships" edges to the LabelRelationship entity.
+func (lu *LabelUpdate) ClearLabelRelationships() *LabelUpdate {
+	lu.mutation.ClearLabelRelationships()
+	return lu
+}
+
+// RemoveLabelRelationshipIDs removes the "label_relationships" edge to LabelRelationship entities by IDs.
+func (lu *LabelUpdate) RemoveLabelRelationshipIDs(ids ...uint64) *LabelUpdate {
+	lu.mutation.RemoveLabelRelationshipIDs(ids...)
+	return lu
+}
+
+// RemoveLabelRelationships removes "label_relationships" edges to LabelRelationship entities.
+func (lu *LabelUpdate) RemoveLabelRelationships(l ...*LabelRelationship) *LabelUpdate {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return lu.RemoveLabelRelationshipIDs(ids...)
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (lu *LabelUpdate) Save(ctx context.Context) (int, error) {
+	if err := lu.defaults(); err != nil {
+		return 0, err
+	}
+	return withHooks(ctx, lu.sqlSave, lu.mutation, lu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (lu *LabelUpdate) SaveX(ctx context.Context) int {
+	affected, err := lu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (lu *LabelUpdate) Exec(ctx context.Context) error {
+	_, err := lu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lu *LabelUpdate) ExecX(ctx context.Context) {
+	if err := lu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (lu *LabelUpdate) defaults() error {
+	if _, ok := lu.mutation.UpdatedAt(); !ok {
+		if label.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized label.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := label.UpdateDefaultUpdatedAt()
+		lu.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (lu *LabelUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	_spec := sqlgraph.NewUpdateSpec(label.Table, label.Columns, sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64))
+	if ps := lu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := lu.mutation.UpdatedAt(); ok {
+		_spec.SetField(label.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := lu.mutation.Status(); ok {
+		_spec.SetField(label.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := lu.mutation.AddedStatus(); ok {
+		_spec.AddField(label.FieldStatus, field.TypeUint8, value)
+	}
+	if lu.mutation.StatusCleared() {
+		_spec.ClearField(label.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := lu.mutation.DeletedAt(); ok {
+		_spec.SetField(label.FieldDeletedAt, field.TypeTime, value)
+	}
+	if lu.mutation.DeletedAtCleared() {
+		_spec.ClearField(label.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := lu.mutation.GetType(); ok {
+		_spec.SetField(label.FieldType, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.AddedType(); ok {
+		_spec.AddField(label.FieldType, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.Name(); ok {
+		_spec.SetField(label.FieldName, field.TypeString, value)
+	}
+	if value, ok := lu.mutation.From(); ok {
+		_spec.SetField(label.FieldFrom, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.AddedFrom(); ok {
+		_spec.AddField(label.FieldFrom, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.Mode(); ok {
+		_spec.SetField(label.FieldMode, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.AddedMode(); ok {
+		_spec.AddField(label.FieldMode, field.TypeInt, value)
+	}
+	if value, ok := lu.mutation.Conditions(); ok {
+		_spec.SetField(label.FieldConditions, field.TypeString, value)
+	}
+	if lu.mutation.ConditionsCleared() {
+		_spec.ClearField(label.FieldConditions, field.TypeString)
+	}
+	if lu.mutation.LabelRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := lu.mutation.RemovedLabelRelationshipsIDs(); len(nodes) > 0 && !lu.mutation.LabelRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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 := lu.mutation.LabelRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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, lu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{label.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	lu.mutation.done = true
+	return n, nil
+}
+
+// LabelUpdateOne is the builder for updating a single Label entity.
+type LabelUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *LabelMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (luo *LabelUpdateOne) SetUpdatedAt(t time.Time) *LabelUpdateOne {
+	luo.mutation.SetUpdatedAt(t)
+	return luo
+}
+
+// SetStatus sets the "status" field.
+func (luo *LabelUpdateOne) SetStatus(u uint8) *LabelUpdateOne {
+	luo.mutation.ResetStatus()
+	luo.mutation.SetStatus(u)
+	return luo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableStatus(u *uint8) *LabelUpdateOne {
+	if u != nil {
+		luo.SetStatus(*u)
+	}
+	return luo
+}
+
+// AddStatus adds u to the "status" field.
+func (luo *LabelUpdateOne) AddStatus(u int8) *LabelUpdateOne {
+	luo.mutation.AddStatus(u)
+	return luo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (luo *LabelUpdateOne) ClearStatus() *LabelUpdateOne {
+	luo.mutation.ClearStatus()
+	return luo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (luo *LabelUpdateOne) SetDeletedAt(t time.Time) *LabelUpdateOne {
+	luo.mutation.SetDeletedAt(t)
+	return luo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableDeletedAt(t *time.Time) *LabelUpdateOne {
+	if t != nil {
+		luo.SetDeletedAt(*t)
+	}
+	return luo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (luo *LabelUpdateOne) ClearDeletedAt() *LabelUpdateOne {
+	luo.mutation.ClearDeletedAt()
+	return luo
+}
+
+// SetType sets the "type" field.
+func (luo *LabelUpdateOne) SetType(i int) *LabelUpdateOne {
+	luo.mutation.ResetType()
+	luo.mutation.SetType(i)
+	return luo
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableType(i *int) *LabelUpdateOne {
+	if i != nil {
+		luo.SetType(*i)
+	}
+	return luo
+}
+
+// AddType adds i to the "type" field.
+func (luo *LabelUpdateOne) AddType(i int) *LabelUpdateOne {
+	luo.mutation.AddType(i)
+	return luo
+}
+
+// SetName sets the "name" field.
+func (luo *LabelUpdateOne) SetName(s string) *LabelUpdateOne {
+	luo.mutation.SetName(s)
+	return luo
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableName(s *string) *LabelUpdateOne {
+	if s != nil {
+		luo.SetName(*s)
+	}
+	return luo
+}
+
+// SetFrom sets the "from" field.
+func (luo *LabelUpdateOne) SetFrom(i int) *LabelUpdateOne {
+	luo.mutation.ResetFrom()
+	luo.mutation.SetFrom(i)
+	return luo
+}
+
+// SetNillableFrom sets the "from" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableFrom(i *int) *LabelUpdateOne {
+	if i != nil {
+		luo.SetFrom(*i)
+	}
+	return luo
+}
+
+// AddFrom adds i to the "from" field.
+func (luo *LabelUpdateOne) AddFrom(i int) *LabelUpdateOne {
+	luo.mutation.AddFrom(i)
+	return luo
+}
+
+// SetMode sets the "mode" field.
+func (luo *LabelUpdateOne) SetMode(i int) *LabelUpdateOne {
+	luo.mutation.ResetMode()
+	luo.mutation.SetMode(i)
+	return luo
+}
+
+// SetNillableMode sets the "mode" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableMode(i *int) *LabelUpdateOne {
+	if i != nil {
+		luo.SetMode(*i)
+	}
+	return luo
+}
+
+// AddMode adds i to the "mode" field.
+func (luo *LabelUpdateOne) AddMode(i int) *LabelUpdateOne {
+	luo.mutation.AddMode(i)
+	return luo
+}
+
+// SetConditions sets the "conditions" field.
+func (luo *LabelUpdateOne) SetConditions(s string) *LabelUpdateOne {
+	luo.mutation.SetConditions(s)
+	return luo
+}
+
+// SetNillableConditions sets the "conditions" field if the given value is not nil.
+func (luo *LabelUpdateOne) SetNillableConditions(s *string) *LabelUpdateOne {
+	if s != nil {
+		luo.SetConditions(*s)
+	}
+	return luo
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (luo *LabelUpdateOne) ClearConditions() *LabelUpdateOne {
+	luo.mutation.ClearConditions()
+	return luo
+}
+
+// AddLabelRelationshipIDs adds the "label_relationships" edge to the LabelRelationship entity by IDs.
+func (luo *LabelUpdateOne) AddLabelRelationshipIDs(ids ...uint64) *LabelUpdateOne {
+	luo.mutation.AddLabelRelationshipIDs(ids...)
+	return luo
+}
+
+// AddLabelRelationships adds the "label_relationships" edges to the LabelRelationship entity.
+func (luo *LabelUpdateOne) AddLabelRelationships(l ...*LabelRelationship) *LabelUpdateOne {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return luo.AddLabelRelationshipIDs(ids...)
+}
+
+// Mutation returns the LabelMutation object of the builder.
+func (luo *LabelUpdateOne) Mutation() *LabelMutation {
+	return luo.mutation
+}
+
+// ClearLabelRelationships clears all "label_relationships" edges to the LabelRelationship entity.
+func (luo *LabelUpdateOne) ClearLabelRelationships() *LabelUpdateOne {
+	luo.mutation.ClearLabelRelationships()
+	return luo
+}
+
+// RemoveLabelRelationshipIDs removes the "label_relationships" edge to LabelRelationship entities by IDs.
+func (luo *LabelUpdateOne) RemoveLabelRelationshipIDs(ids ...uint64) *LabelUpdateOne {
+	luo.mutation.RemoveLabelRelationshipIDs(ids...)
+	return luo
+}
+
+// RemoveLabelRelationships removes "label_relationships" edges to LabelRelationship entities.
+func (luo *LabelUpdateOne) RemoveLabelRelationships(l ...*LabelRelationship) *LabelUpdateOne {
+	ids := make([]uint64, len(l))
+	for i := range l {
+		ids[i] = l[i].ID
+	}
+	return luo.RemoveLabelRelationshipIDs(ids...)
+}
+
+// Where appends a list predicates to the LabelUpdate builder.
+func (luo *LabelUpdateOne) Where(ps ...predicate.Label) *LabelUpdateOne {
+	luo.mutation.Where(ps...)
+	return luo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (luo *LabelUpdateOne) Select(field string, fields ...string) *LabelUpdateOne {
+	luo.fields = append([]string{field}, fields...)
+	return luo
+}
+
+// Save executes the query and returns the updated Label entity.
+func (luo *LabelUpdateOne) Save(ctx context.Context) (*Label, error) {
+	if err := luo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, luo.sqlSave, luo.mutation, luo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (luo *LabelUpdateOne) SaveX(ctx context.Context) *Label {
+	node, err := luo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (luo *LabelUpdateOne) Exec(ctx context.Context) error {
+	_, err := luo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (luo *LabelUpdateOne) ExecX(ctx context.Context) {
+	if err := luo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (luo *LabelUpdateOne) defaults() error {
+	if _, ok := luo.mutation.UpdatedAt(); !ok {
+		if label.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized label.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := label.UpdateDefaultUpdatedAt()
+		luo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (luo *LabelUpdateOne) sqlSave(ctx context.Context) (_node *Label, err error) {
+	_spec := sqlgraph.NewUpdateSpec(label.Table, label.Columns, sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64))
+	id, ok := luo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Label.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := luo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, label.FieldID)
+		for _, f := range fields {
+			if !label.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != label.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := luo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := luo.mutation.UpdatedAt(); ok {
+		_spec.SetField(label.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := luo.mutation.Status(); ok {
+		_spec.SetField(label.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := luo.mutation.AddedStatus(); ok {
+		_spec.AddField(label.FieldStatus, field.TypeUint8, value)
+	}
+	if luo.mutation.StatusCleared() {
+		_spec.ClearField(label.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := luo.mutation.DeletedAt(); ok {
+		_spec.SetField(label.FieldDeletedAt, field.TypeTime, value)
+	}
+	if luo.mutation.DeletedAtCleared() {
+		_spec.ClearField(label.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := luo.mutation.GetType(); ok {
+		_spec.SetField(label.FieldType, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.AddedType(); ok {
+		_spec.AddField(label.FieldType, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.Name(); ok {
+		_spec.SetField(label.FieldName, field.TypeString, value)
+	}
+	if value, ok := luo.mutation.From(); ok {
+		_spec.SetField(label.FieldFrom, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.AddedFrom(); ok {
+		_spec.AddField(label.FieldFrom, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.Mode(); ok {
+		_spec.SetField(label.FieldMode, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.AddedMode(); ok {
+		_spec.AddField(label.FieldMode, field.TypeInt, value)
+	}
+	if value, ok := luo.mutation.Conditions(); ok {
+		_spec.SetField(label.FieldConditions, field.TypeString, value)
+	}
+	if luo.mutation.ConditionsCleared() {
+		_spec.ClearField(label.FieldConditions, field.TypeString)
+	}
+	if luo.mutation.LabelRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := luo.mutation.RemovedLabelRelationshipsIDs(); len(nodes) > 0 && !luo.mutation.LabelRelationshipsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.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 := luo.mutation.LabelRelationshipsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   label.LabelRelationshipsTable,
+			Columns: []string{label.LabelRelationshipsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &Label{config: luo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, luo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{label.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	luo.mutation.done = true
+	return _node, nil
+}

+ 207 - 0
ent/labelrelationship.go

@@ -0,0 +1,207 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// LabelRelationship is the model entity for the LabelRelationship schema.
+type LabelRelationship 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"`
+	// Delete Time | 删除日期
+	DeletedAt time.Time `json:"deleted_at,omitempty"`
+	// 标签 ID
+	LabelID uint64 `json:"label_id,omitempty"`
+	// 联系人 ID
+	ContactID uint64 `json:"contact_id,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the LabelRelationshipQuery when eager-loading is set.
+	Edges        LabelRelationshipEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// LabelRelationshipEdges holds the relations/edges for other nodes in the graph.
+type LabelRelationshipEdges struct {
+	// Contacts holds the value of the contacts edge.
+	Contacts *Contact `json:"contacts,omitempty"`
+	// Labels holds the value of the labels edge.
+	Labels *Label `json:"labels,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [2]bool
+}
+
+// ContactsOrErr returns the Contacts value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e LabelRelationshipEdges) ContactsOrErr() (*Contact, error) {
+	if e.Contacts != nil {
+		return e.Contacts, nil
+	} else if e.loadedTypes[0] {
+		return nil, &NotFoundError{label: contact.Label}
+	}
+	return nil, &NotLoadedError{edge: "contacts"}
+}
+
+// LabelsOrErr returns the Labels value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e LabelRelationshipEdges) LabelsOrErr() (*Label, error) {
+	if e.Labels != nil {
+		return e.Labels, nil
+	} else if e.loadedTypes[1] {
+		return nil, &NotFoundError{label: label.Label}
+	}
+	return nil, &NotLoadedError{edge: "labels"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*LabelRelationship) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case labelrelationship.FieldID, labelrelationship.FieldStatus, labelrelationship.FieldLabelID, labelrelationship.FieldContactID:
+			values[i] = new(sql.NullInt64)
+		case labelrelationship.FieldCreatedAt, labelrelationship.FieldUpdatedAt, labelrelationship.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 LabelRelationship fields.
+func (lr *LabelRelationship) 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 labelrelationship.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			lr.ID = uint64(value.Int64)
+		case labelrelationship.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 {
+				lr.CreatedAt = value.Time
+			}
+		case labelrelationship.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 {
+				lr.UpdatedAt = value.Time
+			}
+		case labelrelationship.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				lr.Status = uint8(value.Int64)
+			}
+		case labelrelationship.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 {
+				lr.DeletedAt = value.Time
+			}
+		case labelrelationship.FieldLabelID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field label_id", values[i])
+			} else if value.Valid {
+				lr.LabelID = uint64(value.Int64)
+			}
+		case labelrelationship.FieldContactID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field contact_id", values[i])
+			} else if value.Valid {
+				lr.ContactID = uint64(value.Int64)
+			}
+		default:
+			lr.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the LabelRelationship.
+// This includes values selected through modifiers, order, etc.
+func (lr *LabelRelationship) Value(name string) (ent.Value, error) {
+	return lr.selectValues.Get(name)
+}
+
+// QueryContacts queries the "contacts" edge of the LabelRelationship entity.
+func (lr *LabelRelationship) QueryContacts() *ContactQuery {
+	return NewLabelRelationshipClient(lr.config).QueryContacts(lr)
+}
+
+// QueryLabels queries the "labels" edge of the LabelRelationship entity.
+func (lr *LabelRelationship) QueryLabels() *LabelQuery {
+	return NewLabelRelationshipClient(lr.config).QueryLabels(lr)
+}
+
+// Update returns a builder for updating this LabelRelationship.
+// Note that you need to call LabelRelationship.Unwrap() before calling this method if this LabelRelationship
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (lr *LabelRelationship) Update() *LabelRelationshipUpdateOne {
+	return NewLabelRelationshipClient(lr.config).UpdateOne(lr)
+}
+
+// Unwrap unwraps the LabelRelationship 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 (lr *LabelRelationship) Unwrap() *LabelRelationship {
+	_tx, ok := lr.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: LabelRelationship is not a transactional entity")
+	}
+	lr.config.driver = _tx.drv
+	return lr
+}
+
+// String implements the fmt.Stringer.
+func (lr *LabelRelationship) String() string {
+	var builder strings.Builder
+	builder.WriteString("LabelRelationship(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", lr.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(lr.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(lr.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", lr.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(lr.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("label_id=")
+	builder.WriteString(fmt.Sprintf("%v", lr.LabelID))
+	builder.WriteString(", ")
+	builder.WriteString("contact_id=")
+	builder.WriteString(fmt.Sprintf("%v", lr.ContactID))
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// LabelRelationships is a parsable slice of LabelRelationship.
+type LabelRelationships []*LabelRelationship

+ 159 - 0
ent/labelrelationship/labelrelationship.go

@@ -0,0 +1,159 @@
+// Code generated by ent, DO NOT EDIT.
+
+package labelrelationship
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the labelrelationship type in the database.
+	Label = "label_relationship"
+	// 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"
+	// FieldDeletedAt holds the string denoting the deleted_at field in the database.
+	FieldDeletedAt = "deleted_at"
+	// FieldLabelID holds the string denoting the label_id field in the database.
+	FieldLabelID = "label_id"
+	// FieldContactID holds the string denoting the contact_id field in the database.
+	FieldContactID = "contact_id"
+	// EdgeContacts holds the string denoting the contacts edge name in mutations.
+	EdgeContacts = "contacts"
+	// EdgeLabels holds the string denoting the labels edge name in mutations.
+	EdgeLabels = "labels"
+	// Table holds the table name of the labelrelationship in the database.
+	Table = "label_relationship"
+	// ContactsTable is the table that holds the contacts relation/edge.
+	ContactsTable = "label_relationship"
+	// ContactsInverseTable is the table name for the Contact entity.
+	// It exists in this package in order to avoid circular dependency with the "contact" package.
+	ContactsInverseTable = "contact"
+	// ContactsColumn is the table column denoting the contacts relation/edge.
+	ContactsColumn = "contact_id"
+	// LabelsTable is the table that holds the labels relation/edge.
+	LabelsTable = "label_relationship"
+	// LabelsInverseTable is the table name for the Label entity.
+	// It exists in this package in order to avoid circular dependency with the "label" package.
+	LabelsInverseTable = "label"
+	// LabelsColumn is the table column denoting the labels relation/edge.
+	LabelsColumn = "label_id"
+)
+
+// Columns holds all SQL columns for labelrelationship fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldLabelID,
+	FieldContactID,
+}
+
+// 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
+}
+
+// Note that the variables below are initialized by the runtime
+// package on the initialization of the application. Therefore,
+// it should be imported in the main as follows:
+//
+//	import _ "wechat-api/ent/runtime"
+var (
+	Hooks        [1]ent.Hook
+	Interceptors [1]ent.Interceptor
+	// 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
+	// DefaultLabelID holds the default value on creation for the "label_id" field.
+	DefaultLabelID uint64
+	// DefaultContactID holds the default value on creation for the "contact_id" field.
+	DefaultContactID uint64
+)
+
+// OrderOption defines the ordering options for the LabelRelationship 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()
+}
+
+// ByDeletedAt orders the results by the deleted_at field.
+func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
+}
+
+// ByLabelID orders the results by the label_id field.
+func ByLabelID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldLabelID, opts...).ToFunc()
+}
+
+// ByContactID orders the results by the contact_id field.
+func ByContactID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldContactID, opts...).ToFunc()
+}
+
+// ByContactsField orders the results by contacts field.
+func ByContactsField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newContactsStep(), sql.OrderByField(field, opts...))
+	}
+}
+
+// ByLabelsField orders the results by labels field.
+func ByLabelsField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newLabelsStep(), sql.OrderByField(field, opts...))
+	}
+}
+func newContactsStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(ContactsInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, ContactsTable, ContactsColumn),
+	)
+}
+func newLabelsStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(LabelsInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, LabelsTable, LabelsColumn),
+	)
+}

+ 367 - 0
ent/labelrelationship/where.go

@@ -0,0 +1,367 @@
+// Code generated by ent, DO NOT EDIT.
+
+package labelrelationship
+
+import (
+	"time"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(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.LabelRelationship {
+	return predicate.LabelRelationship(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.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldStatus, v))
+}
+
+// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ.
+func DeletedAt(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// LabelID applies equality check predicate on the "label_id" field. It's identical to LabelIDEQ.
+func LabelID(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldLabelID, v))
+}
+
+// ContactID applies equality check predicate on the "contact_id" field. It's identical to ContactIDEQ.
+func ContactID(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldContactID, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// LabelIDEQ applies the EQ predicate on the "label_id" field.
+func LabelIDEQ(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldLabelID, v))
+}
+
+// LabelIDNEQ applies the NEQ predicate on the "label_id" field.
+func LabelIDNEQ(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldLabelID, v))
+}
+
+// LabelIDIn applies the In predicate on the "label_id" field.
+func LabelIDIn(vs ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldLabelID, vs...))
+}
+
+// LabelIDNotIn applies the NotIn predicate on the "label_id" field.
+func LabelIDNotIn(vs ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldLabelID, vs...))
+}
+
+// ContactIDEQ applies the EQ predicate on the "contact_id" field.
+func ContactIDEQ(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldEQ(FieldContactID, v))
+}
+
+// ContactIDNEQ applies the NEQ predicate on the "contact_id" field.
+func ContactIDNEQ(v uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNEQ(FieldContactID, v))
+}
+
+// ContactIDIn applies the In predicate on the "contact_id" field.
+func ContactIDIn(vs ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldIn(FieldContactID, vs...))
+}
+
+// ContactIDNotIn applies the NotIn predicate on the "contact_id" field.
+func ContactIDNotIn(vs ...uint64) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.FieldNotIn(FieldContactID, vs...))
+}
+
+// HasContacts applies the HasEdge predicate on the "contacts" edge.
+func HasContacts() predicate.LabelRelationship {
+	return predicate.LabelRelationship(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, ContactsTable, ContactsColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasContactsWith applies the HasEdge predicate on the "contacts" edge with a given conditions (other predicates).
+func HasContactsWith(preds ...predicate.Contact) predicate.LabelRelationship {
+	return predicate.LabelRelationship(func(s *sql.Selector) {
+		step := newContactsStep()
+		sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
+			for _, p := range preds {
+				p(s)
+			}
+		})
+	})
+}
+
+// HasLabels applies the HasEdge predicate on the "labels" edge.
+func HasLabels() predicate.LabelRelationship {
+	return predicate.LabelRelationship(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, LabelsTable, LabelsColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasLabelsWith applies the HasEdge predicate on the "labels" edge with a given conditions (other predicates).
+func HasLabelsWith(preds ...predicate.Label) predicate.LabelRelationship {
+	return predicate.LabelRelationship(func(s *sql.Selector) {
+		step := newLabelsStep()
+		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.LabelRelationship) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.LabelRelationship) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.LabelRelationship) predicate.LabelRelationship {
+	return predicate.LabelRelationship(sql.NotPredicates(p))
+}

+ 909 - 0
ent/labelrelationship_create.go

@@ -0,0 +1,909 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// LabelRelationshipCreate is the builder for creating a LabelRelationship entity.
+type LabelRelationshipCreate struct {
+	config
+	mutation *LabelRelationshipMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (lrc *LabelRelationshipCreate) SetCreatedAt(t time.Time) *LabelRelationshipCreate {
+	lrc.mutation.SetCreatedAt(t)
+	return lrc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableCreatedAt(t *time.Time) *LabelRelationshipCreate {
+	if t != nil {
+		lrc.SetCreatedAt(*t)
+	}
+	return lrc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (lrc *LabelRelationshipCreate) SetUpdatedAt(t time.Time) *LabelRelationshipCreate {
+	lrc.mutation.SetUpdatedAt(t)
+	return lrc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableUpdatedAt(t *time.Time) *LabelRelationshipCreate {
+	if t != nil {
+		lrc.SetUpdatedAt(*t)
+	}
+	return lrc
+}
+
+// SetStatus sets the "status" field.
+func (lrc *LabelRelationshipCreate) SetStatus(u uint8) *LabelRelationshipCreate {
+	lrc.mutation.SetStatus(u)
+	return lrc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableStatus(u *uint8) *LabelRelationshipCreate {
+	if u != nil {
+		lrc.SetStatus(*u)
+	}
+	return lrc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (lrc *LabelRelationshipCreate) SetDeletedAt(t time.Time) *LabelRelationshipCreate {
+	lrc.mutation.SetDeletedAt(t)
+	return lrc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableDeletedAt(t *time.Time) *LabelRelationshipCreate {
+	if t != nil {
+		lrc.SetDeletedAt(*t)
+	}
+	return lrc
+}
+
+// SetLabelID sets the "label_id" field.
+func (lrc *LabelRelationshipCreate) SetLabelID(u uint64) *LabelRelationshipCreate {
+	lrc.mutation.SetLabelID(u)
+	return lrc
+}
+
+// SetNillableLabelID sets the "label_id" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableLabelID(u *uint64) *LabelRelationshipCreate {
+	if u != nil {
+		lrc.SetLabelID(*u)
+	}
+	return lrc
+}
+
+// SetContactID sets the "contact_id" field.
+func (lrc *LabelRelationshipCreate) SetContactID(u uint64) *LabelRelationshipCreate {
+	lrc.mutation.SetContactID(u)
+	return lrc
+}
+
+// SetNillableContactID sets the "contact_id" field if the given value is not nil.
+func (lrc *LabelRelationshipCreate) SetNillableContactID(u *uint64) *LabelRelationshipCreate {
+	if u != nil {
+		lrc.SetContactID(*u)
+	}
+	return lrc
+}
+
+// SetID sets the "id" field.
+func (lrc *LabelRelationshipCreate) SetID(u uint64) *LabelRelationshipCreate {
+	lrc.mutation.SetID(u)
+	return lrc
+}
+
+// SetContactsID sets the "contacts" edge to the Contact entity by ID.
+func (lrc *LabelRelationshipCreate) SetContactsID(id uint64) *LabelRelationshipCreate {
+	lrc.mutation.SetContactsID(id)
+	return lrc
+}
+
+// SetContacts sets the "contacts" edge to the Contact entity.
+func (lrc *LabelRelationshipCreate) SetContacts(c *Contact) *LabelRelationshipCreate {
+	return lrc.SetContactsID(c.ID)
+}
+
+// SetLabelsID sets the "labels" edge to the Label entity by ID.
+func (lrc *LabelRelationshipCreate) SetLabelsID(id uint64) *LabelRelationshipCreate {
+	lrc.mutation.SetLabelsID(id)
+	return lrc
+}
+
+// SetLabels sets the "labels" edge to the Label entity.
+func (lrc *LabelRelationshipCreate) SetLabels(l *Label) *LabelRelationshipCreate {
+	return lrc.SetLabelsID(l.ID)
+}
+
+// Mutation returns the LabelRelationshipMutation object of the builder.
+func (lrc *LabelRelationshipCreate) Mutation() *LabelRelationshipMutation {
+	return lrc.mutation
+}
+
+// Save creates the LabelRelationship in the database.
+func (lrc *LabelRelationshipCreate) Save(ctx context.Context) (*LabelRelationship, error) {
+	if err := lrc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, lrc.sqlSave, lrc.mutation, lrc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (lrc *LabelRelationshipCreate) SaveX(ctx context.Context) *LabelRelationship {
+	v, err := lrc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (lrc *LabelRelationshipCreate) Exec(ctx context.Context) error {
+	_, err := lrc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lrc *LabelRelationshipCreate) ExecX(ctx context.Context) {
+	if err := lrc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (lrc *LabelRelationshipCreate) defaults() error {
+	if _, ok := lrc.mutation.CreatedAt(); !ok {
+		if labelrelationship.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized labelrelationship.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := labelrelationship.DefaultCreatedAt()
+		lrc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := lrc.mutation.UpdatedAt(); !ok {
+		if labelrelationship.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized labelrelationship.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := labelrelationship.DefaultUpdatedAt()
+		lrc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := lrc.mutation.Status(); !ok {
+		v := labelrelationship.DefaultStatus
+		lrc.mutation.SetStatus(v)
+	}
+	if _, ok := lrc.mutation.LabelID(); !ok {
+		v := labelrelationship.DefaultLabelID
+		lrc.mutation.SetLabelID(v)
+	}
+	if _, ok := lrc.mutation.ContactID(); !ok {
+		v := labelrelationship.DefaultContactID
+		lrc.mutation.SetContactID(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (lrc *LabelRelationshipCreate) check() error {
+	if _, ok := lrc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "LabelRelationship.created_at"`)}
+	}
+	if _, ok := lrc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "LabelRelationship.updated_at"`)}
+	}
+	if _, ok := lrc.mutation.LabelID(); !ok {
+		return &ValidationError{Name: "label_id", err: errors.New(`ent: missing required field "LabelRelationship.label_id"`)}
+	}
+	if _, ok := lrc.mutation.ContactID(); !ok {
+		return &ValidationError{Name: "contact_id", err: errors.New(`ent: missing required field "LabelRelationship.contact_id"`)}
+	}
+	if _, ok := lrc.mutation.ContactsID(); !ok {
+		return &ValidationError{Name: "contacts", err: errors.New(`ent: missing required edge "LabelRelationship.contacts"`)}
+	}
+	if _, ok := lrc.mutation.LabelsID(); !ok {
+		return &ValidationError{Name: "labels", err: errors.New(`ent: missing required edge "LabelRelationship.labels"`)}
+	}
+	return nil
+}
+
+func (lrc *LabelRelationshipCreate) sqlSave(ctx context.Context) (*LabelRelationship, error) {
+	if err := lrc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := lrc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, lrc.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)
+	}
+	lrc.mutation.id = &_node.ID
+	lrc.mutation.done = true
+	return _node, nil
+}
+
+func (lrc *LabelRelationshipCreate) createSpec() (*LabelRelationship, *sqlgraph.CreateSpec) {
+	var (
+		_node = &LabelRelationship{config: lrc.config}
+		_spec = sqlgraph.NewCreateSpec(labelrelationship.Table, sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = lrc.conflict
+	if id, ok := lrc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := lrc.mutation.CreatedAt(); ok {
+		_spec.SetField(labelrelationship.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := lrc.mutation.UpdatedAt(); ok {
+		_spec.SetField(labelrelationship.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := lrc.mutation.Status(); ok {
+		_spec.SetField(labelrelationship.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := lrc.mutation.DeletedAt(); ok {
+		_spec.SetField(labelrelationship.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if nodes := lrc.mutation.ContactsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.ContactsTable,
+			Columns: []string{labelrelationship.ContactsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.ContactID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	if nodes := lrc.mutation.LabelsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.LabelsTable,
+			Columns: []string{labelrelationship.LabelsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.LabelID = nodes[0]
+		_spec.Edges = append(_spec.Edges, edge)
+	}
+	return _node, _spec
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.LabelRelationship.Create().
+//		SetCreatedAt(v).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.LabelRelationshipUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (lrc *LabelRelationshipCreate) OnConflict(opts ...sql.ConflictOption) *LabelRelationshipUpsertOne {
+	lrc.conflict = opts
+	return &LabelRelationshipUpsertOne{
+		create: lrc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (lrc *LabelRelationshipCreate) OnConflictColumns(columns ...string) *LabelRelationshipUpsertOne {
+	lrc.conflict = append(lrc.conflict, sql.ConflictColumns(columns...))
+	return &LabelRelationshipUpsertOne{
+		create: lrc,
+	}
+}
+
+type (
+	// LabelRelationshipUpsertOne is the builder for "upsert"-ing
+	//  one LabelRelationship node.
+	LabelRelationshipUpsertOne struct {
+		create *LabelRelationshipCreate
+	}
+
+	// LabelRelationshipUpsert is the "OnConflict" setter.
+	LabelRelationshipUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelRelationshipUpsert) SetUpdatedAt(v time.Time) *LabelRelationshipUpsert {
+	u.Set(labelrelationship.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsert) UpdateUpdatedAt() *LabelRelationshipUpsert {
+	u.SetExcluded(labelrelationship.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelRelationshipUpsert) SetStatus(v uint8) *LabelRelationshipUpsert {
+	u.Set(labelrelationship.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelRelationshipUpsert) UpdateStatus() *LabelRelationshipUpsert {
+	u.SetExcluded(labelrelationship.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelRelationshipUpsert) AddStatus(v uint8) *LabelRelationshipUpsert {
+	u.Add(labelrelationship.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelRelationshipUpsert) ClearStatus() *LabelRelationshipUpsert {
+	u.SetNull(labelrelationship.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelRelationshipUpsert) SetDeletedAt(v time.Time) *LabelRelationshipUpsert {
+	u.Set(labelrelationship.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsert) UpdateDeletedAt() *LabelRelationshipUpsert {
+	u.SetExcluded(labelrelationship.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelRelationshipUpsert) ClearDeletedAt() *LabelRelationshipUpsert {
+	u.SetNull(labelrelationship.FieldDeletedAt)
+	return u
+}
+
+// SetLabelID sets the "label_id" field.
+func (u *LabelRelationshipUpsert) SetLabelID(v uint64) *LabelRelationshipUpsert {
+	u.Set(labelrelationship.FieldLabelID, v)
+	return u
+}
+
+// UpdateLabelID sets the "label_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsert) UpdateLabelID() *LabelRelationshipUpsert {
+	u.SetExcluded(labelrelationship.FieldLabelID)
+	return u
+}
+
+// SetContactID sets the "contact_id" field.
+func (u *LabelRelationshipUpsert) SetContactID(v uint64) *LabelRelationshipUpsert {
+	u.Set(labelrelationship.FieldContactID, v)
+	return u
+}
+
+// UpdateContactID sets the "contact_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsert) UpdateContactID() *LabelRelationshipUpsert {
+	u.SetExcluded(labelrelationship.FieldContactID)
+	return u
+}
+
+// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.
+// Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(labelrelationship.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *LabelRelationshipUpsertOne) UpdateNewValues() *LabelRelationshipUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		if _, exists := u.create.mutation.ID(); exists {
+			s.SetIgnore(labelrelationship.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(labelrelationship.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *LabelRelationshipUpsertOne) Ignore() *LabelRelationshipUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *LabelRelationshipUpsertOne) DoNothing() *LabelRelationshipUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the LabelRelationshipCreate.OnConflict
+// documentation for more info.
+func (u *LabelRelationshipUpsertOne) Update(set func(*LabelRelationshipUpsert)) *LabelRelationshipUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&LabelRelationshipUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelRelationshipUpsertOne) SetUpdatedAt(v time.Time) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertOne) UpdateUpdatedAt() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelRelationshipUpsertOne) SetStatus(v uint8) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelRelationshipUpsertOne) AddStatus(v uint8) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertOne) UpdateStatus() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelRelationshipUpsertOne) ClearStatus() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelRelationshipUpsertOne) SetDeletedAt(v time.Time) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertOne) UpdateDeletedAt() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelRelationshipUpsertOne) ClearDeletedAt() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetLabelID sets the "label_id" field.
+func (u *LabelRelationshipUpsertOne) SetLabelID(v uint64) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetLabelID(v)
+	})
+}
+
+// UpdateLabelID sets the "label_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertOne) UpdateLabelID() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateLabelID()
+	})
+}
+
+// SetContactID sets the "contact_id" field.
+func (u *LabelRelationshipUpsertOne) SetContactID(v uint64) *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetContactID(v)
+	})
+}
+
+// UpdateContactID sets the "contact_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertOne) UpdateContactID() *LabelRelationshipUpsertOne {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateContactID()
+	})
+}
+
+// Exec executes the query.
+func (u *LabelRelationshipUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for LabelRelationshipCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *LabelRelationshipUpsertOne) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// Exec executes the UPSERT query and returns the inserted/updated ID.
+func (u *LabelRelationshipUpsertOne) ID(ctx context.Context) (id uint64, err error) {
+	node, err := u.create.Save(ctx)
+	if err != nil {
+		return id, err
+	}
+	return node.ID, nil
+}
+
+// IDX is like ID, but panics if an error occurs.
+func (u *LabelRelationshipUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// LabelRelationshipCreateBulk is the builder for creating many LabelRelationship entities in bulk.
+type LabelRelationshipCreateBulk struct {
+	config
+	err      error
+	builders []*LabelRelationshipCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the LabelRelationship entities in the database.
+func (lrcb *LabelRelationshipCreateBulk) Save(ctx context.Context) ([]*LabelRelationship, error) {
+	if lrcb.err != nil {
+		return nil, lrcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(lrcb.builders))
+	nodes := make([]*LabelRelationship, len(lrcb.builders))
+	mutators := make([]Mutator, len(lrcb.builders))
+	for i := range lrcb.builders {
+		func(i int, root context.Context) {
+			builder := lrcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*LabelRelationshipMutation)
+				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, lrcb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = lrcb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, lrcb.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, lrcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (lrcb *LabelRelationshipCreateBulk) SaveX(ctx context.Context) []*LabelRelationship {
+	v, err := lrcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (lrcb *LabelRelationshipCreateBulk) Exec(ctx context.Context) error {
+	_, err := lrcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lrcb *LabelRelationshipCreateBulk) ExecX(ctx context.Context) {
+	if err := lrcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.LabelRelationship.CreateBulk(builders...).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.LabelRelationshipUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (lrcb *LabelRelationshipCreateBulk) OnConflict(opts ...sql.ConflictOption) *LabelRelationshipUpsertBulk {
+	lrcb.conflict = opts
+	return &LabelRelationshipUpsertBulk{
+		create: lrcb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (lrcb *LabelRelationshipCreateBulk) OnConflictColumns(columns ...string) *LabelRelationshipUpsertBulk {
+	lrcb.conflict = append(lrcb.conflict, sql.ConflictColumns(columns...))
+	return &LabelRelationshipUpsertBulk{
+		create: lrcb,
+	}
+}
+
+// LabelRelationshipUpsertBulk is the builder for "upsert"-ing
+// a bulk of LabelRelationship nodes.
+type LabelRelationshipUpsertBulk struct {
+	create *LabelRelationshipCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(labelrelationship.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *LabelRelationshipUpsertBulk) UpdateNewValues() *LabelRelationshipUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
+		for _, b := range u.create.builders {
+			if _, exists := b.mutation.ID(); exists {
+				s.SetIgnore(labelrelationship.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(labelrelationship.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.LabelRelationship.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *LabelRelationshipUpsertBulk) Ignore() *LabelRelationshipUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *LabelRelationshipUpsertBulk) DoNothing() *LabelRelationshipUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the LabelRelationshipCreateBulk.OnConflict
+// documentation for more info.
+func (u *LabelRelationshipUpsertBulk) Update(set func(*LabelRelationshipUpsert)) *LabelRelationshipUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&LabelRelationshipUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *LabelRelationshipUpsertBulk) SetUpdatedAt(v time.Time) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertBulk) UpdateUpdatedAt() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *LabelRelationshipUpsertBulk) SetStatus(v uint8) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *LabelRelationshipUpsertBulk) AddStatus(v uint8) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertBulk) UpdateStatus() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *LabelRelationshipUpsertBulk) ClearStatus() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *LabelRelationshipUpsertBulk) SetDeletedAt(v time.Time) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertBulk) UpdateDeletedAt() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *LabelRelationshipUpsertBulk) ClearDeletedAt() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetLabelID sets the "label_id" field.
+func (u *LabelRelationshipUpsertBulk) SetLabelID(v uint64) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetLabelID(v)
+	})
+}
+
+// UpdateLabelID sets the "label_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertBulk) UpdateLabelID() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateLabelID()
+	})
+}
+
+// SetContactID sets the "contact_id" field.
+func (u *LabelRelationshipUpsertBulk) SetContactID(v uint64) *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.SetContactID(v)
+	})
+}
+
+// UpdateContactID sets the "contact_id" field to the value that was provided on create.
+func (u *LabelRelationshipUpsertBulk) UpdateContactID() *LabelRelationshipUpsertBulk {
+	return u.Update(func(s *LabelRelationshipUpsert) {
+		s.UpdateContactID()
+	})
+}
+
+// Exec executes the query.
+func (u *LabelRelationshipUpsertBulk) Exec(ctx context.Context) error {
+	if u.create.err != nil {
+		return u.create.err
+	}
+	for i, b := range u.create.builders {
+		if len(b.conflict) != 0 {
+			return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the LabelRelationshipCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for LabelRelationshipCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *LabelRelationshipUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/labelrelationship_delete.go

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

+ 680 - 0
ent/labelrelationship_query.go

@@ -0,0 +1,680 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"fmt"
+	"math"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// LabelRelationshipQuery is the builder for querying LabelRelationship entities.
+type LabelRelationshipQuery struct {
+	config
+	ctx          *QueryContext
+	order        []labelrelationship.OrderOption
+	inters       []Interceptor
+	predicates   []predicate.LabelRelationship
+	withContacts *ContactQuery
+	withLabels   *LabelQuery
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the LabelRelationshipQuery builder.
+func (lrq *LabelRelationshipQuery) Where(ps ...predicate.LabelRelationship) *LabelRelationshipQuery {
+	lrq.predicates = append(lrq.predicates, ps...)
+	return lrq
+}
+
+// Limit the number of records to be returned by this query.
+func (lrq *LabelRelationshipQuery) Limit(limit int) *LabelRelationshipQuery {
+	lrq.ctx.Limit = &limit
+	return lrq
+}
+
+// Offset to start from.
+func (lrq *LabelRelationshipQuery) Offset(offset int) *LabelRelationshipQuery {
+	lrq.ctx.Offset = &offset
+	return lrq
+}
+
+// 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 (lrq *LabelRelationshipQuery) Unique(unique bool) *LabelRelationshipQuery {
+	lrq.ctx.Unique = &unique
+	return lrq
+}
+
+// Order specifies how the records should be ordered.
+func (lrq *LabelRelationshipQuery) Order(o ...labelrelationship.OrderOption) *LabelRelationshipQuery {
+	lrq.order = append(lrq.order, o...)
+	return lrq
+}
+
+// QueryContacts chains the current query on the "contacts" edge.
+func (lrq *LabelRelationshipQuery) QueryContacts() *ContactQuery {
+	query := (&ContactClient{config: lrq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := lrq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := lrq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(labelrelationship.Table, labelrelationship.FieldID, selector),
+			sqlgraph.To(contact.Table, contact.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, labelrelationship.ContactsTable, labelrelationship.ContactsColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(lrq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// QueryLabels chains the current query on the "labels" edge.
+func (lrq *LabelRelationshipQuery) QueryLabels() *LabelQuery {
+	query := (&LabelClient{config: lrq.config}).Query()
+	query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
+		if err := lrq.prepareQuery(ctx); err != nil {
+			return nil, err
+		}
+		selector := lrq.sqlQuery(ctx)
+		if err := selector.Err(); err != nil {
+			return nil, err
+		}
+		step := sqlgraph.NewStep(
+			sqlgraph.From(labelrelationship.Table, labelrelationship.FieldID, selector),
+			sqlgraph.To(label.Table, label.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, labelrelationship.LabelsTable, labelrelationship.LabelsColumn),
+		)
+		fromU = sqlgraph.SetNeighbors(lrq.driver.Dialect(), step)
+		return fromU, nil
+	}
+	return query
+}
+
+// First returns the first LabelRelationship entity from the query.
+// Returns a *NotFoundError when no LabelRelationship was found.
+func (lrq *LabelRelationshipQuery) First(ctx context.Context) (*LabelRelationship, error) {
+	nodes, err := lrq.Limit(1).All(setContextOp(ctx, lrq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{labelrelationship.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) FirstX(ctx context.Context) *LabelRelationship {
+	node, err := lrq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first LabelRelationship ID from the query.
+// Returns a *NotFoundError when no LabelRelationship ID was found.
+func (lrq *LabelRelationshipQuery) FirstID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = lrq.Limit(1).IDs(setContextOp(ctx, lrq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{labelrelationship.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) FirstIDX(ctx context.Context) uint64 {
+	id, err := lrq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single LabelRelationship entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one LabelRelationship entity is found.
+// Returns a *NotFoundError when no LabelRelationship entities are found.
+func (lrq *LabelRelationshipQuery) Only(ctx context.Context) (*LabelRelationship, error) {
+	nodes, err := lrq.Limit(2).All(setContextOp(ctx, lrq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{labelrelationship.Label}
+	default:
+		return nil, &NotSingularError{labelrelationship.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) OnlyX(ctx context.Context) *LabelRelationship {
+	node, err := lrq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only LabelRelationship ID in the query.
+// Returns a *NotSingularError when more than one LabelRelationship ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (lrq *LabelRelationshipQuery) OnlyID(ctx context.Context) (id uint64, err error) {
+	var ids []uint64
+	if ids, err = lrq.Limit(2).IDs(setContextOp(ctx, lrq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{labelrelationship.Label}
+	default:
+		err = &NotSingularError{labelrelationship.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) OnlyIDX(ctx context.Context) uint64 {
+	id, err := lrq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of LabelRelationships.
+func (lrq *LabelRelationshipQuery) All(ctx context.Context) ([]*LabelRelationship, error) {
+	ctx = setContextOp(ctx, lrq.ctx, "All")
+	if err := lrq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*LabelRelationship, *LabelRelationshipQuery]()
+	return withInterceptors[[]*LabelRelationship](ctx, lrq, qr, lrq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) AllX(ctx context.Context) []*LabelRelationship {
+	nodes, err := lrq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of LabelRelationship IDs.
+func (lrq *LabelRelationshipQuery) IDs(ctx context.Context) (ids []uint64, err error) {
+	if lrq.ctx.Unique == nil && lrq.path != nil {
+		lrq.Unique(true)
+	}
+	ctx = setContextOp(ctx, lrq.ctx, "IDs")
+	if err = lrq.Select(labelrelationship.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) IDsX(ctx context.Context) []uint64 {
+	ids, err := lrq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (lrq *LabelRelationshipQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, lrq.ctx, "Count")
+	if err := lrq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, lrq, querierCount[*LabelRelationshipQuery](), lrq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (lrq *LabelRelationshipQuery) CountX(ctx context.Context) int {
+	count, err := lrq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (lrq *LabelRelationshipQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, lrq.ctx, "Exist")
+	switch _, err := lrq.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 (lrq *LabelRelationshipQuery) ExistX(ctx context.Context) bool {
+	exist, err := lrq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the LabelRelationshipQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (lrq *LabelRelationshipQuery) Clone() *LabelRelationshipQuery {
+	if lrq == nil {
+		return nil
+	}
+	return &LabelRelationshipQuery{
+		config:       lrq.config,
+		ctx:          lrq.ctx.Clone(),
+		order:        append([]labelrelationship.OrderOption{}, lrq.order...),
+		inters:       append([]Interceptor{}, lrq.inters...),
+		predicates:   append([]predicate.LabelRelationship{}, lrq.predicates...),
+		withContacts: lrq.withContacts.Clone(),
+		withLabels:   lrq.withLabels.Clone(),
+		// clone intermediate query.
+		sql:  lrq.sql.Clone(),
+		path: lrq.path,
+	}
+}
+
+// WithContacts tells the query-builder to eager-load the nodes that are connected to
+// the "contacts" edge. The optional arguments are used to configure the query builder of the edge.
+func (lrq *LabelRelationshipQuery) WithContacts(opts ...func(*ContactQuery)) *LabelRelationshipQuery {
+	query := (&ContactClient{config: lrq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	lrq.withContacts = query
+	return lrq
+}
+
+// WithLabels tells the query-builder to eager-load the nodes that are connected to
+// the "labels" edge. The optional arguments are used to configure the query builder of the edge.
+func (lrq *LabelRelationshipQuery) WithLabels(opts ...func(*LabelQuery)) *LabelRelationshipQuery {
+	query := (&LabelClient{config: lrq.config}).Query()
+	for _, opt := range opts {
+		opt(query)
+	}
+	lrq.withLabels = query
+	return lrq
+}
+
+// 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.LabelRelationship.Query().
+//		GroupBy(labelrelationship.FieldCreatedAt).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (lrq *LabelRelationshipQuery) GroupBy(field string, fields ...string) *LabelRelationshipGroupBy {
+	lrq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &LabelRelationshipGroupBy{build: lrq}
+	grbuild.flds = &lrq.ctx.Fields
+	grbuild.label = labelrelationship.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.LabelRelationship.Query().
+//		Select(labelrelationship.FieldCreatedAt).
+//		Scan(ctx, &v)
+func (lrq *LabelRelationshipQuery) Select(fields ...string) *LabelRelationshipSelect {
+	lrq.ctx.Fields = append(lrq.ctx.Fields, fields...)
+	sbuild := &LabelRelationshipSelect{LabelRelationshipQuery: lrq}
+	sbuild.label = labelrelationship.Label
+	sbuild.flds, sbuild.scan = &lrq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a LabelRelationshipSelect configured with the given aggregations.
+func (lrq *LabelRelationshipQuery) Aggregate(fns ...AggregateFunc) *LabelRelationshipSelect {
+	return lrq.Select().Aggregate(fns...)
+}
+
+func (lrq *LabelRelationshipQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range lrq.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, lrq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range lrq.ctx.Fields {
+		if !labelrelationship.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if lrq.path != nil {
+		prev, err := lrq.path(ctx)
+		if err != nil {
+			return err
+		}
+		lrq.sql = prev
+	}
+	return nil
+}
+
+func (lrq *LabelRelationshipQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*LabelRelationship, error) {
+	var (
+		nodes       = []*LabelRelationship{}
+		_spec       = lrq.querySpec()
+		loadedTypes = [2]bool{
+			lrq.withContacts != nil,
+			lrq.withLabels != nil,
+		}
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*LabelRelationship).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &LabelRelationship{config: lrq.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, lrq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	if query := lrq.withContacts; query != nil {
+		if err := lrq.loadContacts(ctx, query, nodes, nil,
+			func(n *LabelRelationship, e *Contact) { n.Edges.Contacts = e }); err != nil {
+			return nil, err
+		}
+	}
+	if query := lrq.withLabels; query != nil {
+		if err := lrq.loadLabels(ctx, query, nodes, nil,
+			func(n *LabelRelationship, e *Label) { n.Edges.Labels = e }); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+func (lrq *LabelRelationshipQuery) loadContacts(ctx context.Context, query *ContactQuery, nodes []*LabelRelationship, init func(*LabelRelationship), assign func(*LabelRelationship, *Contact)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*LabelRelationship)
+	for i := range nodes {
+		fk := nodes[i].ContactID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(contact.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 "contact_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+func (lrq *LabelRelationshipQuery) loadLabels(ctx context.Context, query *LabelQuery, nodes []*LabelRelationship, init func(*LabelRelationship), assign func(*LabelRelationship, *Label)) error {
+	ids := make([]uint64, 0, len(nodes))
+	nodeids := make(map[uint64][]*LabelRelationship)
+	for i := range nodes {
+		fk := nodes[i].LabelID
+		if _, ok := nodeids[fk]; !ok {
+			ids = append(ids, fk)
+		}
+		nodeids[fk] = append(nodeids[fk], nodes[i])
+	}
+	if len(ids) == 0 {
+		return nil
+	}
+	query.Where(label.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 "label_id" returned %v`, n.ID)
+		}
+		for i := range nodes {
+			assign(nodes[i], n)
+		}
+	}
+	return nil
+}
+
+func (lrq *LabelRelationshipQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := lrq.querySpec()
+	_spec.Node.Columns = lrq.ctx.Fields
+	if len(lrq.ctx.Fields) > 0 {
+		_spec.Unique = lrq.ctx.Unique != nil && *lrq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, lrq.driver, _spec)
+}
+
+func (lrq *LabelRelationshipQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(labelrelationship.Table, labelrelationship.Columns, sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64))
+	_spec.From = lrq.sql
+	if unique := lrq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if lrq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := lrq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, labelrelationship.FieldID)
+		for i := range fields {
+			if fields[i] != labelrelationship.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+		if lrq.withContacts != nil {
+			_spec.Node.AddColumnOnce(labelrelationship.FieldContactID)
+		}
+		if lrq.withLabels != nil {
+			_spec.Node.AddColumnOnce(labelrelationship.FieldLabelID)
+		}
+	}
+	if ps := lrq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := lrq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := lrq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := lrq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (lrq *LabelRelationshipQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(lrq.driver.Dialect())
+	t1 := builder.Table(labelrelationship.Table)
+	columns := lrq.ctx.Fields
+	if len(columns) == 0 {
+		columns = labelrelationship.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if lrq.sql != nil {
+		selector = lrq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if lrq.ctx.Unique != nil && *lrq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range lrq.predicates {
+		p(selector)
+	}
+	for _, p := range lrq.order {
+		p(selector)
+	}
+	if offset := lrq.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 := lrq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// LabelRelationshipGroupBy is the group-by builder for LabelRelationship entities.
+type LabelRelationshipGroupBy struct {
+	selector
+	build *LabelRelationshipQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (lrgb *LabelRelationshipGroupBy) Aggregate(fns ...AggregateFunc) *LabelRelationshipGroupBy {
+	lrgb.fns = append(lrgb.fns, fns...)
+	return lrgb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (lrgb *LabelRelationshipGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, lrgb.build.ctx, "GroupBy")
+	if err := lrgb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*LabelRelationshipQuery, *LabelRelationshipGroupBy](ctx, lrgb.build, lrgb, lrgb.build.inters, v)
+}
+
+func (lrgb *LabelRelationshipGroupBy) sqlScan(ctx context.Context, root *LabelRelationshipQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(lrgb.fns))
+	for _, fn := range lrgb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*lrgb.flds)+len(lrgb.fns))
+		for _, f := range *lrgb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*lrgb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := lrgb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// LabelRelationshipSelect is the builder for selecting fields of LabelRelationship entities.
+type LabelRelationshipSelect struct {
+	*LabelRelationshipQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (lrs *LabelRelationshipSelect) Aggregate(fns ...AggregateFunc) *LabelRelationshipSelect {
+	lrs.fns = append(lrs.fns, fns...)
+	return lrs
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (lrs *LabelRelationshipSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, lrs.ctx, "Select")
+	if err := lrs.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*LabelRelationshipQuery, *LabelRelationshipSelect](ctx, lrs.LabelRelationshipQuery, lrs, lrs.inters, v)
+}
+
+func (lrs *LabelRelationshipSelect) sqlScan(ctx context.Context, root *LabelRelationshipQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(lrs.fns))
+	for _, fn := range lrs.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*lrs.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 := lrs.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 618 - 0
ent/labelrelationship_update.go

@@ -0,0 +1,618 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// LabelRelationshipUpdate is the builder for updating LabelRelationship entities.
+type LabelRelationshipUpdate struct {
+	config
+	hooks    []Hook
+	mutation *LabelRelationshipMutation
+}
+
+// Where appends a list predicates to the LabelRelationshipUpdate builder.
+func (lru *LabelRelationshipUpdate) Where(ps ...predicate.LabelRelationship) *LabelRelationshipUpdate {
+	lru.mutation.Where(ps...)
+	return lru
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (lru *LabelRelationshipUpdate) SetUpdatedAt(t time.Time) *LabelRelationshipUpdate {
+	lru.mutation.SetUpdatedAt(t)
+	return lru
+}
+
+// SetStatus sets the "status" field.
+func (lru *LabelRelationshipUpdate) SetStatus(u uint8) *LabelRelationshipUpdate {
+	lru.mutation.ResetStatus()
+	lru.mutation.SetStatus(u)
+	return lru
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (lru *LabelRelationshipUpdate) SetNillableStatus(u *uint8) *LabelRelationshipUpdate {
+	if u != nil {
+		lru.SetStatus(*u)
+	}
+	return lru
+}
+
+// AddStatus adds u to the "status" field.
+func (lru *LabelRelationshipUpdate) AddStatus(u int8) *LabelRelationshipUpdate {
+	lru.mutation.AddStatus(u)
+	return lru
+}
+
+// ClearStatus clears the value of the "status" field.
+func (lru *LabelRelationshipUpdate) ClearStatus() *LabelRelationshipUpdate {
+	lru.mutation.ClearStatus()
+	return lru
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (lru *LabelRelationshipUpdate) SetDeletedAt(t time.Time) *LabelRelationshipUpdate {
+	lru.mutation.SetDeletedAt(t)
+	return lru
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (lru *LabelRelationshipUpdate) SetNillableDeletedAt(t *time.Time) *LabelRelationshipUpdate {
+	if t != nil {
+		lru.SetDeletedAt(*t)
+	}
+	return lru
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (lru *LabelRelationshipUpdate) ClearDeletedAt() *LabelRelationshipUpdate {
+	lru.mutation.ClearDeletedAt()
+	return lru
+}
+
+// SetLabelID sets the "label_id" field.
+func (lru *LabelRelationshipUpdate) SetLabelID(u uint64) *LabelRelationshipUpdate {
+	lru.mutation.SetLabelID(u)
+	return lru
+}
+
+// SetNillableLabelID sets the "label_id" field if the given value is not nil.
+func (lru *LabelRelationshipUpdate) SetNillableLabelID(u *uint64) *LabelRelationshipUpdate {
+	if u != nil {
+		lru.SetLabelID(*u)
+	}
+	return lru
+}
+
+// SetContactID sets the "contact_id" field.
+func (lru *LabelRelationshipUpdate) SetContactID(u uint64) *LabelRelationshipUpdate {
+	lru.mutation.SetContactID(u)
+	return lru
+}
+
+// SetNillableContactID sets the "contact_id" field if the given value is not nil.
+func (lru *LabelRelationshipUpdate) SetNillableContactID(u *uint64) *LabelRelationshipUpdate {
+	if u != nil {
+		lru.SetContactID(*u)
+	}
+	return lru
+}
+
+// SetContactsID sets the "contacts" edge to the Contact entity by ID.
+func (lru *LabelRelationshipUpdate) SetContactsID(id uint64) *LabelRelationshipUpdate {
+	lru.mutation.SetContactsID(id)
+	return lru
+}
+
+// SetContacts sets the "contacts" edge to the Contact entity.
+func (lru *LabelRelationshipUpdate) SetContacts(c *Contact) *LabelRelationshipUpdate {
+	return lru.SetContactsID(c.ID)
+}
+
+// SetLabelsID sets the "labels" edge to the Label entity by ID.
+func (lru *LabelRelationshipUpdate) SetLabelsID(id uint64) *LabelRelationshipUpdate {
+	lru.mutation.SetLabelsID(id)
+	return lru
+}
+
+// SetLabels sets the "labels" edge to the Label entity.
+func (lru *LabelRelationshipUpdate) SetLabels(l *Label) *LabelRelationshipUpdate {
+	return lru.SetLabelsID(l.ID)
+}
+
+// Mutation returns the LabelRelationshipMutation object of the builder.
+func (lru *LabelRelationshipUpdate) Mutation() *LabelRelationshipMutation {
+	return lru.mutation
+}
+
+// ClearContacts clears the "contacts" edge to the Contact entity.
+func (lru *LabelRelationshipUpdate) ClearContacts() *LabelRelationshipUpdate {
+	lru.mutation.ClearContacts()
+	return lru
+}
+
+// ClearLabels clears the "labels" edge to the Label entity.
+func (lru *LabelRelationshipUpdate) ClearLabels() *LabelRelationshipUpdate {
+	lru.mutation.ClearLabels()
+	return lru
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (lru *LabelRelationshipUpdate) Save(ctx context.Context) (int, error) {
+	if err := lru.defaults(); err != nil {
+		return 0, err
+	}
+	return withHooks(ctx, lru.sqlSave, lru.mutation, lru.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (lru *LabelRelationshipUpdate) SaveX(ctx context.Context) int {
+	affected, err := lru.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (lru *LabelRelationshipUpdate) Exec(ctx context.Context) error {
+	_, err := lru.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lru *LabelRelationshipUpdate) ExecX(ctx context.Context) {
+	if err := lru.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (lru *LabelRelationshipUpdate) defaults() error {
+	if _, ok := lru.mutation.UpdatedAt(); !ok {
+		if labelrelationship.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized labelrelationship.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := labelrelationship.UpdateDefaultUpdatedAt()
+		lru.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (lru *LabelRelationshipUpdate) check() error {
+	if _, ok := lru.mutation.ContactsID(); lru.mutation.ContactsCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "LabelRelationship.contacts"`)
+	}
+	if _, ok := lru.mutation.LabelsID(); lru.mutation.LabelsCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "LabelRelationship.labels"`)
+	}
+	return nil
+}
+
+func (lru *LabelRelationshipUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	if err := lru.check(); err != nil {
+		return n, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(labelrelationship.Table, labelrelationship.Columns, sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64))
+	if ps := lru.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := lru.mutation.UpdatedAt(); ok {
+		_spec.SetField(labelrelationship.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := lru.mutation.Status(); ok {
+		_spec.SetField(labelrelationship.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := lru.mutation.AddedStatus(); ok {
+		_spec.AddField(labelrelationship.FieldStatus, field.TypeUint8, value)
+	}
+	if lru.mutation.StatusCleared() {
+		_spec.ClearField(labelrelationship.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := lru.mutation.DeletedAt(); ok {
+		_spec.SetField(labelrelationship.FieldDeletedAt, field.TypeTime, value)
+	}
+	if lru.mutation.DeletedAtCleared() {
+		_spec.ClearField(labelrelationship.FieldDeletedAt, field.TypeTime)
+	}
+	if lru.mutation.ContactsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.ContactsTable,
+			Columns: []string{labelrelationship.ContactsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := lru.mutation.ContactsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.ContactsTable,
+			Columns: []string{labelrelationship.ContactsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if lru.mutation.LabelsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.LabelsTable,
+			Columns: []string{labelrelationship.LabelsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := lru.mutation.LabelsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.LabelsTable,
+			Columns: []string{labelrelationship.LabelsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(label.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, lru.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{labelrelationship.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	lru.mutation.done = true
+	return n, nil
+}
+
+// LabelRelationshipUpdateOne is the builder for updating a single LabelRelationship entity.
+type LabelRelationshipUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *LabelRelationshipMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (lruo *LabelRelationshipUpdateOne) SetUpdatedAt(t time.Time) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetUpdatedAt(t)
+	return lruo
+}
+
+// SetStatus sets the "status" field.
+func (lruo *LabelRelationshipUpdateOne) SetStatus(u uint8) *LabelRelationshipUpdateOne {
+	lruo.mutation.ResetStatus()
+	lruo.mutation.SetStatus(u)
+	return lruo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (lruo *LabelRelationshipUpdateOne) SetNillableStatus(u *uint8) *LabelRelationshipUpdateOne {
+	if u != nil {
+		lruo.SetStatus(*u)
+	}
+	return lruo
+}
+
+// AddStatus adds u to the "status" field.
+func (lruo *LabelRelationshipUpdateOne) AddStatus(u int8) *LabelRelationshipUpdateOne {
+	lruo.mutation.AddStatus(u)
+	return lruo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (lruo *LabelRelationshipUpdateOne) ClearStatus() *LabelRelationshipUpdateOne {
+	lruo.mutation.ClearStatus()
+	return lruo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (lruo *LabelRelationshipUpdateOne) SetDeletedAt(t time.Time) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetDeletedAt(t)
+	return lruo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (lruo *LabelRelationshipUpdateOne) SetNillableDeletedAt(t *time.Time) *LabelRelationshipUpdateOne {
+	if t != nil {
+		lruo.SetDeletedAt(*t)
+	}
+	return lruo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (lruo *LabelRelationshipUpdateOne) ClearDeletedAt() *LabelRelationshipUpdateOne {
+	lruo.mutation.ClearDeletedAt()
+	return lruo
+}
+
+// SetLabelID sets the "label_id" field.
+func (lruo *LabelRelationshipUpdateOne) SetLabelID(u uint64) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetLabelID(u)
+	return lruo
+}
+
+// SetNillableLabelID sets the "label_id" field if the given value is not nil.
+func (lruo *LabelRelationshipUpdateOne) SetNillableLabelID(u *uint64) *LabelRelationshipUpdateOne {
+	if u != nil {
+		lruo.SetLabelID(*u)
+	}
+	return lruo
+}
+
+// SetContactID sets the "contact_id" field.
+func (lruo *LabelRelationshipUpdateOne) SetContactID(u uint64) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetContactID(u)
+	return lruo
+}
+
+// SetNillableContactID sets the "contact_id" field if the given value is not nil.
+func (lruo *LabelRelationshipUpdateOne) SetNillableContactID(u *uint64) *LabelRelationshipUpdateOne {
+	if u != nil {
+		lruo.SetContactID(*u)
+	}
+	return lruo
+}
+
+// SetContactsID sets the "contacts" edge to the Contact entity by ID.
+func (lruo *LabelRelationshipUpdateOne) SetContactsID(id uint64) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetContactsID(id)
+	return lruo
+}
+
+// SetContacts sets the "contacts" edge to the Contact entity.
+func (lruo *LabelRelationshipUpdateOne) SetContacts(c *Contact) *LabelRelationshipUpdateOne {
+	return lruo.SetContactsID(c.ID)
+}
+
+// SetLabelsID sets the "labels" edge to the Label entity by ID.
+func (lruo *LabelRelationshipUpdateOne) SetLabelsID(id uint64) *LabelRelationshipUpdateOne {
+	lruo.mutation.SetLabelsID(id)
+	return lruo
+}
+
+// SetLabels sets the "labels" edge to the Label entity.
+func (lruo *LabelRelationshipUpdateOne) SetLabels(l *Label) *LabelRelationshipUpdateOne {
+	return lruo.SetLabelsID(l.ID)
+}
+
+// Mutation returns the LabelRelationshipMutation object of the builder.
+func (lruo *LabelRelationshipUpdateOne) Mutation() *LabelRelationshipMutation {
+	return lruo.mutation
+}
+
+// ClearContacts clears the "contacts" edge to the Contact entity.
+func (lruo *LabelRelationshipUpdateOne) ClearContacts() *LabelRelationshipUpdateOne {
+	lruo.mutation.ClearContacts()
+	return lruo
+}
+
+// ClearLabels clears the "labels" edge to the Label entity.
+func (lruo *LabelRelationshipUpdateOne) ClearLabels() *LabelRelationshipUpdateOne {
+	lruo.mutation.ClearLabels()
+	return lruo
+}
+
+// Where appends a list predicates to the LabelRelationshipUpdate builder.
+func (lruo *LabelRelationshipUpdateOne) Where(ps ...predicate.LabelRelationship) *LabelRelationshipUpdateOne {
+	lruo.mutation.Where(ps...)
+	return lruo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (lruo *LabelRelationshipUpdateOne) Select(field string, fields ...string) *LabelRelationshipUpdateOne {
+	lruo.fields = append([]string{field}, fields...)
+	return lruo
+}
+
+// Save executes the query and returns the updated LabelRelationship entity.
+func (lruo *LabelRelationshipUpdateOne) Save(ctx context.Context) (*LabelRelationship, error) {
+	if err := lruo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, lruo.sqlSave, lruo.mutation, lruo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (lruo *LabelRelationshipUpdateOne) SaveX(ctx context.Context) *LabelRelationship {
+	node, err := lruo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (lruo *LabelRelationshipUpdateOne) Exec(ctx context.Context) error {
+	_, err := lruo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (lruo *LabelRelationshipUpdateOne) ExecX(ctx context.Context) {
+	if err := lruo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (lruo *LabelRelationshipUpdateOne) defaults() error {
+	if _, ok := lruo.mutation.UpdatedAt(); !ok {
+		if labelrelationship.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized labelrelationship.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := labelrelationship.UpdateDefaultUpdatedAt()
+		lruo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (lruo *LabelRelationshipUpdateOne) check() error {
+	if _, ok := lruo.mutation.ContactsID(); lruo.mutation.ContactsCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "LabelRelationship.contacts"`)
+	}
+	if _, ok := lruo.mutation.LabelsID(); lruo.mutation.LabelsCleared() && !ok {
+		return errors.New(`ent: clearing a required unique edge "LabelRelationship.labels"`)
+	}
+	return nil
+}
+
+func (lruo *LabelRelationshipUpdateOne) sqlSave(ctx context.Context) (_node *LabelRelationship, err error) {
+	if err := lruo.check(); err != nil {
+		return _node, err
+	}
+	_spec := sqlgraph.NewUpdateSpec(labelrelationship.Table, labelrelationship.Columns, sqlgraph.NewFieldSpec(labelrelationship.FieldID, field.TypeUint64))
+	id, ok := lruo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "LabelRelationship.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := lruo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, labelrelationship.FieldID)
+		for _, f := range fields {
+			if !labelrelationship.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != labelrelationship.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := lruo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := lruo.mutation.UpdatedAt(); ok {
+		_spec.SetField(labelrelationship.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := lruo.mutation.Status(); ok {
+		_spec.SetField(labelrelationship.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := lruo.mutation.AddedStatus(); ok {
+		_spec.AddField(labelrelationship.FieldStatus, field.TypeUint8, value)
+	}
+	if lruo.mutation.StatusCleared() {
+		_spec.ClearField(labelrelationship.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := lruo.mutation.DeletedAt(); ok {
+		_spec.SetField(labelrelationship.FieldDeletedAt, field.TypeTime, value)
+	}
+	if lruo.mutation.DeletedAtCleared() {
+		_spec.ClearField(labelrelationship.FieldDeletedAt, field.TypeTime)
+	}
+	if lruo.mutation.ContactsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.ContactsTable,
+			Columns: []string{labelrelationship.ContactsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := lruo.mutation.ContactsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.ContactsTable,
+			Columns: []string{labelrelationship.ContactsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	if lruo.mutation.LabelsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.LabelsTable,
+			Columns: []string{labelrelationship.LabelsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := lruo.mutation.LabelsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   labelrelationship.LabelsTable,
+			Columns: []string{labelrelationship.LabelsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(label.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &LabelRelationship{config: lruo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, lruo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{labelrelationship.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	lruo.mutation.done = true
+	return _node, nil
+}

+ 125 - 0
ent/message.go

@@ -0,0 +1,125 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"wechat-api/ent/message"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Message is the model entity for the Message schema.
+type Message struct {
+	config `json:"-"`
+	// ID of the ent.
+	ID int `json:"id,omitempty"`
+	// 属主微信id
+	WxWxid string `json:"wx_wxid,omitempty"`
+	// 微信id 公众号微信ID
+	Wxid string `json:"wxid,omitempty"`
+	// 微信消息内容
+	Content      string `json:"content,omitempty"`
+	selectValues sql.SelectValues
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Message) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case message.FieldID:
+			values[i] = new(sql.NullInt64)
+		case message.FieldWxWxid, message.FieldWxid, message.FieldContent:
+			values[i] = new(sql.NullString)
+		default:
+			values[i] = new(sql.UnknownType)
+		}
+	}
+	return values, nil
+}
+
+// assignValues assigns the values that were returned from sql.Rows (after scanning)
+// to the Message fields.
+func (m *Message) 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 message.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			m.ID = int(value.Int64)
+		case message.FieldWxWxid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field wx_wxid", values[i])
+			} else if value.Valid {
+				m.WxWxid = value.String
+			}
+		case message.FieldWxid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field wxid", values[i])
+			} else if value.Valid {
+				m.Wxid = value.String
+			}
+		case message.FieldContent:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field content", values[i])
+			} else if value.Valid {
+				m.Content = value.String
+			}
+		default:
+			m.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Message.
+// This includes values selected through modifiers, order, etc.
+func (m *Message) Value(name string) (ent.Value, error) {
+	return m.selectValues.Get(name)
+}
+
+// Update returns a builder for updating this Message.
+// Note that you need to call Message.Unwrap() before calling this method if this Message
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (m *Message) Update() *MessageUpdateOne {
+	return NewMessageClient(m.config).UpdateOne(m)
+}
+
+// Unwrap unwraps the Message 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 (m *Message) Unwrap() *Message {
+	_tx, ok := m.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Message is not a transactional entity")
+	}
+	m.config.driver = _tx.drv
+	return m
+}
+
+// String implements the fmt.Stringer.
+func (m *Message) String() string {
+	var builder strings.Builder
+	builder.WriteString("Message(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", m.ID))
+	builder.WriteString("wx_wxid=")
+	builder.WriteString(m.WxWxid)
+	builder.WriteString(", ")
+	builder.WriteString("wxid=")
+	builder.WriteString(m.Wxid)
+	builder.WriteString(", ")
+	builder.WriteString("content=")
+	builder.WriteString(m.Content)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Messages is a parsable slice of Message.
+type Messages []*Message

+ 72 - 0
ent/message/message.go

@@ -0,0 +1,72 @@
+// Code generated by ent, DO NOT EDIT.
+
+package message
+
+import (
+	"entgo.io/ent/dialect/sql"
+)
+
+const (
+	// Label holds the string label denoting the message type in the database.
+	Label = "message"
+	// FieldID holds the string denoting the id field in the database.
+	FieldID = "id"
+	// FieldWxWxid holds the string denoting the wx_wxid field in the database.
+	FieldWxWxid = "wx_wxid"
+	// FieldWxid holds the string denoting the wxid field in the database.
+	FieldWxid = "wxid"
+	// FieldContent holds the string denoting the content field in the database.
+	FieldContent = "content"
+	// Table holds the table name of the message in the database.
+	Table = "message"
+)
+
+// Columns holds all SQL columns for message fields.
+var Columns = []string{
+	FieldID,
+	FieldWxWxid,
+	FieldWxid,
+	FieldContent,
+}
+
+// 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 (
+	// DefaultWxWxid holds the default value on creation for the "wx_wxid" field.
+	DefaultWxWxid string
+	// DefaultWxid holds the default value on creation for the "wxid" field.
+	DefaultWxid string
+	// DefaultContent holds the default value on creation for the "content" field.
+	DefaultContent string
+)
+
+// OrderOption defines the ordering options for the Message 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()
+}
+
+// ByWxWxid orders the results by the wx_wxid field.
+func ByWxWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxWxid, opts...).ToFunc()
+}
+
+// ByWxid orders the results by the wxid field.
+func ByWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxid, opts...).ToFunc()
+}
+
+// ByContent orders the results by the content field.
+func ByContent(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldContent, opts...).ToFunc()
+}

+ 289 - 0
ent/message/where.go

@@ -0,0 +1,289 @@
+// Code generated by ent, DO NOT EDIT.
+
+package message
+
+import (
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id int) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id int) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id int) predicate.Message {
+	return predicate.Message(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...int) predicate.Message {
+	return predicate.Message(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...int) predicate.Message {
+	return predicate.Message(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id int) predicate.Message {
+	return predicate.Message(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id int) predicate.Message {
+	return predicate.Message(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id int) predicate.Message {
+	return predicate.Message(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id int) predicate.Message {
+	return predicate.Message(sql.FieldLTE(FieldID, id))
+}
+
+// WxWxid applies equality check predicate on the "wx_wxid" field. It's identical to WxWxidEQ.
+func WxWxid(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldWxWxid, v))
+}
+
+// Wxid applies equality check predicate on the "wxid" field. It's identical to WxidEQ.
+func Wxid(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldWxid, v))
+}
+
+// Content applies equality check predicate on the "content" field. It's identical to ContentEQ.
+func Content(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldContent, v))
+}
+
+// WxWxidEQ applies the EQ predicate on the "wx_wxid" field.
+func WxWxidEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldWxWxid, v))
+}
+
+// WxWxidNEQ applies the NEQ predicate on the "wx_wxid" field.
+func WxWxidNEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldNEQ(FieldWxWxid, v))
+}
+
+// WxWxidIn applies the In predicate on the "wx_wxid" field.
+func WxWxidIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldIn(FieldWxWxid, vs...))
+}
+
+// WxWxidNotIn applies the NotIn predicate on the "wx_wxid" field.
+func WxWxidNotIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldNotIn(FieldWxWxid, vs...))
+}
+
+// WxWxidGT applies the GT predicate on the "wx_wxid" field.
+func WxWxidGT(v string) predicate.Message {
+	return predicate.Message(sql.FieldGT(FieldWxWxid, v))
+}
+
+// WxWxidGTE applies the GTE predicate on the "wx_wxid" field.
+func WxWxidGTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldGTE(FieldWxWxid, v))
+}
+
+// WxWxidLT applies the LT predicate on the "wx_wxid" field.
+func WxWxidLT(v string) predicate.Message {
+	return predicate.Message(sql.FieldLT(FieldWxWxid, v))
+}
+
+// WxWxidLTE applies the LTE predicate on the "wx_wxid" field.
+func WxWxidLTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldLTE(FieldWxWxid, v))
+}
+
+// WxWxidContains applies the Contains predicate on the "wx_wxid" field.
+func WxWxidContains(v string) predicate.Message {
+	return predicate.Message(sql.FieldContains(FieldWxWxid, v))
+}
+
+// WxWxidHasPrefix applies the HasPrefix predicate on the "wx_wxid" field.
+func WxWxidHasPrefix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasPrefix(FieldWxWxid, v))
+}
+
+// WxWxidHasSuffix applies the HasSuffix predicate on the "wx_wxid" field.
+func WxWxidHasSuffix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasSuffix(FieldWxWxid, v))
+}
+
+// WxWxidIsNil applies the IsNil predicate on the "wx_wxid" field.
+func WxWxidIsNil() predicate.Message {
+	return predicate.Message(sql.FieldIsNull(FieldWxWxid))
+}
+
+// WxWxidNotNil applies the NotNil predicate on the "wx_wxid" field.
+func WxWxidNotNil() predicate.Message {
+	return predicate.Message(sql.FieldNotNull(FieldWxWxid))
+}
+
+// WxWxidEqualFold applies the EqualFold predicate on the "wx_wxid" field.
+func WxWxidEqualFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldEqualFold(FieldWxWxid, v))
+}
+
+// WxWxidContainsFold applies the ContainsFold predicate on the "wx_wxid" field.
+func WxWxidContainsFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldContainsFold(FieldWxWxid, v))
+}
+
+// WxidEQ applies the EQ predicate on the "wxid" field.
+func WxidEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldWxid, v))
+}
+
+// WxidNEQ applies the NEQ predicate on the "wxid" field.
+func WxidNEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldNEQ(FieldWxid, v))
+}
+
+// WxidIn applies the In predicate on the "wxid" field.
+func WxidIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldIn(FieldWxid, vs...))
+}
+
+// WxidNotIn applies the NotIn predicate on the "wxid" field.
+func WxidNotIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldNotIn(FieldWxid, vs...))
+}
+
+// WxidGT applies the GT predicate on the "wxid" field.
+func WxidGT(v string) predicate.Message {
+	return predicate.Message(sql.FieldGT(FieldWxid, v))
+}
+
+// WxidGTE applies the GTE predicate on the "wxid" field.
+func WxidGTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldGTE(FieldWxid, v))
+}
+
+// WxidLT applies the LT predicate on the "wxid" field.
+func WxidLT(v string) predicate.Message {
+	return predicate.Message(sql.FieldLT(FieldWxid, v))
+}
+
+// WxidLTE applies the LTE predicate on the "wxid" field.
+func WxidLTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldLTE(FieldWxid, v))
+}
+
+// WxidContains applies the Contains predicate on the "wxid" field.
+func WxidContains(v string) predicate.Message {
+	return predicate.Message(sql.FieldContains(FieldWxid, v))
+}
+
+// WxidHasPrefix applies the HasPrefix predicate on the "wxid" field.
+func WxidHasPrefix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasPrefix(FieldWxid, v))
+}
+
+// WxidHasSuffix applies the HasSuffix predicate on the "wxid" field.
+func WxidHasSuffix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasSuffix(FieldWxid, v))
+}
+
+// WxidEqualFold applies the EqualFold predicate on the "wxid" field.
+func WxidEqualFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldEqualFold(FieldWxid, v))
+}
+
+// WxidContainsFold applies the ContainsFold predicate on the "wxid" field.
+func WxidContainsFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldContainsFold(FieldWxid, v))
+}
+
+// ContentEQ applies the EQ predicate on the "content" field.
+func ContentEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldEQ(FieldContent, v))
+}
+
+// ContentNEQ applies the NEQ predicate on the "content" field.
+func ContentNEQ(v string) predicate.Message {
+	return predicate.Message(sql.FieldNEQ(FieldContent, v))
+}
+
+// ContentIn applies the In predicate on the "content" field.
+func ContentIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldIn(FieldContent, vs...))
+}
+
+// ContentNotIn applies the NotIn predicate on the "content" field.
+func ContentNotIn(vs ...string) predicate.Message {
+	return predicate.Message(sql.FieldNotIn(FieldContent, vs...))
+}
+
+// ContentGT applies the GT predicate on the "content" field.
+func ContentGT(v string) predicate.Message {
+	return predicate.Message(sql.FieldGT(FieldContent, v))
+}
+
+// ContentGTE applies the GTE predicate on the "content" field.
+func ContentGTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldGTE(FieldContent, v))
+}
+
+// ContentLT applies the LT predicate on the "content" field.
+func ContentLT(v string) predicate.Message {
+	return predicate.Message(sql.FieldLT(FieldContent, v))
+}
+
+// ContentLTE applies the LTE predicate on the "content" field.
+func ContentLTE(v string) predicate.Message {
+	return predicate.Message(sql.FieldLTE(FieldContent, v))
+}
+
+// ContentContains applies the Contains predicate on the "content" field.
+func ContentContains(v string) predicate.Message {
+	return predicate.Message(sql.FieldContains(FieldContent, v))
+}
+
+// ContentHasPrefix applies the HasPrefix predicate on the "content" field.
+func ContentHasPrefix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasPrefix(FieldContent, v))
+}
+
+// ContentHasSuffix applies the HasSuffix predicate on the "content" field.
+func ContentHasSuffix(v string) predicate.Message {
+	return predicate.Message(sql.FieldHasSuffix(FieldContent, v))
+}
+
+// ContentEqualFold applies the EqualFold predicate on the "content" field.
+func ContentEqualFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldEqualFold(FieldContent, v))
+}
+
+// ContentContainsFold applies the ContainsFold predicate on the "content" field.
+func ContentContainsFold(v string) predicate.Message {
+	return predicate.Message(sql.FieldContainsFold(FieldContent, v))
+}
+
+// And groups predicates with the AND operator between them.
+func And(predicates ...predicate.Message) predicate.Message {
+	return predicate.Message(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Message) predicate.Message {
+	return predicate.Message(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Message) predicate.Message {
+	return predicate.Message(sql.NotPredicates(p))
+}

+ 619 - 0
ent/message_create.go

@@ -0,0 +1,619 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"wechat-api/ent/message"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// MessageCreate is the builder for creating a Message entity.
+type MessageCreate struct {
+	config
+	mutation *MessageMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (mc *MessageCreate) SetWxWxid(s string) *MessageCreate {
+	mc.mutation.SetWxWxid(s)
+	return mc
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (mc *MessageCreate) SetNillableWxWxid(s *string) *MessageCreate {
+	if s != nil {
+		mc.SetWxWxid(*s)
+	}
+	return mc
+}
+
+// SetWxid sets the "wxid" field.
+func (mc *MessageCreate) SetWxid(s string) *MessageCreate {
+	mc.mutation.SetWxid(s)
+	return mc
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (mc *MessageCreate) SetNillableWxid(s *string) *MessageCreate {
+	if s != nil {
+		mc.SetWxid(*s)
+	}
+	return mc
+}
+
+// SetContent sets the "content" field.
+func (mc *MessageCreate) SetContent(s string) *MessageCreate {
+	mc.mutation.SetContent(s)
+	return mc
+}
+
+// SetNillableContent sets the "content" field if the given value is not nil.
+func (mc *MessageCreate) SetNillableContent(s *string) *MessageCreate {
+	if s != nil {
+		mc.SetContent(*s)
+	}
+	return mc
+}
+
+// Mutation returns the MessageMutation object of the builder.
+func (mc *MessageCreate) Mutation() *MessageMutation {
+	return mc.mutation
+}
+
+// Save creates the Message in the database.
+func (mc *MessageCreate) Save(ctx context.Context) (*Message, error) {
+	mc.defaults()
+	return withHooks(ctx, mc.sqlSave, mc.mutation, mc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (mc *MessageCreate) SaveX(ctx context.Context) *Message {
+	v, err := mc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (mc *MessageCreate) Exec(ctx context.Context) error {
+	_, err := mc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (mc *MessageCreate) ExecX(ctx context.Context) {
+	if err := mc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (mc *MessageCreate) defaults() {
+	if _, ok := mc.mutation.WxWxid(); !ok {
+		v := message.DefaultWxWxid
+		mc.mutation.SetWxWxid(v)
+	}
+	if _, ok := mc.mutation.Wxid(); !ok {
+		v := message.DefaultWxid
+		mc.mutation.SetWxid(v)
+	}
+	if _, ok := mc.mutation.Content(); !ok {
+		v := message.DefaultContent
+		mc.mutation.SetContent(v)
+	}
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (mc *MessageCreate) check() error {
+	if _, ok := mc.mutation.Wxid(); !ok {
+		return &ValidationError{Name: "wxid", err: errors.New(`ent: missing required field "Message.wxid"`)}
+	}
+	if _, ok := mc.mutation.Content(); !ok {
+		return &ValidationError{Name: "content", err: errors.New(`ent: missing required field "Message.content"`)}
+	}
+	return nil
+}
+
+func (mc *MessageCreate) sqlSave(ctx context.Context) (*Message, error) {
+	if err := mc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := mc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, mc.driver, _spec); err != nil {
+		if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	id := _spec.ID.Value.(int64)
+	_node.ID = int(id)
+	mc.mutation.id = &_node.ID
+	mc.mutation.done = true
+	return _node, nil
+}
+
+func (mc *MessageCreate) createSpec() (*Message, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Message{config: mc.config}
+		_spec = sqlgraph.NewCreateSpec(message.Table, sqlgraph.NewFieldSpec(message.FieldID, field.TypeInt))
+	)
+	_spec.OnConflict = mc.conflict
+	if value, ok := mc.mutation.WxWxid(); ok {
+		_spec.SetField(message.FieldWxWxid, field.TypeString, value)
+		_node.WxWxid = value
+	}
+	if value, ok := mc.mutation.Wxid(); ok {
+		_spec.SetField(message.FieldWxid, field.TypeString, value)
+		_node.Wxid = value
+	}
+	if value, ok := mc.mutation.Content(); ok {
+		_spec.SetField(message.FieldContent, field.TypeString, value)
+		_node.Content = value
+	}
+	return _node, _spec
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Message.Create().
+//		SetWxWxid(v).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.MessageUpsert) {
+//			SetWxWxid(v+v).
+//		}).
+//		Exec(ctx)
+func (mc *MessageCreate) OnConflict(opts ...sql.ConflictOption) *MessageUpsertOne {
+	mc.conflict = opts
+	return &MessageUpsertOne{
+		create: mc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (mc *MessageCreate) OnConflictColumns(columns ...string) *MessageUpsertOne {
+	mc.conflict = append(mc.conflict, sql.ConflictColumns(columns...))
+	return &MessageUpsertOne{
+		create: mc,
+	}
+}
+
+type (
+	// MessageUpsertOne is the builder for "upsert"-ing
+	//  one Message node.
+	MessageUpsertOne struct {
+		create *MessageCreate
+	}
+
+	// MessageUpsert is the "OnConflict" setter.
+	MessageUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *MessageUpsert) SetWxWxid(v string) *MessageUpsert {
+	u.Set(message.FieldWxWxid, v)
+	return u
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *MessageUpsert) UpdateWxWxid() *MessageUpsert {
+	u.SetExcluded(message.FieldWxWxid)
+	return u
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *MessageUpsert) ClearWxWxid() *MessageUpsert {
+	u.SetNull(message.FieldWxWxid)
+	return u
+}
+
+// SetWxid sets the "wxid" field.
+func (u *MessageUpsert) SetWxid(v string) *MessageUpsert {
+	u.Set(message.FieldWxid, v)
+	return u
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *MessageUpsert) UpdateWxid() *MessageUpsert {
+	u.SetExcluded(message.FieldWxid)
+	return u
+}
+
+// SetContent sets the "content" field.
+func (u *MessageUpsert) SetContent(v string) *MessageUpsert {
+	u.Set(message.FieldContent, v)
+	return u
+}
+
+// UpdateContent sets the "content" field to the value that was provided on create.
+func (u *MessageUpsert) UpdateContent() *MessageUpsert {
+	u.SetExcluded(message.FieldContent)
+	return u
+}
+
+// UpdateNewValues updates the mutable fields using the new values that were set on create.
+// Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//		).
+//		Exec(ctx)
+func (u *MessageUpsertOne) UpdateNewValues() *MessageUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *MessageUpsertOne) Ignore() *MessageUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *MessageUpsertOne) DoNothing() *MessageUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the MessageCreate.OnConflict
+// documentation for more info.
+func (u *MessageUpsertOne) Update(set func(*MessageUpsert)) *MessageUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&MessageUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *MessageUpsertOne) SetWxWxid(v string) *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetWxWxid(v)
+	})
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *MessageUpsertOne) UpdateWxWxid() *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateWxWxid()
+	})
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *MessageUpsertOne) ClearWxWxid() *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.ClearWxWxid()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *MessageUpsertOne) SetWxid(v string) *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *MessageUpsertOne) UpdateWxid() *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetContent sets the "content" field.
+func (u *MessageUpsertOne) SetContent(v string) *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetContent(v)
+	})
+}
+
+// UpdateContent sets the "content" field to the value that was provided on create.
+func (u *MessageUpsertOne) UpdateContent() *MessageUpsertOne {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateContent()
+	})
+}
+
+// Exec executes the query.
+func (u *MessageUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for MessageCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *MessageUpsertOne) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// Exec executes the UPSERT query and returns the inserted/updated ID.
+func (u *MessageUpsertOne) ID(ctx context.Context) (id int, err error) {
+	node, err := u.create.Save(ctx)
+	if err != nil {
+		return id, err
+	}
+	return node.ID, nil
+}
+
+// IDX is like ID, but panics if an error occurs.
+func (u *MessageUpsertOne) IDX(ctx context.Context) int {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// MessageCreateBulk is the builder for creating many Message entities in bulk.
+type MessageCreateBulk struct {
+	config
+	err      error
+	builders []*MessageCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Message entities in the database.
+func (mcb *MessageCreateBulk) Save(ctx context.Context) ([]*Message, error) {
+	if mcb.err != nil {
+		return nil, mcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(mcb.builders))
+	nodes := make([]*Message, len(mcb.builders))
+	mutators := make([]Mutator, len(mcb.builders))
+	for i := range mcb.builders {
+		func(i int, root context.Context) {
+			builder := mcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*MessageMutation)
+				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, mcb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = mcb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, mcb.driver, spec); err != nil {
+						if sqlgraph.IsConstraintError(err) {
+							err = &ConstraintError{msg: err.Error(), wrap: err}
+						}
+					}
+				}
+				if err != nil {
+					return nil, err
+				}
+				mutation.id = &nodes[i].ID
+				if specs[i].ID.Value != nil {
+					id := specs[i].ID.Value.(int64)
+					nodes[i].ID = int(id)
+				}
+				mutation.done = true
+				return nodes[i], nil
+			})
+			for i := len(builder.hooks) - 1; i >= 0; i-- {
+				mut = builder.hooks[i](mut)
+			}
+			mutators[i] = mut
+		}(i, ctx)
+	}
+	if len(mutators) > 0 {
+		if _, err := mutators[0].Mutate(ctx, mcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (mcb *MessageCreateBulk) SaveX(ctx context.Context) []*Message {
+	v, err := mcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (mcb *MessageCreateBulk) Exec(ctx context.Context) error {
+	_, err := mcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (mcb *MessageCreateBulk) ExecX(ctx context.Context) {
+	if err := mcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Message.CreateBulk(builders...).
+//		OnConflict(
+//			// Update the row with the new values
+//			// the was proposed for insertion.
+//			sql.ResolveWithNewValues(),
+//		).
+//		// Override some of the fields with custom
+//		// update values.
+//		Update(func(u *ent.MessageUpsert) {
+//			SetWxWxid(v+v).
+//		}).
+//		Exec(ctx)
+func (mcb *MessageCreateBulk) OnConflict(opts ...sql.ConflictOption) *MessageUpsertBulk {
+	mcb.conflict = opts
+	return &MessageUpsertBulk{
+		create: mcb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (mcb *MessageCreateBulk) OnConflictColumns(columns ...string) *MessageUpsertBulk {
+	mcb.conflict = append(mcb.conflict, sql.ConflictColumns(columns...))
+	return &MessageUpsertBulk{
+		create: mcb,
+	}
+}
+
+// MessageUpsertBulk is the builder for "upsert"-ing
+// a bulk of Message nodes.
+type MessageUpsertBulk struct {
+	create *MessageCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//		).
+//		Exec(ctx)
+func (u *MessageUpsertBulk) UpdateNewValues() *MessageUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Message.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *MessageUpsertBulk) Ignore() *MessageUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
+	return u
+}
+
+// DoNothing configures the conflict_action to `DO NOTHING`.
+// Supported only by SQLite and PostgreSQL.
+func (u *MessageUpsertBulk) DoNothing() *MessageUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the MessageCreateBulk.OnConflict
+// documentation for more info.
+func (u *MessageUpsertBulk) Update(set func(*MessageUpsert)) *MessageUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&MessageUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *MessageUpsertBulk) SetWxWxid(v string) *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetWxWxid(v)
+	})
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *MessageUpsertBulk) UpdateWxWxid() *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateWxWxid()
+	})
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *MessageUpsertBulk) ClearWxWxid() *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.ClearWxWxid()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *MessageUpsertBulk) SetWxid(v string) *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *MessageUpsertBulk) UpdateWxid() *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetContent sets the "content" field.
+func (u *MessageUpsertBulk) SetContent(v string) *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.SetContent(v)
+	})
+}
+
+// UpdateContent sets the "content" field to the value that was provided on create.
+func (u *MessageUpsertBulk) UpdateContent() *MessageUpsertBulk {
+	return u.Update(func(s *MessageUpsert) {
+		s.UpdateContent()
+	})
+}
+
+// Exec executes the query.
+func (u *MessageUpsertBulk) Exec(ctx context.Context) error {
+	if u.create.err != nil {
+		return u.create.err
+	}
+	for i, b := range u.create.builders {
+		if len(b.conflict) != 0 {
+			return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the MessageCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for MessageCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *MessageUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/message_delete.go

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

+ 526 - 0
ent/message_query.go

@@ -0,0 +1,526 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"fmt"
+	"math"
+	"wechat-api/ent/message"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// MessageQuery is the builder for querying Message entities.
+type MessageQuery struct {
+	config
+	ctx        *QueryContext
+	order      []message.OrderOption
+	inters     []Interceptor
+	predicates []predicate.Message
+	// intermediate query (i.e. traversal path).
+	sql  *sql.Selector
+	path func(context.Context) (*sql.Selector, error)
+}
+
+// Where adds a new predicate for the MessageQuery builder.
+func (mq *MessageQuery) Where(ps ...predicate.Message) *MessageQuery {
+	mq.predicates = append(mq.predicates, ps...)
+	return mq
+}
+
+// Limit the number of records to be returned by this query.
+func (mq *MessageQuery) Limit(limit int) *MessageQuery {
+	mq.ctx.Limit = &limit
+	return mq
+}
+
+// Offset to start from.
+func (mq *MessageQuery) Offset(offset int) *MessageQuery {
+	mq.ctx.Offset = &offset
+	return mq
+}
+
+// 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 (mq *MessageQuery) Unique(unique bool) *MessageQuery {
+	mq.ctx.Unique = &unique
+	return mq
+}
+
+// Order specifies how the records should be ordered.
+func (mq *MessageQuery) Order(o ...message.OrderOption) *MessageQuery {
+	mq.order = append(mq.order, o...)
+	return mq
+}
+
+// First returns the first Message entity from the query.
+// Returns a *NotFoundError when no Message was found.
+func (mq *MessageQuery) First(ctx context.Context) (*Message, error) {
+	nodes, err := mq.Limit(1).All(setContextOp(ctx, mq.ctx, "First"))
+	if err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nil, &NotFoundError{message.Label}
+	}
+	return nodes[0], nil
+}
+
+// FirstX is like First, but panics if an error occurs.
+func (mq *MessageQuery) FirstX(ctx context.Context) *Message {
+	node, err := mq.First(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return node
+}
+
+// FirstID returns the first Message ID from the query.
+// Returns a *NotFoundError when no Message ID was found.
+func (mq *MessageQuery) FirstID(ctx context.Context) (id int, err error) {
+	var ids []int
+	if ids, err = mq.Limit(1).IDs(setContextOp(ctx, mq.ctx, "FirstID")); err != nil {
+		return
+	}
+	if len(ids) == 0 {
+		err = &NotFoundError{message.Label}
+		return
+	}
+	return ids[0], nil
+}
+
+// FirstIDX is like FirstID, but panics if an error occurs.
+func (mq *MessageQuery) FirstIDX(ctx context.Context) int {
+	id, err := mq.FirstID(ctx)
+	if err != nil && !IsNotFound(err) {
+		panic(err)
+	}
+	return id
+}
+
+// Only returns a single Message entity found by the query, ensuring it only returns one.
+// Returns a *NotSingularError when more than one Message entity is found.
+// Returns a *NotFoundError when no Message entities are found.
+func (mq *MessageQuery) Only(ctx context.Context) (*Message, error) {
+	nodes, err := mq.Limit(2).All(setContextOp(ctx, mq.ctx, "Only"))
+	if err != nil {
+		return nil, err
+	}
+	switch len(nodes) {
+	case 1:
+		return nodes[0], nil
+	case 0:
+		return nil, &NotFoundError{message.Label}
+	default:
+		return nil, &NotSingularError{message.Label}
+	}
+}
+
+// OnlyX is like Only, but panics if an error occurs.
+func (mq *MessageQuery) OnlyX(ctx context.Context) *Message {
+	node, err := mq.Only(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// OnlyID is like Only, but returns the only Message ID in the query.
+// Returns a *NotSingularError when more than one Message ID is found.
+// Returns a *NotFoundError when no entities are found.
+func (mq *MessageQuery) OnlyID(ctx context.Context) (id int, err error) {
+	var ids []int
+	if ids, err = mq.Limit(2).IDs(setContextOp(ctx, mq.ctx, "OnlyID")); err != nil {
+		return
+	}
+	switch len(ids) {
+	case 1:
+		id = ids[0]
+	case 0:
+		err = &NotFoundError{message.Label}
+	default:
+		err = &NotSingularError{message.Label}
+	}
+	return
+}
+
+// OnlyIDX is like OnlyID, but panics if an error occurs.
+func (mq *MessageQuery) OnlyIDX(ctx context.Context) int {
+	id, err := mq.OnlyID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// All executes the query and returns a list of Messages.
+func (mq *MessageQuery) All(ctx context.Context) ([]*Message, error) {
+	ctx = setContextOp(ctx, mq.ctx, "All")
+	if err := mq.prepareQuery(ctx); err != nil {
+		return nil, err
+	}
+	qr := querierAll[[]*Message, *MessageQuery]()
+	return withInterceptors[[]*Message](ctx, mq, qr, mq.inters)
+}
+
+// AllX is like All, but panics if an error occurs.
+func (mq *MessageQuery) AllX(ctx context.Context) []*Message {
+	nodes, err := mq.All(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return nodes
+}
+
+// IDs executes the query and returns a list of Message IDs.
+func (mq *MessageQuery) IDs(ctx context.Context) (ids []int, err error) {
+	if mq.ctx.Unique == nil && mq.path != nil {
+		mq.Unique(true)
+	}
+	ctx = setContextOp(ctx, mq.ctx, "IDs")
+	if err = mq.Select(message.FieldID).Scan(ctx, &ids); err != nil {
+		return nil, err
+	}
+	return ids, nil
+}
+
+// IDsX is like IDs, but panics if an error occurs.
+func (mq *MessageQuery) IDsX(ctx context.Context) []int {
+	ids, err := mq.IDs(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return ids
+}
+
+// Count returns the count of the given query.
+func (mq *MessageQuery) Count(ctx context.Context) (int, error) {
+	ctx = setContextOp(ctx, mq.ctx, "Count")
+	if err := mq.prepareQuery(ctx); err != nil {
+		return 0, err
+	}
+	return withInterceptors[int](ctx, mq, querierCount[*MessageQuery](), mq.inters)
+}
+
+// CountX is like Count, but panics if an error occurs.
+func (mq *MessageQuery) CountX(ctx context.Context) int {
+	count, err := mq.Count(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return count
+}
+
+// Exist returns true if the query has elements in the graph.
+func (mq *MessageQuery) Exist(ctx context.Context) (bool, error) {
+	ctx = setContextOp(ctx, mq.ctx, "Exist")
+	switch _, err := mq.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 (mq *MessageQuery) ExistX(ctx context.Context) bool {
+	exist, err := mq.Exist(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return exist
+}
+
+// Clone returns a duplicate of the MessageQuery builder, including all associated steps. It can be
+// used to prepare common query builders and use them differently after the clone is made.
+func (mq *MessageQuery) Clone() *MessageQuery {
+	if mq == nil {
+		return nil
+	}
+	return &MessageQuery{
+		config:     mq.config,
+		ctx:        mq.ctx.Clone(),
+		order:      append([]message.OrderOption{}, mq.order...),
+		inters:     append([]Interceptor{}, mq.inters...),
+		predicates: append([]predicate.Message{}, mq.predicates...),
+		// clone intermediate query.
+		sql:  mq.sql.Clone(),
+		path: mq.path,
+	}
+}
+
+// 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 {
+//		WxWxid string `json:"wx_wxid,omitempty"`
+//		Count int `json:"count,omitempty"`
+//	}
+//
+//	client.Message.Query().
+//		GroupBy(message.FieldWxWxid).
+//		Aggregate(ent.Count()).
+//		Scan(ctx, &v)
+func (mq *MessageQuery) GroupBy(field string, fields ...string) *MessageGroupBy {
+	mq.ctx.Fields = append([]string{field}, fields...)
+	grbuild := &MessageGroupBy{build: mq}
+	grbuild.flds = &mq.ctx.Fields
+	grbuild.label = message.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 {
+//		WxWxid string `json:"wx_wxid,omitempty"`
+//	}
+//
+//	client.Message.Query().
+//		Select(message.FieldWxWxid).
+//		Scan(ctx, &v)
+func (mq *MessageQuery) Select(fields ...string) *MessageSelect {
+	mq.ctx.Fields = append(mq.ctx.Fields, fields...)
+	sbuild := &MessageSelect{MessageQuery: mq}
+	sbuild.label = message.Label
+	sbuild.flds, sbuild.scan = &mq.ctx.Fields, sbuild.Scan
+	return sbuild
+}
+
+// Aggregate returns a MessageSelect configured with the given aggregations.
+func (mq *MessageQuery) Aggregate(fns ...AggregateFunc) *MessageSelect {
+	return mq.Select().Aggregate(fns...)
+}
+
+func (mq *MessageQuery) prepareQuery(ctx context.Context) error {
+	for _, inter := range mq.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, mq); err != nil {
+				return err
+			}
+		}
+	}
+	for _, f := range mq.ctx.Fields {
+		if !message.ValidColumn(f) {
+			return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+		}
+	}
+	if mq.path != nil {
+		prev, err := mq.path(ctx)
+		if err != nil {
+			return err
+		}
+		mq.sql = prev
+	}
+	return nil
+}
+
+func (mq *MessageQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Message, error) {
+	var (
+		nodes = []*Message{}
+		_spec = mq.querySpec()
+	)
+	_spec.ScanValues = func(columns []string) ([]any, error) {
+		return (*Message).scanValues(nil, columns)
+	}
+	_spec.Assign = func(columns []string, values []any) error {
+		node := &Message{config: mq.config}
+		nodes = append(nodes, node)
+		return node.assignValues(columns, values)
+	}
+	for i := range hooks {
+		hooks[i](ctx, _spec)
+	}
+	if err := sqlgraph.QueryNodes(ctx, mq.driver, _spec); err != nil {
+		return nil, err
+	}
+	if len(nodes) == 0 {
+		return nodes, nil
+	}
+	return nodes, nil
+}
+
+func (mq *MessageQuery) sqlCount(ctx context.Context) (int, error) {
+	_spec := mq.querySpec()
+	_spec.Node.Columns = mq.ctx.Fields
+	if len(mq.ctx.Fields) > 0 {
+		_spec.Unique = mq.ctx.Unique != nil && *mq.ctx.Unique
+	}
+	return sqlgraph.CountNodes(ctx, mq.driver, _spec)
+}
+
+func (mq *MessageQuery) querySpec() *sqlgraph.QuerySpec {
+	_spec := sqlgraph.NewQuerySpec(message.Table, message.Columns, sqlgraph.NewFieldSpec(message.FieldID, field.TypeInt))
+	_spec.From = mq.sql
+	if unique := mq.ctx.Unique; unique != nil {
+		_spec.Unique = *unique
+	} else if mq.path != nil {
+		_spec.Unique = true
+	}
+	if fields := mq.ctx.Fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, message.FieldID)
+		for i := range fields {
+			if fields[i] != message.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
+			}
+		}
+	}
+	if ps := mq.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if limit := mq.ctx.Limit; limit != nil {
+		_spec.Limit = *limit
+	}
+	if offset := mq.ctx.Offset; offset != nil {
+		_spec.Offset = *offset
+	}
+	if ps := mq.order; len(ps) > 0 {
+		_spec.Order = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	return _spec
+}
+
+func (mq *MessageQuery) sqlQuery(ctx context.Context) *sql.Selector {
+	builder := sql.Dialect(mq.driver.Dialect())
+	t1 := builder.Table(message.Table)
+	columns := mq.ctx.Fields
+	if len(columns) == 0 {
+		columns = message.Columns
+	}
+	selector := builder.Select(t1.Columns(columns...)...).From(t1)
+	if mq.sql != nil {
+		selector = mq.sql
+		selector.Select(selector.Columns(columns...)...)
+	}
+	if mq.ctx.Unique != nil && *mq.ctx.Unique {
+		selector.Distinct()
+	}
+	for _, p := range mq.predicates {
+		p(selector)
+	}
+	for _, p := range mq.order {
+		p(selector)
+	}
+	if offset := mq.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 := mq.ctx.Limit; limit != nil {
+		selector.Limit(*limit)
+	}
+	return selector
+}
+
+// MessageGroupBy is the group-by builder for Message entities.
+type MessageGroupBy struct {
+	selector
+	build *MessageQuery
+}
+
+// Aggregate adds the given aggregation functions to the group-by query.
+func (mgb *MessageGroupBy) Aggregate(fns ...AggregateFunc) *MessageGroupBy {
+	mgb.fns = append(mgb.fns, fns...)
+	return mgb
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (mgb *MessageGroupBy) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, mgb.build.ctx, "GroupBy")
+	if err := mgb.build.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*MessageQuery, *MessageGroupBy](ctx, mgb.build, mgb, mgb.build.inters, v)
+}
+
+func (mgb *MessageGroupBy) sqlScan(ctx context.Context, root *MessageQuery, v any) error {
+	selector := root.sqlQuery(ctx).Select()
+	aggregation := make([]string, 0, len(mgb.fns))
+	for _, fn := range mgb.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	if len(selector.SelectedColumns()) == 0 {
+		columns := make([]string, 0, len(*mgb.flds)+len(mgb.fns))
+		for _, f := range *mgb.flds {
+			columns = append(columns, selector.C(f))
+		}
+		columns = append(columns, aggregation...)
+		selector.Select(columns...)
+	}
+	selector.GroupBy(selector.Columns(*mgb.flds...)...)
+	if err := selector.Err(); err != nil {
+		return err
+	}
+	rows := &sql.Rows{}
+	query, args := selector.Query()
+	if err := mgb.build.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}
+
+// MessageSelect is the builder for selecting fields of Message entities.
+type MessageSelect struct {
+	*MessageQuery
+	selector
+}
+
+// Aggregate adds the given aggregation functions to the selector query.
+func (ms *MessageSelect) Aggregate(fns ...AggregateFunc) *MessageSelect {
+	ms.fns = append(ms.fns, fns...)
+	return ms
+}
+
+// Scan applies the selector query and scans the result into the given value.
+func (ms *MessageSelect) Scan(ctx context.Context, v any) error {
+	ctx = setContextOp(ctx, ms.ctx, "Select")
+	if err := ms.prepareQuery(ctx); err != nil {
+		return err
+	}
+	return scanWithInterceptors[*MessageQuery, *MessageSelect](ctx, ms.MessageQuery, ms, ms.inters, v)
+}
+
+func (ms *MessageSelect) sqlScan(ctx context.Context, root *MessageQuery, v any) error {
+	selector := root.sqlQuery(ctx)
+	aggregation := make([]string, 0, len(ms.fns))
+	for _, fn := range ms.fns {
+		aggregation = append(aggregation, fn(selector))
+	}
+	switch n := len(*ms.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 := ms.driver.Query(ctx, query, args, rows); err != nil {
+		return err
+	}
+	defer rows.Close()
+	return sql.ScanSlice(rows, v)
+}

+ 295 - 0
ent/message_update.go

@@ -0,0 +1,295 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"wechat-api/ent/message"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// MessageUpdate is the builder for updating Message entities.
+type MessageUpdate struct {
+	config
+	hooks    []Hook
+	mutation *MessageMutation
+}
+
+// Where appends a list predicates to the MessageUpdate builder.
+func (mu *MessageUpdate) Where(ps ...predicate.Message) *MessageUpdate {
+	mu.mutation.Where(ps...)
+	return mu
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (mu *MessageUpdate) SetWxWxid(s string) *MessageUpdate {
+	mu.mutation.SetWxWxid(s)
+	return mu
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (mu *MessageUpdate) SetNillableWxWxid(s *string) *MessageUpdate {
+	if s != nil {
+		mu.SetWxWxid(*s)
+	}
+	return mu
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (mu *MessageUpdate) ClearWxWxid() *MessageUpdate {
+	mu.mutation.ClearWxWxid()
+	return mu
+}
+
+// SetWxid sets the "wxid" field.
+func (mu *MessageUpdate) SetWxid(s string) *MessageUpdate {
+	mu.mutation.SetWxid(s)
+	return mu
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (mu *MessageUpdate) SetNillableWxid(s *string) *MessageUpdate {
+	if s != nil {
+		mu.SetWxid(*s)
+	}
+	return mu
+}
+
+// SetContent sets the "content" field.
+func (mu *MessageUpdate) SetContent(s string) *MessageUpdate {
+	mu.mutation.SetContent(s)
+	return mu
+}
+
+// SetNillableContent sets the "content" field if the given value is not nil.
+func (mu *MessageUpdate) SetNillableContent(s *string) *MessageUpdate {
+	if s != nil {
+		mu.SetContent(*s)
+	}
+	return mu
+}
+
+// Mutation returns the MessageMutation object of the builder.
+func (mu *MessageUpdate) Mutation() *MessageMutation {
+	return mu.mutation
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (mu *MessageUpdate) Save(ctx context.Context) (int, error) {
+	return withHooks(ctx, mu.sqlSave, mu.mutation, mu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (mu *MessageUpdate) SaveX(ctx context.Context) int {
+	affected, err := mu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (mu *MessageUpdate) Exec(ctx context.Context) error {
+	_, err := mu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (mu *MessageUpdate) ExecX(ctx context.Context) {
+	if err := mu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+func (mu *MessageUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	_spec := sqlgraph.NewUpdateSpec(message.Table, message.Columns, sqlgraph.NewFieldSpec(message.FieldID, field.TypeInt))
+	if ps := mu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := mu.mutation.WxWxid(); ok {
+		_spec.SetField(message.FieldWxWxid, field.TypeString, value)
+	}
+	if mu.mutation.WxWxidCleared() {
+		_spec.ClearField(message.FieldWxWxid, field.TypeString)
+	}
+	if value, ok := mu.mutation.Wxid(); ok {
+		_spec.SetField(message.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := mu.mutation.Content(); ok {
+		_spec.SetField(message.FieldContent, field.TypeString, value)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, mu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{message.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	mu.mutation.done = true
+	return n, nil
+}
+
+// MessageUpdateOne is the builder for updating a single Message entity.
+type MessageUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *MessageMutation
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (muo *MessageUpdateOne) SetWxWxid(s string) *MessageUpdateOne {
+	muo.mutation.SetWxWxid(s)
+	return muo
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (muo *MessageUpdateOne) SetNillableWxWxid(s *string) *MessageUpdateOne {
+	if s != nil {
+		muo.SetWxWxid(*s)
+	}
+	return muo
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (muo *MessageUpdateOne) ClearWxWxid() *MessageUpdateOne {
+	muo.mutation.ClearWxWxid()
+	return muo
+}
+
+// SetWxid sets the "wxid" field.
+func (muo *MessageUpdateOne) SetWxid(s string) *MessageUpdateOne {
+	muo.mutation.SetWxid(s)
+	return muo
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (muo *MessageUpdateOne) SetNillableWxid(s *string) *MessageUpdateOne {
+	if s != nil {
+		muo.SetWxid(*s)
+	}
+	return muo
+}
+
+// SetContent sets the "content" field.
+func (muo *MessageUpdateOne) SetContent(s string) *MessageUpdateOne {
+	muo.mutation.SetContent(s)
+	return muo
+}
+
+// SetNillableContent sets the "content" field if the given value is not nil.
+func (muo *MessageUpdateOne) SetNillableContent(s *string) *MessageUpdateOne {
+	if s != nil {
+		muo.SetContent(*s)
+	}
+	return muo
+}
+
+// Mutation returns the MessageMutation object of the builder.
+func (muo *MessageUpdateOne) Mutation() *MessageMutation {
+	return muo.mutation
+}
+
+// Where appends a list predicates to the MessageUpdate builder.
+func (muo *MessageUpdateOne) Where(ps ...predicate.Message) *MessageUpdateOne {
+	muo.mutation.Where(ps...)
+	return muo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (muo *MessageUpdateOne) Select(field string, fields ...string) *MessageUpdateOne {
+	muo.fields = append([]string{field}, fields...)
+	return muo
+}
+
+// Save executes the query and returns the updated Message entity.
+func (muo *MessageUpdateOne) Save(ctx context.Context) (*Message, error) {
+	return withHooks(ctx, muo.sqlSave, muo.mutation, muo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (muo *MessageUpdateOne) SaveX(ctx context.Context) *Message {
+	node, err := muo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (muo *MessageUpdateOne) Exec(ctx context.Context) error {
+	_, err := muo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (muo *MessageUpdateOne) ExecX(ctx context.Context) {
+	if err := muo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+func (muo *MessageUpdateOne) sqlSave(ctx context.Context) (_node *Message, err error) {
+	_spec := sqlgraph.NewUpdateSpec(message.Table, message.Columns, sqlgraph.NewFieldSpec(message.FieldID, field.TypeInt))
+	id, ok := muo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Message.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := muo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, message.FieldID)
+		for _, f := range fields {
+			if !message.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != message.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := muo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := muo.mutation.WxWxid(); ok {
+		_spec.SetField(message.FieldWxWxid, field.TypeString, value)
+	}
+	if muo.mutation.WxWxidCleared() {
+		_spec.ClearField(message.FieldWxWxid, field.TypeString)
+	}
+	if value, ok := muo.mutation.Wxid(); ok {
+		_spec.SetField(message.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := muo.mutation.Content(); ok {
+		_spec.SetField(message.FieldContent, field.TypeString, value)
+	}
+	_node = &Message{config: muo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, muo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{message.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	muo.mutation.done = true
+	return _node, nil
+}

+ 95 - 0
ent/migrate/schema.go

@@ -60,6 +60,87 @@ var (
 			},
 		},
 	}
+	// LabelColumns holds the columns for the "label" table.
+	LabelColumns = []*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: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
+		{Name: "type", Type: field.TypeInt, Comment: "标签类型:1好友,2群组,3公众号,4企业微信联系人", Default: 1},
+		{Name: "name", Type: field.TypeString, Comment: "标签名称", Default: ""},
+		{Name: "from", Type: field.TypeInt, Comment: "标签来源:1后台创建 2个微同步", Default: 1},
+		{Name: "mode", Type: field.TypeInt, Comment: "标签模式:1动态 2静态", Default: 1},
+		{Name: "conditions", Type: field.TypeString, Nullable: true, Comment: "标签的触达条件", Default: ""},
+	}
+	// LabelTable holds the schema information for the "label" table.
+	LabelTable = &schema.Table{
+		Name:       "label",
+		Columns:    LabelColumns,
+		PrimaryKey: []*schema.Column{LabelColumns[0]},
+		Indexes: []*schema.Index{
+			{
+				Name:    "label_name_from_mode",
+				Unique:  true,
+				Columns: []*schema.Column{LabelColumns[6], LabelColumns[7], LabelColumns[8]},
+			},
+		},
+	}
+	// LabelRelationshipColumns holds the columns for the "label_relationship" table.
+	LabelRelationshipColumns = []*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: "deleted_at", Type: field.TypeTime, Nullable: true, Comment: "Delete Time | 删除日期"},
+		{Name: "contact_id", Type: field.TypeUint64, Comment: "联系人 ID", Default: 1},
+		{Name: "label_id", Type: field.TypeUint64, Comment: "标签 ID", Default: 1},
+	}
+	// LabelRelationshipTable holds the schema information for the "label_relationship" table.
+	LabelRelationshipTable = &schema.Table{
+		Name:       "label_relationship",
+		Columns:    LabelRelationshipColumns,
+		PrimaryKey: []*schema.Column{LabelRelationshipColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "label_relationship_contact_contact_relationships",
+				Columns:    []*schema.Column{LabelRelationshipColumns[5]},
+				RefColumns: []*schema.Column{ContactColumns[0]},
+				OnDelete:   schema.NoAction,
+			},
+			{
+				Symbol:     "label_relationship_label_label_relationships",
+				Columns:    []*schema.Column{LabelRelationshipColumns[6]},
+				RefColumns: []*schema.Column{LabelColumns[0]},
+				OnDelete:   schema.NoAction,
+			},
+		},
+		Indexes: []*schema.Index{
+			{
+				Name:    "labelrelationship_label_id",
+				Unique:  false,
+				Columns: []*schema.Column{LabelRelationshipColumns[6]},
+			},
+			{
+				Name:    "labelrelationship_contact_id",
+				Unique:  false,
+				Columns: []*schema.Column{LabelRelationshipColumns[5]},
+			},
+		},
+	}
+	// MessageColumns holds the columns for the "message" table.
+	MessageColumns = []*schema.Column{
+		{Name: "id", Type: field.TypeInt, Increment: true},
+		{Name: "wx_wxid", Type: field.TypeString, Nullable: true, Comment: "属主微信id", Default: ""},
+		{Name: "wxid", Type: field.TypeString, Comment: "微信id 公众号微信ID", Default: ""},
+		{Name: "content", Type: field.TypeString, Comment: "微信消息内容", Default: ""},
+	}
+	// MessageTable holds the schema information for the "message" table.
+	MessageTable = &schema.Table{
+		Name:       "message",
+		Columns:    MessageColumns,
+		PrimaryKey: []*schema.Column{MessageColumns[0]},
+	}
 	// ServerColumns holds the columns for the "server" table.
 	ServerColumns = []*schema.Column{
 		{Name: "id", Type: field.TypeUint64, Increment: true},
@@ -156,6 +237,9 @@ var (
 	// Tables holds all the tables in the schema.
 	Tables = []*schema.Table{
 		ContactTable,
+		LabelTable,
+		LabelRelationshipTable,
+		MessageTable,
 		ServerTable,
 		WxTable,
 	}
@@ -165,6 +249,17 @@ func init() {
 	ContactTable.Annotation = &entsql.Annotation{
 		Table: "contact",
 	}
+	LabelTable.Annotation = &entsql.Annotation{
+		Table: "label",
+	}
+	LabelRelationshipTable.ForeignKeys[0].RefTable = ContactTable
+	LabelRelationshipTable.ForeignKeys[1].RefTable = LabelTable
+	LabelRelationshipTable.Annotation = &entsql.Annotation{
+		Table: "label_relationship",
+	}
+	MessageTable.Annotation = &entsql.Annotation{
+		Table: "message",
+	}
 	ServerTable.Annotation = &entsql.Annotation{
 		Table: "server",
 	}

+ 2451 - 37
ent/mutation.go

@@ -9,6 +9,9 @@ import (
 	"sync"
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/predicate"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
@@ -26,45 +29,51 @@ const (
 	OpUpdateOne = ent.OpUpdateOne
 
 	// Node types.
-	TypeContact = "Contact"
-	TypeServer  = "Server"
-	TypeWx      = "Wx"
+	TypeContact           = "Contact"
+	TypeLabel             = "Label"
+	TypeLabelRelationship = "LabelRelationship"
+	TypeMessage           = "Message"
+	TypeServer            = "Server"
+	TypeWx                = "Wx"
 )
 
 // ContactMutation represents an operation that mutates the Contact nodes in the graph.
 type ContactMutation struct {
 	config
-	op            Op
-	typ           string
-	id            *uint64
-	created_at    *time.Time
-	updated_at    *time.Time
-	status        *uint8
-	addstatus     *int8
-	deleted_at    *time.Time
-	wx_wxid       *string
-	_type         *int
-	add_type      *int
-	wxid          *string
-	account       *string
-	nickname      *string
-	markname      *string
-	headimg       *string
-	sex           *int
-	addsex        *int
-	starrole      *string
-	dontseeit     *int
-	adddontseeit  *int
-	dontseeme     *int
-	adddontseeme  *int
-	lag           *string
-	gid           *string
-	gname         *string
-	v3            *string
-	clearedFields map[string]struct{}
-	done          bool
-	oldValue      func(context.Context) (*Contact, error)
-	predicates    []predicate.Contact
+	op                           Op
+	typ                          string
+	id                           *uint64
+	created_at                   *time.Time
+	updated_at                   *time.Time
+	status                       *uint8
+	addstatus                    *int8
+	deleted_at                   *time.Time
+	wx_wxid                      *string
+	_type                        *int
+	add_type                     *int
+	wxid                         *string
+	account                      *string
+	nickname                     *string
+	markname                     *string
+	headimg                      *string
+	sex                          *int
+	addsex                       *int
+	starrole                     *string
+	dontseeit                    *int
+	adddontseeit                 *int
+	dontseeme                    *int
+	adddontseeme                 *int
+	lag                          *string
+	gid                          *string
+	gname                        *string
+	v3                           *string
+	clearedFields                map[string]struct{}
+	contact_relationships        map[uint64]struct{}
+	removedcontact_relationships map[uint64]struct{}
+	clearedcontact_relationships bool
+	done                         bool
+	oldValue                     func(context.Context) (*Contact, error)
+	predicates                   []predicate.Contact
 }
 
 var _ ent.Mutation = (*ContactMutation)(nil)
@@ -1009,6 +1018,60 @@ func (m *ContactMutation) ResetV3() {
 	m.v3 = nil
 }
 
+// AddContactRelationshipIDs adds the "contact_relationships" edge to the LabelRelationship entity by ids.
+func (m *ContactMutation) AddContactRelationshipIDs(ids ...uint64) {
+	if m.contact_relationships == nil {
+		m.contact_relationships = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.contact_relationships[ids[i]] = struct{}{}
+	}
+}
+
+// ClearContactRelationships clears the "contact_relationships" edge to the LabelRelationship entity.
+func (m *ContactMutation) ClearContactRelationships() {
+	m.clearedcontact_relationships = true
+}
+
+// ContactRelationshipsCleared reports if the "contact_relationships" edge to the LabelRelationship entity was cleared.
+func (m *ContactMutation) ContactRelationshipsCleared() bool {
+	return m.clearedcontact_relationships
+}
+
+// RemoveContactRelationshipIDs removes the "contact_relationships" edge to the LabelRelationship entity by IDs.
+func (m *ContactMutation) RemoveContactRelationshipIDs(ids ...uint64) {
+	if m.removedcontact_relationships == nil {
+		m.removedcontact_relationships = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.contact_relationships, ids[i])
+		m.removedcontact_relationships[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedContactRelationships returns the removed IDs of the "contact_relationships" edge to the LabelRelationship entity.
+func (m *ContactMutation) RemovedContactRelationshipsIDs() (ids []uint64) {
+	for id := range m.removedcontact_relationships {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ContactRelationshipsIDs returns the "contact_relationships" edge IDs in the mutation.
+func (m *ContactMutation) ContactRelationshipsIDs() (ids []uint64) {
+	for id := range m.contact_relationships {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetContactRelationships resets all changes to the "contact_relationships" edge.
+func (m *ContactMutation) ResetContactRelationships() {
+	m.contact_relationships = nil
+	m.clearedcontact_relationships = false
+	m.removedcontact_relationships = nil
+}
+
 // Where appends a list predicates to the ContactMutation builder.
 func (m *ContactMutation) Where(ps ...predicate.Contact) {
 	m.predicates = append(m.predicates, ps...)
@@ -1538,52 +1601,2403 @@ func (m *ContactMutation) ResetField(name string) error {
 
 // AddedEdges returns all edge names that were set/added in this mutation.
 func (m *ContactMutation) AddedEdges() []string {
-	edges := make([]string, 0, 0)
+	edges := make([]string, 0, 1)
+	if m.contact_relationships != nil {
+		edges = append(edges, contact.EdgeContactRelationships)
+	}
 	return edges
 }
 
 // AddedIDs returns all IDs (to other nodes) that were added for the given edge
 // name in this mutation.
 func (m *ContactMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case contact.EdgeContactRelationships:
+		ids := make([]ent.Value, 0, len(m.contact_relationships))
+		for id := range m.contact_relationships {
+			ids = append(ids, id)
+		}
+		return ids
+	}
 	return nil
 }
 
 // RemovedEdges returns all edge names that were removed in this mutation.
 func (m *ContactMutation) RemovedEdges() []string {
-	edges := make([]string, 0, 0)
+	edges := make([]string, 0, 1)
+	if m.removedcontact_relationships != nil {
+		edges = append(edges, contact.EdgeContactRelationships)
+	}
 	return edges
 }
 
 // RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
 // the given name in this mutation.
 func (m *ContactMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case contact.EdgeContactRelationships:
+		ids := make([]ent.Value, 0, len(m.removedcontact_relationships))
+		for id := range m.removedcontact_relationships {
+			ids = append(ids, id)
+		}
+		return ids
+	}
 	return nil
 }
 
 // ClearedEdges returns all edge names that were cleared in this mutation.
 func (m *ContactMutation) ClearedEdges() []string {
-	edges := make([]string, 0, 0)
+	edges := make([]string, 0, 1)
+	if m.clearedcontact_relationships {
+		edges = append(edges, contact.EdgeContactRelationships)
+	}
 	return edges
 }
 
 // EdgeCleared returns a boolean which indicates if the edge with the given name
 // was cleared in this mutation.
 func (m *ContactMutation) EdgeCleared(name string) bool {
+	switch name {
+	case contact.EdgeContactRelationships:
+		return m.clearedcontact_relationships
+	}
 	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 *ContactMutation) ClearEdge(name string) error {
+	switch name {
+	}
 	return fmt.Errorf("unknown Contact 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 *ContactMutation) ResetEdge(name string) error {
+	switch name {
+	case contact.EdgeContactRelationships:
+		m.ResetContactRelationships()
+		return nil
+	}
 	return fmt.Errorf("unknown Contact edge %s", name)
 }
 
+// LabelMutation represents an operation that mutates the Label nodes in the graph.
+type LabelMutation struct {
+	config
+	op                         Op
+	typ                        string
+	id                         *uint64
+	created_at                 *time.Time
+	updated_at                 *time.Time
+	status                     *uint8
+	addstatus                  *int8
+	deleted_at                 *time.Time
+	_type                      *int
+	add_type                   *int
+	name                       *string
+	from                       *int
+	addfrom                    *int
+	mode                       *int
+	addmode                    *int
+	conditions                 *string
+	clearedFields              map[string]struct{}
+	label_relationships        map[uint64]struct{}
+	removedlabel_relationships map[uint64]struct{}
+	clearedlabel_relationships bool
+	done                       bool
+	oldValue                   func(context.Context) (*Label, error)
+	predicates                 []predicate.Label
+}
+
+var _ ent.Mutation = (*LabelMutation)(nil)
+
+// labelOption allows management of the mutation configuration using functional options.
+type labelOption func(*LabelMutation)
+
+// newLabelMutation creates new mutation for the Label entity.
+func newLabelMutation(c config, op Op, opts ...labelOption) *LabelMutation {
+	m := &LabelMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeLabel,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withLabelID sets the ID field of the mutation.
+func withLabelID(id uint64) labelOption {
+	return func(m *LabelMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Label
+		)
+		m.oldValue = func(ctx context.Context) (*Label, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Label.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withLabel sets the old Label of the mutation.
+func withLabel(node *Label) labelOption {
+	return func(m *LabelMutation) {
+		m.oldValue = func(context.Context) (*Label, 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 LabelMutation) 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 LabelMutation) 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 Label entities.
+func (m *LabelMutation) 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 *LabelMutation) 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 *LabelMutation) 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().Label.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 *LabelMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *LabelMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *LabelMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) 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 *LabelMutation) 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 *LabelMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[label.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *LabelMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[label.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *LabelMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, label.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *LabelMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[label.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *LabelMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[label.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *LabelMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, label.FieldDeletedAt)
+}
+
+// SetType sets the "type" field.
+func (m *LabelMutation) SetType(i int) {
+	m._type = &i
+	m.add_type = nil
+}
+
+// GetType returns the value of the "type" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) 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 *LabelMutation) 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 *LabelMutation) ResetType() {
+	m._type = nil
+	m.add_type = nil
+}
+
+// SetName sets the "name" field.
+func (m *LabelMutation) SetName(s string) {
+	m.name = &s
+}
+
+// Name returns the value of the "name" field in the mutation.
+func (m *LabelMutation) 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 Label entity.
+// If the Label 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 *LabelMutation) 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 *LabelMutation) ResetName() {
+	m.name = nil
+}
+
+// SetFrom sets the "from" field.
+func (m *LabelMutation) SetFrom(i int) {
+	m.from = &i
+	m.addfrom = nil
+}
+
+// From returns the value of the "from" field in the mutation.
+func (m *LabelMutation) From() (r int, exists bool) {
+	v := m.from
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldFrom returns the old "from" field's value of the Label entity.
+// If the Label 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 *LabelMutation) OldFrom(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldFrom is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldFrom requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldFrom: %w", err)
+	}
+	return oldValue.From, nil
+}
+
+// AddFrom adds i to the "from" field.
+func (m *LabelMutation) AddFrom(i int) {
+	if m.addfrom != nil {
+		*m.addfrom += i
+	} else {
+		m.addfrom = &i
+	}
+}
+
+// AddedFrom returns the value that was added to the "from" field in this mutation.
+func (m *LabelMutation) AddedFrom() (r int, exists bool) {
+	v := m.addfrom
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetFrom resets all changes to the "from" field.
+func (m *LabelMutation) ResetFrom() {
+	m.from = nil
+	m.addfrom = nil
+}
+
+// SetMode sets the "mode" field.
+func (m *LabelMutation) SetMode(i int) {
+	m.mode = &i
+	m.addmode = nil
+}
+
+// Mode returns the value of the "mode" field in the mutation.
+func (m *LabelMutation) Mode() (r int, exists bool) {
+	v := m.mode
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldMode returns the old "mode" field's value of the Label entity.
+// If the Label 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 *LabelMutation) OldMode(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldMode is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldMode requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldMode: %w", err)
+	}
+	return oldValue.Mode, nil
+}
+
+// AddMode adds i to the "mode" field.
+func (m *LabelMutation) AddMode(i int) {
+	if m.addmode != nil {
+		*m.addmode += i
+	} else {
+		m.addmode = &i
+	}
+}
+
+// AddedMode returns the value that was added to the "mode" field in this mutation.
+func (m *LabelMutation) AddedMode() (r int, exists bool) {
+	v := m.addmode
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetMode resets all changes to the "mode" field.
+func (m *LabelMutation) ResetMode() {
+	m.mode = nil
+	m.addmode = nil
+}
+
+// SetConditions sets the "conditions" field.
+func (m *LabelMutation) SetConditions(s string) {
+	m.conditions = &s
+}
+
+// Conditions returns the value of the "conditions" field in the mutation.
+func (m *LabelMutation) Conditions() (r string, exists bool) {
+	v := m.conditions
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldConditions returns the old "conditions" field's value of the Label entity.
+// If the Label 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 *LabelMutation) OldConditions(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldConditions is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldConditions requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldConditions: %w", err)
+	}
+	return oldValue.Conditions, nil
+}
+
+// ClearConditions clears the value of the "conditions" field.
+func (m *LabelMutation) ClearConditions() {
+	m.conditions = nil
+	m.clearedFields[label.FieldConditions] = struct{}{}
+}
+
+// ConditionsCleared returns if the "conditions" field was cleared in this mutation.
+func (m *LabelMutation) ConditionsCleared() bool {
+	_, ok := m.clearedFields[label.FieldConditions]
+	return ok
+}
+
+// ResetConditions resets all changes to the "conditions" field.
+func (m *LabelMutation) ResetConditions() {
+	m.conditions = nil
+	delete(m.clearedFields, label.FieldConditions)
+}
+
+// AddLabelRelationshipIDs adds the "label_relationships" edge to the LabelRelationship entity by ids.
+func (m *LabelMutation) AddLabelRelationshipIDs(ids ...uint64) {
+	if m.label_relationships == nil {
+		m.label_relationships = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.label_relationships[ids[i]] = struct{}{}
+	}
+}
+
+// ClearLabelRelationships clears the "label_relationships" edge to the LabelRelationship entity.
+func (m *LabelMutation) ClearLabelRelationships() {
+	m.clearedlabel_relationships = true
+}
+
+// LabelRelationshipsCleared reports if the "label_relationships" edge to the LabelRelationship entity was cleared.
+func (m *LabelMutation) LabelRelationshipsCleared() bool {
+	return m.clearedlabel_relationships
+}
+
+// RemoveLabelRelationshipIDs removes the "label_relationships" edge to the LabelRelationship entity by IDs.
+func (m *LabelMutation) RemoveLabelRelationshipIDs(ids ...uint64) {
+	if m.removedlabel_relationships == nil {
+		m.removedlabel_relationships = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.label_relationships, ids[i])
+		m.removedlabel_relationships[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedLabelRelationships returns the removed IDs of the "label_relationships" edge to the LabelRelationship entity.
+func (m *LabelMutation) RemovedLabelRelationshipsIDs() (ids []uint64) {
+	for id := range m.removedlabel_relationships {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// LabelRelationshipsIDs returns the "label_relationships" edge IDs in the mutation.
+func (m *LabelMutation) LabelRelationshipsIDs() (ids []uint64) {
+	for id := range m.label_relationships {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetLabelRelationships resets all changes to the "label_relationships" edge.
+func (m *LabelMutation) ResetLabelRelationships() {
+	m.label_relationships = nil
+	m.clearedlabel_relationships = false
+	m.removedlabel_relationships = nil
+}
+
+// Where appends a list predicates to the LabelMutation builder.
+func (m *LabelMutation) Where(ps ...predicate.Label) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the LabelMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *LabelMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Label, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *LabelMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *LabelMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Label).
+func (m *LabelMutation) 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 *LabelMutation) Fields() []string {
+	fields := make([]string, 0, 9)
+	if m.created_at != nil {
+		fields = append(fields, label.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, label.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, label.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, label.FieldDeletedAt)
+	}
+	if m._type != nil {
+		fields = append(fields, label.FieldType)
+	}
+	if m.name != nil {
+		fields = append(fields, label.FieldName)
+	}
+	if m.from != nil {
+		fields = append(fields, label.FieldFrom)
+	}
+	if m.mode != nil {
+		fields = append(fields, label.FieldMode)
+	}
+	if m.conditions != nil {
+		fields = append(fields, label.FieldConditions)
+	}
+	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 *LabelMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case label.FieldCreatedAt:
+		return m.CreatedAt()
+	case label.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case label.FieldStatus:
+		return m.Status()
+	case label.FieldDeletedAt:
+		return m.DeletedAt()
+	case label.FieldType:
+		return m.GetType()
+	case label.FieldName:
+		return m.Name()
+	case label.FieldFrom:
+		return m.From()
+	case label.FieldMode:
+		return m.Mode()
+	case label.FieldConditions:
+		return m.Conditions()
+	}
+	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 *LabelMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case label.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case label.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case label.FieldStatus:
+		return m.OldStatus(ctx)
+	case label.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case label.FieldType:
+		return m.OldType(ctx)
+	case label.FieldName:
+		return m.OldName(ctx)
+	case label.FieldFrom:
+		return m.OldFrom(ctx)
+	case label.FieldMode:
+		return m.OldMode(ctx)
+	case label.FieldConditions:
+		return m.OldConditions(ctx)
+	}
+	return nil, fmt.Errorf("unknown Label 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 *LabelMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case label.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 label.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 label.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case label.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	case label.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetType(v)
+		return nil
+	case label.FieldName:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetName(v)
+		return nil
+	case label.FieldFrom:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetFrom(v)
+		return nil
+	case label.FieldMode:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetMode(v)
+		return nil
+	case label.FieldConditions:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetConditions(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Label field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *LabelMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, label.FieldStatus)
+	}
+	if m.add_type != nil {
+		fields = append(fields, label.FieldType)
+	}
+	if m.addfrom != nil {
+		fields = append(fields, label.FieldFrom)
+	}
+	if m.addmode != nil {
+		fields = append(fields, label.FieldMode)
+	}
+	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 *LabelMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case label.FieldStatus:
+		return m.AddedStatus()
+	case label.FieldType:
+		return m.AddedType()
+	case label.FieldFrom:
+		return m.AddedFrom()
+	case label.FieldMode:
+		return m.AddedMode()
+	}
+	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 *LabelMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case label.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case label.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddType(v)
+		return nil
+	case label.FieldFrom:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddFrom(v)
+		return nil
+	case label.FieldMode:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddMode(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Label numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *LabelMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(label.FieldStatus) {
+		fields = append(fields, label.FieldStatus)
+	}
+	if m.FieldCleared(label.FieldDeletedAt) {
+		fields = append(fields, label.FieldDeletedAt)
+	}
+	if m.FieldCleared(label.FieldConditions) {
+		fields = append(fields, label.FieldConditions)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *LabelMutation) 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 *LabelMutation) ClearField(name string) error {
+	switch name {
+	case label.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case label.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	case label.FieldConditions:
+		m.ClearConditions()
+		return nil
+	}
+	return fmt.Errorf("unknown Label 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 *LabelMutation) ResetField(name string) error {
+	switch name {
+	case label.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case label.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case label.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case label.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case label.FieldType:
+		m.ResetType()
+		return nil
+	case label.FieldName:
+		m.ResetName()
+		return nil
+	case label.FieldFrom:
+		m.ResetFrom()
+		return nil
+	case label.FieldMode:
+		m.ResetMode()
+		return nil
+	case label.FieldConditions:
+		m.ResetConditions()
+		return nil
+	}
+	return fmt.Errorf("unknown Label field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *LabelMutation) AddedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.label_relationships != nil {
+		edges = append(edges, label.EdgeLabelRelationships)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *LabelMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case label.EdgeLabelRelationships:
+		ids := make([]ent.Value, 0, len(m.label_relationships))
+		for id := range m.label_relationships {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *LabelMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.removedlabel_relationships != nil {
+		edges = append(edges, label.EdgeLabelRelationships)
+	}
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *LabelMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case label.EdgeLabelRelationships:
+		ids := make([]ent.Value, 0, len(m.removedlabel_relationships))
+		for id := range m.removedlabel_relationships {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *LabelMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.clearedlabel_relationships {
+		edges = append(edges, label.EdgeLabelRelationships)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *LabelMutation) EdgeCleared(name string) bool {
+	switch name {
+	case label.EdgeLabelRelationships:
+		return m.clearedlabel_relationships
+	}
+	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 *LabelMutation) ClearEdge(name string) error {
+	switch name {
+	}
+	return fmt.Errorf("unknown Label 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 *LabelMutation) ResetEdge(name string) error {
+	switch name {
+	case label.EdgeLabelRelationships:
+		m.ResetLabelRelationships()
+		return nil
+	}
+	return fmt.Errorf("unknown Label edge %s", name)
+}
+
+// LabelRelationshipMutation represents an operation that mutates the LabelRelationship nodes in the graph.
+type LabelRelationshipMutation struct {
+	config
+	op              Op
+	typ             string
+	id              *uint64
+	created_at      *time.Time
+	updated_at      *time.Time
+	status          *uint8
+	addstatus       *int8
+	deleted_at      *time.Time
+	clearedFields   map[string]struct{}
+	contacts        *uint64
+	clearedcontacts bool
+	labels          *uint64
+	clearedlabels   bool
+	done            bool
+	oldValue        func(context.Context) (*LabelRelationship, error)
+	predicates      []predicate.LabelRelationship
+}
+
+var _ ent.Mutation = (*LabelRelationshipMutation)(nil)
+
+// labelrelationshipOption allows management of the mutation configuration using functional options.
+type labelrelationshipOption func(*LabelRelationshipMutation)
+
+// newLabelRelationshipMutation creates new mutation for the LabelRelationship entity.
+func newLabelRelationshipMutation(c config, op Op, opts ...labelrelationshipOption) *LabelRelationshipMutation {
+	m := &LabelRelationshipMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeLabelRelationship,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withLabelRelationshipID sets the ID field of the mutation.
+func withLabelRelationshipID(id uint64) labelrelationshipOption {
+	return func(m *LabelRelationshipMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *LabelRelationship
+		)
+		m.oldValue = func(ctx context.Context) (*LabelRelationship, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().LabelRelationship.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withLabelRelationship sets the old LabelRelationship of the mutation.
+func withLabelRelationship(node *LabelRelationship) labelrelationshipOption {
+	return func(m *LabelRelationshipMutation) {
+		m.oldValue = func(context.Context) (*LabelRelationship, 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 LabelRelationshipMutation) 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 LabelRelationshipMutation) 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 LabelRelationship entities.
+func (m *LabelRelationshipMutation) 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) 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().LabelRelationship.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 *LabelRelationshipMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *LabelRelationshipMutation) 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 LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *LabelRelationshipMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *LabelRelationshipMutation) 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 LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *LabelRelationshipMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *LabelRelationshipMutation) 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 LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[labelrelationship.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *LabelRelationshipMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[labelrelationship.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *LabelRelationshipMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, labelrelationship.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *LabelRelationshipMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *LabelRelationshipMutation) 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 LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) 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 *LabelRelationshipMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[labelrelationship.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *LabelRelationshipMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[labelrelationship.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *LabelRelationshipMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, labelrelationship.FieldDeletedAt)
+}
+
+// SetLabelID sets the "label_id" field.
+func (m *LabelRelationshipMutation) SetLabelID(u uint64) {
+	m.labels = &u
+}
+
+// LabelID returns the value of the "label_id" field in the mutation.
+func (m *LabelRelationshipMutation) LabelID() (r uint64, exists bool) {
+	v := m.labels
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldLabelID returns the old "label_id" field's value of the LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) OldLabelID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldLabelID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldLabelID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldLabelID: %w", err)
+	}
+	return oldValue.LabelID, nil
+}
+
+// ResetLabelID resets all changes to the "label_id" field.
+func (m *LabelRelationshipMutation) ResetLabelID() {
+	m.labels = nil
+}
+
+// SetContactID sets the "contact_id" field.
+func (m *LabelRelationshipMutation) SetContactID(u uint64) {
+	m.contacts = &u
+}
+
+// ContactID returns the value of the "contact_id" field in the mutation.
+func (m *LabelRelationshipMutation) ContactID() (r uint64, exists bool) {
+	v := m.contacts
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldContactID returns the old "contact_id" field's value of the LabelRelationship entity.
+// If the LabelRelationship 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 *LabelRelationshipMutation) OldContactID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldContactID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldContactID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldContactID: %w", err)
+	}
+	return oldValue.ContactID, nil
+}
+
+// ResetContactID resets all changes to the "contact_id" field.
+func (m *LabelRelationshipMutation) ResetContactID() {
+	m.contacts = nil
+}
+
+// SetContactsID sets the "contacts" edge to the Contact entity by id.
+func (m *LabelRelationshipMutation) SetContactsID(id uint64) {
+	m.contacts = &id
+}
+
+// ClearContacts clears the "contacts" edge to the Contact entity.
+func (m *LabelRelationshipMutation) ClearContacts() {
+	m.clearedcontacts = true
+	m.clearedFields[labelrelationship.FieldContactID] = struct{}{}
+}
+
+// ContactsCleared reports if the "contacts" edge to the Contact entity was cleared.
+func (m *LabelRelationshipMutation) ContactsCleared() bool {
+	return m.clearedcontacts
+}
+
+// ContactsID returns the "contacts" edge ID in the mutation.
+func (m *LabelRelationshipMutation) ContactsID() (id uint64, exists bool) {
+	if m.contacts != nil {
+		return *m.contacts, true
+	}
+	return
+}
+
+// ContactsIDs returns the "contacts" edge IDs in the mutation.
+// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
+// ContactsID instead. It exists only for internal usage by the builders.
+func (m *LabelRelationshipMutation) ContactsIDs() (ids []uint64) {
+	if id := m.contacts; id != nil {
+		ids = append(ids, *id)
+	}
+	return
+}
+
+// ResetContacts resets all changes to the "contacts" edge.
+func (m *LabelRelationshipMutation) ResetContacts() {
+	m.contacts = nil
+	m.clearedcontacts = false
+}
+
+// SetLabelsID sets the "labels" edge to the Label entity by id.
+func (m *LabelRelationshipMutation) SetLabelsID(id uint64) {
+	m.labels = &id
+}
+
+// ClearLabels clears the "labels" edge to the Label entity.
+func (m *LabelRelationshipMutation) ClearLabels() {
+	m.clearedlabels = true
+	m.clearedFields[labelrelationship.FieldLabelID] = struct{}{}
+}
+
+// LabelsCleared reports if the "labels" edge to the Label entity was cleared.
+func (m *LabelRelationshipMutation) LabelsCleared() bool {
+	return m.clearedlabels
+}
+
+// LabelsID returns the "labels" edge ID in the mutation.
+func (m *LabelRelationshipMutation) LabelsID() (id uint64, exists bool) {
+	if m.labels != nil {
+		return *m.labels, true
+	}
+	return
+}
+
+// LabelsIDs returns the "labels" edge IDs in the mutation.
+// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
+// LabelsID instead. It exists only for internal usage by the builders.
+func (m *LabelRelationshipMutation) LabelsIDs() (ids []uint64) {
+	if id := m.labels; id != nil {
+		ids = append(ids, *id)
+	}
+	return
+}
+
+// ResetLabels resets all changes to the "labels" edge.
+func (m *LabelRelationshipMutation) ResetLabels() {
+	m.labels = nil
+	m.clearedlabels = false
+}
+
+// Where appends a list predicates to the LabelRelationshipMutation builder.
+func (m *LabelRelationshipMutation) Where(ps ...predicate.LabelRelationship) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the LabelRelationshipMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *LabelRelationshipMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.LabelRelationship, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *LabelRelationshipMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *LabelRelationshipMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (LabelRelationship).
+func (m *LabelRelationshipMutation) 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 *LabelRelationshipMutation) Fields() []string {
+	fields := make([]string, 0, 6)
+	if m.created_at != nil {
+		fields = append(fields, labelrelationship.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, labelrelationship.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, labelrelationship.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, labelrelationship.FieldDeletedAt)
+	}
+	if m.labels != nil {
+		fields = append(fields, labelrelationship.FieldLabelID)
+	}
+	if m.contacts != nil {
+		fields = append(fields, labelrelationship.FieldContactID)
+	}
+	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 *LabelRelationshipMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case labelrelationship.FieldCreatedAt:
+		return m.CreatedAt()
+	case labelrelationship.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case labelrelationship.FieldStatus:
+		return m.Status()
+	case labelrelationship.FieldDeletedAt:
+		return m.DeletedAt()
+	case labelrelationship.FieldLabelID:
+		return m.LabelID()
+	case labelrelationship.FieldContactID:
+		return m.ContactID()
+	}
+	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 *LabelRelationshipMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case labelrelationship.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case labelrelationship.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case labelrelationship.FieldStatus:
+		return m.OldStatus(ctx)
+	case labelrelationship.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case labelrelationship.FieldLabelID:
+		return m.OldLabelID(ctx)
+	case labelrelationship.FieldContactID:
+		return m.OldContactID(ctx)
+	}
+	return nil, fmt.Errorf("unknown LabelRelationship 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 *LabelRelationshipMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case labelrelationship.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 labelrelationship.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 labelrelationship.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case labelrelationship.FieldDeletedAt:
+		v, ok := value.(time.Time)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDeletedAt(v)
+		return nil
+	case labelrelationship.FieldLabelID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetLabelID(v)
+		return nil
+	case labelrelationship.FieldContactID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetContactID(v)
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *LabelRelationshipMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, labelrelationship.FieldStatus)
+	}
+	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 *LabelRelationshipMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case labelrelationship.FieldStatus:
+		return m.AddedStatus()
+	}
+	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 *LabelRelationshipMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case labelrelationship.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *LabelRelationshipMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(labelrelationship.FieldStatus) {
+		fields = append(fields, labelrelationship.FieldStatus)
+	}
+	if m.FieldCleared(labelrelationship.FieldDeletedAt) {
+		fields = append(fields, labelrelationship.FieldDeletedAt)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *LabelRelationshipMutation) 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 *LabelRelationshipMutation) ClearField(name string) error {
+	switch name {
+	case labelrelationship.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case labelrelationship.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship 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 *LabelRelationshipMutation) ResetField(name string) error {
+	switch name {
+	case labelrelationship.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case labelrelationship.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case labelrelationship.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case labelrelationship.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case labelrelationship.FieldLabelID:
+		m.ResetLabelID()
+		return nil
+	case labelrelationship.FieldContactID:
+		m.ResetContactID()
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *LabelRelationshipMutation) AddedEdges() []string {
+	edges := make([]string, 0, 2)
+	if m.contacts != nil {
+		edges = append(edges, labelrelationship.EdgeContacts)
+	}
+	if m.labels != nil {
+		edges = append(edges, labelrelationship.EdgeLabels)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *LabelRelationshipMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case labelrelationship.EdgeContacts:
+		if id := m.contacts; id != nil {
+			return []ent.Value{*id}
+		}
+	case labelrelationship.EdgeLabels:
+		if id := m.labels; id != nil {
+			return []ent.Value{*id}
+		}
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *LabelRelationshipMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 2)
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *LabelRelationshipMutation) RemovedIDs(name string) []ent.Value {
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *LabelRelationshipMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 2)
+	if m.clearedcontacts {
+		edges = append(edges, labelrelationship.EdgeContacts)
+	}
+	if m.clearedlabels {
+		edges = append(edges, labelrelationship.EdgeLabels)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *LabelRelationshipMutation) EdgeCleared(name string) bool {
+	switch name {
+	case labelrelationship.EdgeContacts:
+		return m.clearedcontacts
+	case labelrelationship.EdgeLabels:
+		return m.clearedlabels
+	}
+	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 *LabelRelationshipMutation) ClearEdge(name string) error {
+	switch name {
+	case labelrelationship.EdgeContacts:
+		m.ClearContacts()
+		return nil
+	case labelrelationship.EdgeLabels:
+		m.ClearLabels()
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship 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 *LabelRelationshipMutation) ResetEdge(name string) error {
+	switch name {
+	case labelrelationship.EdgeContacts:
+		m.ResetContacts()
+		return nil
+	case labelrelationship.EdgeLabels:
+		m.ResetLabels()
+		return nil
+	}
+	return fmt.Errorf("unknown LabelRelationship edge %s", name)
+}
+
+// MessageMutation represents an operation that mutates the Message nodes in the graph.
+type MessageMutation struct {
+	config
+	op            Op
+	typ           string
+	id            *int
+	wx_wxid       *string
+	wxid          *string
+	content       *string
+	clearedFields map[string]struct{}
+	done          bool
+	oldValue      func(context.Context) (*Message, error)
+	predicates    []predicate.Message
+}
+
+var _ ent.Mutation = (*MessageMutation)(nil)
+
+// messageOption allows management of the mutation configuration using functional options.
+type messageOption func(*MessageMutation)
+
+// newMessageMutation creates new mutation for the Message entity.
+func newMessageMutation(c config, op Op, opts ...messageOption) *MessageMutation {
+	m := &MessageMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeMessage,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withMessageID sets the ID field of the mutation.
+func withMessageID(id int) messageOption {
+	return func(m *MessageMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Message
+		)
+		m.oldValue = func(ctx context.Context) (*Message, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Message.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withMessage sets the old Message of the mutation.
+func withMessage(node *Message) messageOption {
+	return func(m *MessageMutation) {
+		m.oldValue = func(context.Context) (*Message, 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 MessageMutation) 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 MessageMutation) Tx() (*Tx, error) {
+	if _, ok := m.driver.(*txDriver); !ok {
+		return nil, errors.New("ent: mutation is not running in a transaction")
+	}
+	tx := &Tx{config: m.config}
+	tx.init()
+	return tx, nil
+}
+
+// ID returns the ID value in the mutation. Note that the ID is only available
+// if it was provided to the builder or after it was returned from the database.
+func (m *MessageMutation) ID() (id int, exists bool) {
+	if m.id == nil {
+		return
+	}
+	return *m.id, true
+}
+
+// IDs queries the database and returns the entity ids that match the mutation's predicate.
+// That means, if the mutation is applied within a transaction with an isolation level such
+// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
+// or updated by the mutation.
+func (m *MessageMutation) IDs(ctx context.Context) ([]int, error) {
+	switch {
+	case m.op.Is(OpUpdateOne | OpDeleteOne):
+		id, exists := m.ID()
+		if exists {
+			return []int{id}, nil
+		}
+		fallthrough
+	case m.op.Is(OpUpdate | OpDelete):
+		return m.Client().Message.Query().Where(m.predicates...).IDs(ctx)
+	default:
+		return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
+	}
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (m *MessageMutation) SetWxWxid(s string) {
+	m.wx_wxid = &s
+}
+
+// WxWxid returns the value of the "wx_wxid" field in the mutation.
+func (m *MessageMutation) WxWxid() (r string, exists bool) {
+	v := m.wx_wxid
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldWxWxid returns the old "wx_wxid" field's value of the Message entity.
+// If the Message 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 *MessageMutation) OldWxWxid(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldWxWxid is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldWxWxid requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldWxWxid: %w", err)
+	}
+	return oldValue.WxWxid, nil
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (m *MessageMutation) ClearWxWxid() {
+	m.wx_wxid = nil
+	m.clearedFields[message.FieldWxWxid] = struct{}{}
+}
+
+// WxWxidCleared returns if the "wx_wxid" field was cleared in this mutation.
+func (m *MessageMutation) WxWxidCleared() bool {
+	_, ok := m.clearedFields[message.FieldWxWxid]
+	return ok
+}
+
+// ResetWxWxid resets all changes to the "wx_wxid" field.
+func (m *MessageMutation) ResetWxWxid() {
+	m.wx_wxid = nil
+	delete(m.clearedFields, message.FieldWxWxid)
+}
+
+// SetWxid sets the "wxid" field.
+func (m *MessageMutation) SetWxid(s string) {
+	m.wxid = &s
+}
+
+// Wxid returns the value of the "wxid" field in the mutation.
+func (m *MessageMutation) Wxid() (r string, exists bool) {
+	v := m.wxid
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldWxid returns the old "wxid" field's value of the Message entity.
+// If the Message 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 *MessageMutation) OldWxid(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldWxid is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldWxid requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldWxid: %w", err)
+	}
+	return oldValue.Wxid, nil
+}
+
+// ResetWxid resets all changes to the "wxid" field.
+func (m *MessageMutation) ResetWxid() {
+	m.wxid = nil
+}
+
+// SetContent sets the "content" field.
+func (m *MessageMutation) SetContent(s string) {
+	m.content = &s
+}
+
+// Content returns the value of the "content" field in the mutation.
+func (m *MessageMutation) Content() (r string, exists bool) {
+	v := m.content
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldContent returns the old "content" field's value of the Message entity.
+// If the Message 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 *MessageMutation) OldContent(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldContent is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldContent requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldContent: %w", err)
+	}
+	return oldValue.Content, nil
+}
+
+// ResetContent resets all changes to the "content" field.
+func (m *MessageMutation) ResetContent() {
+	m.content = nil
+}
+
+// Where appends a list predicates to the MessageMutation builder.
+func (m *MessageMutation) Where(ps ...predicate.Message) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the MessageMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *MessageMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Message, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *MessageMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *MessageMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Message).
+func (m *MessageMutation) 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 *MessageMutation) Fields() []string {
+	fields := make([]string, 0, 3)
+	if m.wx_wxid != nil {
+		fields = append(fields, message.FieldWxWxid)
+	}
+	if m.wxid != nil {
+		fields = append(fields, message.FieldWxid)
+	}
+	if m.content != nil {
+		fields = append(fields, message.FieldContent)
+	}
+	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 *MessageMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case message.FieldWxWxid:
+		return m.WxWxid()
+	case message.FieldWxid:
+		return m.Wxid()
+	case message.FieldContent:
+		return m.Content()
+	}
+	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 *MessageMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case message.FieldWxWxid:
+		return m.OldWxWxid(ctx)
+	case message.FieldWxid:
+		return m.OldWxid(ctx)
+	case message.FieldContent:
+		return m.OldContent(ctx)
+	}
+	return nil, fmt.Errorf("unknown Message 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 *MessageMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case message.FieldWxWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxWxid(v)
+		return nil
+	case message.FieldWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxid(v)
+		return nil
+	case message.FieldContent:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetContent(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Message field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *MessageMutation) AddedFields() []string {
+	return nil
+}
+
+// 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 *MessageMutation) AddedField(name string) (ent.Value, bool) {
+	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 *MessageMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	}
+	return fmt.Errorf("unknown Message numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *MessageMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(message.FieldWxWxid) {
+		fields = append(fields, message.FieldWxWxid)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *MessageMutation) 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 *MessageMutation) ClearField(name string) error {
+	switch name {
+	case message.FieldWxWxid:
+		m.ClearWxWxid()
+		return nil
+	}
+	return fmt.Errorf("unknown Message 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 *MessageMutation) ResetField(name string) error {
+	switch name {
+	case message.FieldWxWxid:
+		m.ResetWxWxid()
+		return nil
+	case message.FieldWxid:
+		m.ResetWxid()
+		return nil
+	case message.FieldContent:
+		m.ResetContent()
+		return nil
+	}
+	return fmt.Errorf("unknown Message field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *MessageMutation) AddedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *MessageMutation) AddedIDs(name string) []ent.Value {
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *MessageMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *MessageMutation) RemovedIDs(name string) []ent.Value {
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *MessageMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 0)
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *MessageMutation) EdgeCleared(name string) bool {
+	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 *MessageMutation) ClearEdge(name string) error {
+	return fmt.Errorf("unknown Message 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 *MessageMutation) ResetEdge(name string) error {
+	return fmt.Errorf("unknown Message edge %s", name)
+}
+
 // ServerMutation represents an operation that mutates the Server nodes in the graph.
 type ServerMutation struct {
 	config

+ 255 - 3
ent/pagination.go

@@ -6,6 +6,9 @@ import (
 	"context"
 	"fmt"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
 )
@@ -111,7 +114,9 @@ func (c *ContactQuery) Page(
 		Size: pageSize,
 	}
 
-	count, err := c.Clone().Count(ctx)
+	query := c.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
 
 	if err != nil {
 		return nil, err
@@ -135,6 +140,249 @@ func (c *ContactQuery) Page(
 	return ret, nil
 }
 
+type LabelPager struct {
+	Order  label.OrderOption
+	Filter func(*LabelQuery) (*LabelQuery, error)
+}
+
+// LabelPaginateOption enables pagination customization.
+type LabelPaginateOption func(*LabelPager)
+
+// DefaultLabelOrder is the default ordering of Label.
+var DefaultLabelOrder = Desc(label.FieldID)
+
+func newLabelPager(opts []LabelPaginateOption) (*LabelPager, error) {
+	pager := &LabelPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultLabelOrder
+	}
+	return pager, nil
+}
+
+func (p *LabelPager) ApplyFilter(query *LabelQuery) (*LabelQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// LabelPageList is Label PageList result.
+type LabelPageList struct {
+	List        []*Label     `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (l *LabelQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...LabelPaginateOption,
+) (*LabelPageList, error) {
+
+	pager, err := newLabelPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if l, err = pager.ApplyFilter(l); err != nil {
+		return nil, err
+	}
+
+	ret := &LabelPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	query := l.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		l = l.Order(pager.Order)
+	} else {
+		l = l.Order(DefaultLabelOrder)
+	}
+
+	l = l.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := l.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
+type LabelRelationshipPager struct {
+	Order  labelrelationship.OrderOption
+	Filter func(*LabelRelationshipQuery) (*LabelRelationshipQuery, error)
+}
+
+// LabelRelationshipPaginateOption enables pagination customization.
+type LabelRelationshipPaginateOption func(*LabelRelationshipPager)
+
+// DefaultLabelRelationshipOrder is the default ordering of LabelRelationship.
+var DefaultLabelRelationshipOrder = Desc(labelrelationship.FieldID)
+
+func newLabelRelationshipPager(opts []LabelRelationshipPaginateOption) (*LabelRelationshipPager, error) {
+	pager := &LabelRelationshipPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultLabelRelationshipOrder
+	}
+	return pager, nil
+}
+
+func (p *LabelRelationshipPager) ApplyFilter(query *LabelRelationshipQuery) (*LabelRelationshipQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// LabelRelationshipPageList is LabelRelationship PageList result.
+type LabelRelationshipPageList struct {
+	List        []*LabelRelationship `json:"list"`
+	PageDetails *PageDetails         `json:"pageDetails"`
+}
+
+func (lr *LabelRelationshipQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...LabelRelationshipPaginateOption,
+) (*LabelRelationshipPageList, error) {
+
+	pager, err := newLabelRelationshipPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if lr, err = pager.ApplyFilter(lr); err != nil {
+		return nil, err
+	}
+
+	ret := &LabelRelationshipPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	query := lr.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		lr = lr.Order(pager.Order)
+	} else {
+		lr = lr.Order(DefaultLabelRelationshipOrder)
+	}
+
+	lr = lr.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := lr.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
+type MessagePager struct {
+	Order  message.OrderOption
+	Filter func(*MessageQuery) (*MessageQuery, error)
+}
+
+// MessagePaginateOption enables pagination customization.
+type MessagePaginateOption func(*MessagePager)
+
+// DefaultMessageOrder is the default ordering of Message.
+var DefaultMessageOrder = Desc(message.FieldID)
+
+func newMessagePager(opts []MessagePaginateOption) (*MessagePager, error) {
+	pager := &MessagePager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultMessageOrder
+	}
+	return pager, nil
+}
+
+func (p *MessagePager) ApplyFilter(query *MessageQuery) (*MessageQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// MessagePageList is Message PageList result.
+type MessagePageList struct {
+	List        []*Message   `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (m *MessageQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...MessagePaginateOption,
+) (*MessagePageList, error) {
+
+	pager, err := newMessagePager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if m, err = pager.ApplyFilter(m); err != nil {
+		return nil, err
+	}
+
+	ret := &MessagePageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	query := m.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		m = m.Order(pager.Order)
+	} else {
+		m = m.Order(DefaultMessageOrder)
+	}
+
+	m = m.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := m.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
 type ServerPager struct {
 	Order  server.OrderOption
 	Filter func(*ServerQuery) (*ServerQuery, error)
@@ -190,7 +438,9 @@ func (s *ServerQuery) Page(
 		Size: pageSize,
 	}
 
-	count, err := s.Clone().Count(ctx)
+	query := s.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
 
 	if err != nil {
 		return nil, err
@@ -269,7 +519,9 @@ func (w *WxQuery) Page(
 		Size: pageSize,
 	}
 
-	count, err := w.Clone().Count(ctx)
+	query := w.Clone()
+	query.ctx.Fields = nil
+	count, err := query.Count(ctx)
 
 	if err != nil {
 		return nil, err

+ 9 - 0
ent/predicate/predicate.go

@@ -9,6 +9,15 @@ import (
 // Contact is the predicate function for contact builders.
 type Contact func(*sql.Selector)
 
+// Label is the predicate function for label builders.
+type Label func(*sql.Selector)
+
+// LabelRelationship is the predicate function for labelrelationship builders.
+type LabelRelationship func(*sql.Selector)
+
+// Message is the predicate function for message builders.
+type Message func(*sql.Selector)
+
 // Server is the predicate function for server builders.
 type Server func(*sql.Selector)
 

+ 95 - 0
ent/runtime/runtime.go

@@ -5,6 +5,9 @@ package runtime
 import (
 	"time"
 	"wechat-api/ent/contact"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/ent/message"
 	"wechat-api/ent/schema"
 	"wechat-api/ent/server"
 	"wechat-api/ent/wx"
@@ -99,6 +102,98 @@ func init() {
 	contactDescV3 := contactFields[14].Descriptor()
 	// contact.DefaultV3 holds the default value on creation for the v3 field.
 	contact.DefaultV3 = contactDescV3.Default.(string)
+	labelMixin := schema.Label{}.Mixin()
+	labelMixinHooks2 := labelMixin[2].Hooks()
+	label.Hooks[0] = labelMixinHooks2[0]
+	labelMixinInters2 := labelMixin[2].Interceptors()
+	label.Interceptors[0] = labelMixinInters2[0]
+	labelMixinFields0 := labelMixin[0].Fields()
+	_ = labelMixinFields0
+	labelMixinFields1 := labelMixin[1].Fields()
+	_ = labelMixinFields1
+	labelFields := schema.Label{}.Fields()
+	_ = labelFields
+	// labelDescCreatedAt is the schema descriptor for created_at field.
+	labelDescCreatedAt := labelMixinFields0[1].Descriptor()
+	// label.DefaultCreatedAt holds the default value on creation for the created_at field.
+	label.DefaultCreatedAt = labelDescCreatedAt.Default.(func() time.Time)
+	// labelDescUpdatedAt is the schema descriptor for updated_at field.
+	labelDescUpdatedAt := labelMixinFields0[2].Descriptor()
+	// label.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	label.DefaultUpdatedAt = labelDescUpdatedAt.Default.(func() time.Time)
+	// label.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	label.UpdateDefaultUpdatedAt = labelDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// labelDescStatus is the schema descriptor for status field.
+	labelDescStatus := labelMixinFields1[0].Descriptor()
+	// label.DefaultStatus holds the default value on creation for the status field.
+	label.DefaultStatus = labelDescStatus.Default.(uint8)
+	// labelDescType is the schema descriptor for type field.
+	labelDescType := labelFields[0].Descriptor()
+	// label.DefaultType holds the default value on creation for the type field.
+	label.DefaultType = labelDescType.Default.(int)
+	// labelDescName is the schema descriptor for name field.
+	labelDescName := labelFields[1].Descriptor()
+	// label.DefaultName holds the default value on creation for the name field.
+	label.DefaultName = labelDescName.Default.(string)
+	// labelDescFrom is the schema descriptor for from field.
+	labelDescFrom := labelFields[2].Descriptor()
+	// label.DefaultFrom holds the default value on creation for the from field.
+	label.DefaultFrom = labelDescFrom.Default.(int)
+	// labelDescMode is the schema descriptor for mode field.
+	labelDescMode := labelFields[3].Descriptor()
+	// label.DefaultMode holds the default value on creation for the mode field.
+	label.DefaultMode = labelDescMode.Default.(int)
+	// labelDescConditions is the schema descriptor for conditions field.
+	labelDescConditions := labelFields[4].Descriptor()
+	// label.DefaultConditions holds the default value on creation for the conditions field.
+	label.DefaultConditions = labelDescConditions.Default.(string)
+	labelrelationshipMixin := schema.LabelRelationship{}.Mixin()
+	labelrelationshipMixinHooks2 := labelrelationshipMixin[2].Hooks()
+	labelrelationship.Hooks[0] = labelrelationshipMixinHooks2[0]
+	labelrelationshipMixinInters2 := labelrelationshipMixin[2].Interceptors()
+	labelrelationship.Interceptors[0] = labelrelationshipMixinInters2[0]
+	labelrelationshipMixinFields0 := labelrelationshipMixin[0].Fields()
+	_ = labelrelationshipMixinFields0
+	labelrelationshipMixinFields1 := labelrelationshipMixin[1].Fields()
+	_ = labelrelationshipMixinFields1
+	labelrelationshipFields := schema.LabelRelationship{}.Fields()
+	_ = labelrelationshipFields
+	// labelrelationshipDescCreatedAt is the schema descriptor for created_at field.
+	labelrelationshipDescCreatedAt := labelrelationshipMixinFields0[1].Descriptor()
+	// labelrelationship.DefaultCreatedAt holds the default value on creation for the created_at field.
+	labelrelationship.DefaultCreatedAt = labelrelationshipDescCreatedAt.Default.(func() time.Time)
+	// labelrelationshipDescUpdatedAt is the schema descriptor for updated_at field.
+	labelrelationshipDescUpdatedAt := labelrelationshipMixinFields0[2].Descriptor()
+	// labelrelationship.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	labelrelationship.DefaultUpdatedAt = labelrelationshipDescUpdatedAt.Default.(func() time.Time)
+	// labelrelationship.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	labelrelationship.UpdateDefaultUpdatedAt = labelrelationshipDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// labelrelationshipDescStatus is the schema descriptor for status field.
+	labelrelationshipDescStatus := labelrelationshipMixinFields1[0].Descriptor()
+	// labelrelationship.DefaultStatus holds the default value on creation for the status field.
+	labelrelationship.DefaultStatus = labelrelationshipDescStatus.Default.(uint8)
+	// labelrelationshipDescLabelID is the schema descriptor for label_id field.
+	labelrelationshipDescLabelID := labelrelationshipFields[0].Descriptor()
+	// labelrelationship.DefaultLabelID holds the default value on creation for the label_id field.
+	labelrelationship.DefaultLabelID = labelrelationshipDescLabelID.Default.(uint64)
+	// labelrelationshipDescContactID is the schema descriptor for contact_id field.
+	labelrelationshipDescContactID := labelrelationshipFields[1].Descriptor()
+	// labelrelationship.DefaultContactID holds the default value on creation for the contact_id field.
+	labelrelationship.DefaultContactID = labelrelationshipDescContactID.Default.(uint64)
+	messageFields := schema.Message{}.Fields()
+	_ = messageFields
+	// messageDescWxWxid is the schema descriptor for wx_wxid field.
+	messageDescWxWxid := messageFields[0].Descriptor()
+	// message.DefaultWxWxid holds the default value on creation for the wx_wxid field.
+	message.DefaultWxWxid = messageDescWxWxid.Default.(string)
+	// messageDescWxid is the schema descriptor for wxid field.
+	messageDescWxid := messageFields[1].Descriptor()
+	// message.DefaultWxid holds the default value on creation for the wxid field.
+	message.DefaultWxid = messageDescWxid.Default.(string)
+	// messageDescContent is the schema descriptor for content field.
+	messageDescContent := messageFields[2].Descriptor()
+	// message.DefaultContent holds the default value on creation for the content field.
+	message.DefaultContent = messageDescContent.Default.(string)
 	serverMixin := schema.Server{}.Mixin()
 	serverMixinHooks2 := serverMixin[2].Hooks()
 	server.Hooks[0] = serverMixinHooks2[0]

+ 4 - 1
ent/schema/contact.go

@@ -4,6 +4,7 @@ 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"
@@ -82,7 +83,9 @@ func (Contact) Indexes() []ent.Index {
 }
 
 func (Contact) Edges() []ent.Edge {
-	return nil
+	return []ent.Edge{
+		edge.To("contact_relationships", LabelRelationship.Type),
+	}
 }
 func (Contact) Annotations() []schema.Annotation {
 	return []schema.Annotation{entsql.Annotation{Table: "contact"}}

+ 59 - 0
ent/schema/label.go

@@ -0,0 +1,59 @@
+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"
+	"wechat-api/ent/schema/localmixin"
+)
+
+type Label struct {
+	ent.Schema
+}
+
+func (Label) Fields() []ent.Field {
+	return []ent.Field{
+		field.Int("type").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("标签类型:1好友,2群组,3公众号,4企业微信联系人"),
+		field.String("name").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("标签名称"),
+		field.Int("from").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("标签来源:1后台创建 2个微同步"),
+		field.Int("mode").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("标签模式:1动态 2静态"),
+		field.String("conditions").Optional().Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("标签的触达条件"),
+	}
+}
+
+func (Label) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (Label) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("name", "from", "mode").Unique(),
+	}
+}
+
+func (Label) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.To("label_relationships", LabelRelationship.Type),
+	}
+}
+func (Label) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "label"}}
+}

+ 60 - 0
ent/schema/label_relationship.go

@@ -0,0 +1,60 @@
+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"
+	"wechat-api/ent/schema/localmixin"
+)
+
+type LabelRelationship struct {
+	ent.Schema
+}
+
+func (LabelRelationship) Fields() []ent.Field {
+	return []ent.Field{
+		field.Uint64("label_id").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("标签 ID"),
+		field.Uint64("contact_id").Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("联系人 ID"),
+	}
+}
+
+func (LabelRelationship) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (LabelRelationship) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("label_id"),
+		index.Fields("contact_id"),
+	}
+}
+
+func (LabelRelationship) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.From("contacts", Contact.Type).
+			Ref("contact_relationships").
+			Unique().
+			Field("contact_id").
+			Required(),
+		edge.From("labels", Label.Type).
+			Ref("label_relationships").
+			Unique().
+			Field("label_id").
+			Required(),
+	}
+}
+func (LabelRelationship) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "label_relationship"}}
+}

+ 384 - 0
ent/set_not_nil.go

@@ -437,6 +437,390 @@ func (c *ContactCreate) SetNotNilV3(value *string) *ContactCreate {
 }
 
 // set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilUpdatedAt(value *time.Time) *LabelUpdate {
+	if value != nil {
+		return l.SetUpdatedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilUpdatedAt(value *time.Time) *LabelUpdateOne {
+	if value != nil {
+		return l.SetUpdatedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilUpdatedAt(value *time.Time) *LabelCreate {
+	if value != nil {
+		return l.SetUpdatedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilStatus(value *uint8) *LabelUpdate {
+	if value != nil {
+		return l.SetStatus(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilStatus(value *uint8) *LabelUpdateOne {
+	if value != nil {
+		return l.SetStatus(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilStatus(value *uint8) *LabelCreate {
+	if value != nil {
+		return l.SetStatus(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilDeletedAt(value *time.Time) *LabelUpdate {
+	if value != nil {
+		return l.SetDeletedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilDeletedAt(value *time.Time) *LabelUpdateOne {
+	if value != nil {
+		return l.SetDeletedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilDeletedAt(value *time.Time) *LabelCreate {
+	if value != nil {
+		return l.SetDeletedAt(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilType(value *int) *LabelUpdate {
+	if value != nil {
+		return l.SetType(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilType(value *int) *LabelUpdateOne {
+	if value != nil {
+		return l.SetType(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilType(value *int) *LabelCreate {
+	if value != nil {
+		return l.SetType(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilName(value *string) *LabelUpdate {
+	if value != nil {
+		return l.SetName(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilName(value *string) *LabelUpdateOne {
+	if value != nil {
+		return l.SetName(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilName(value *string) *LabelCreate {
+	if value != nil {
+		return l.SetName(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilFrom(value *int) *LabelUpdate {
+	if value != nil {
+		return l.SetFrom(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilFrom(value *int) *LabelUpdateOne {
+	if value != nil {
+		return l.SetFrom(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilFrom(value *int) *LabelCreate {
+	if value != nil {
+		return l.SetFrom(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilMode(value *int) *LabelUpdate {
+	if value != nil {
+		return l.SetMode(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilMode(value *int) *LabelUpdateOne {
+	if value != nil {
+		return l.SetMode(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilMode(value *int) *LabelCreate {
+	if value != nil {
+		return l.SetMode(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdate) SetNotNilConditions(value *string) *LabelUpdate {
+	if value != nil {
+		return l.SetConditions(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelUpdateOne) SetNotNilConditions(value *string) *LabelUpdateOne {
+	if value != nil {
+		return l.SetConditions(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (l *LabelCreate) SetNotNilConditions(value *string) *LabelCreate {
+	if value != nil {
+		return l.SetConditions(*value)
+	}
+	return l
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdate) SetNotNilUpdatedAt(value *time.Time) *LabelRelationshipUpdate {
+	if value != nil {
+		return lr.SetUpdatedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdateOne) SetNotNilUpdatedAt(value *time.Time) *LabelRelationshipUpdateOne {
+	if value != nil {
+		return lr.SetUpdatedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipCreate) SetNotNilUpdatedAt(value *time.Time) *LabelRelationshipCreate {
+	if value != nil {
+		return lr.SetUpdatedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdate) SetNotNilStatus(value *uint8) *LabelRelationshipUpdate {
+	if value != nil {
+		return lr.SetStatus(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdateOne) SetNotNilStatus(value *uint8) *LabelRelationshipUpdateOne {
+	if value != nil {
+		return lr.SetStatus(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipCreate) SetNotNilStatus(value *uint8) *LabelRelationshipCreate {
+	if value != nil {
+		return lr.SetStatus(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdate) SetNotNilDeletedAt(value *time.Time) *LabelRelationshipUpdate {
+	if value != nil {
+		return lr.SetDeletedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdateOne) SetNotNilDeletedAt(value *time.Time) *LabelRelationshipUpdateOne {
+	if value != nil {
+		return lr.SetDeletedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipCreate) SetNotNilDeletedAt(value *time.Time) *LabelRelationshipCreate {
+	if value != nil {
+		return lr.SetDeletedAt(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdate) SetNotNilLabelID(value *uint64) *LabelRelationshipUpdate {
+	if value != nil {
+		return lr.SetLabelID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdateOne) SetNotNilLabelID(value *uint64) *LabelRelationshipUpdateOne {
+	if value != nil {
+		return lr.SetLabelID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipCreate) SetNotNilLabelID(value *uint64) *LabelRelationshipCreate {
+	if value != nil {
+		return lr.SetLabelID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdate) SetNotNilContactID(value *uint64) *LabelRelationshipUpdate {
+	if value != nil {
+		return lr.SetContactID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipUpdateOne) SetNotNilContactID(value *uint64) *LabelRelationshipUpdateOne {
+	if value != nil {
+		return lr.SetContactID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (lr *LabelRelationshipCreate) SetNotNilContactID(value *uint64) *LabelRelationshipCreate {
+	if value != nil {
+		return lr.SetContactID(*value)
+	}
+	return lr
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdate) SetNotNilWxWxid(value *string) *MessageUpdate {
+	if value != nil {
+		return m.SetWxWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdateOne) SetNotNilWxWxid(value *string) *MessageUpdateOne {
+	if value != nil {
+		return m.SetWxWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageCreate) SetNotNilWxWxid(value *string) *MessageCreate {
+	if value != nil {
+		return m.SetWxWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdate) SetNotNilWxid(value *string) *MessageUpdate {
+	if value != nil {
+		return m.SetWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdateOne) SetNotNilWxid(value *string) *MessageUpdateOne {
+	if value != nil {
+		return m.SetWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageCreate) SetNotNilWxid(value *string) *MessageCreate {
+	if value != nil {
+		return m.SetWxid(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdate) SetNotNilContent(value *string) *MessageUpdate {
+	if value != nil {
+		return m.SetContent(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageUpdateOne) SetNotNilContent(value *string) *MessageUpdateOne {
+	if value != nil {
+		return m.SetContent(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
+func (m *MessageCreate) SetNotNilContent(value *string) *MessageCreate {
+	if value != nil {
+		return m.SetContent(*value)
+	}
+	return m
+}
+
+// set field if value's pointer is not nil.
 func (s *ServerUpdate) SetNotNilUpdatedAt(value *time.Time) *ServerUpdate {
 	if value != nil {
 		return s.SetUpdatedAt(*value)

+ 3 - 1
ent/template/pagination.tmpl

@@ -140,7 +140,9 @@ in the LICENSE file in the root directory of this source tree.
                 Size: pageSize,
             }
 
-            count, err := {{ $r }}.Clone().Count(ctx)
+            query := {{ $r }}.Clone()
+            query.ctx.Fields = nil
+            count, err := query.Count(ctx)
 
             if err != nil {
                 return nil, err

+ 9 - 0
ent/tx.go

@@ -16,6 +16,12 @@ type Tx struct {
 	config
 	// Contact is the client for interacting with the Contact builders.
 	Contact *ContactClient
+	// Label is the client for interacting with the Label builders.
+	Label *LabelClient
+	// LabelRelationship is the client for interacting with the LabelRelationship builders.
+	LabelRelationship *LabelRelationshipClient
+	// Message is the client for interacting with the Message builders.
+	Message *MessageClient
 	// Server is the client for interacting with the Server builders.
 	Server *ServerClient
 	// Wx is the client for interacting with the Wx builders.
@@ -152,6 +158,9 @@ func (tx *Tx) Client() *Client {
 
 func (tx *Tx) init() {
 	tx.Contact = NewContactClient(tx.config)
+	tx.Label = NewLabelClient(tx.config)
+	tx.LabelRelationship = NewLabelRelationshipClient(tx.config)
+	tx.Message = NewMessageClient(tx.config)
 	tx.Server = NewServerClient(tx.config)
 	tx.Wx = NewWxClient(tx.config)
 }

+ 4 - 0
go.sum

@@ -362,6 +362,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
@@ -392,6 +393,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
 github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
 github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
@@ -470,6 +472,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
 github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
 github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
+github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=

+ 4 - 4
internal/handler/Contact/create_contact_handler.go

@@ -1,16 +1,16 @@
-package Contact
+package contact
 
 import (
 	"net/http"
 
 	"github.com/zeromicro/go-zero/rest/httpx"
 
-	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/logic/contact"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 )
 
-// swagger:route post /contact/create Contact CreateContact
+// swagger:route post /contact/create contact CreateContact
 //
 // Create contact information | 创建Contact
 //
@@ -33,7 +33,7 @@ func CreateContactHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 			return
 		}
 
-		l := Contact.NewCreateContactLogic(r.Context(), svcCtx)
+		l := contact.NewCreateContactLogic(r.Context(), svcCtx)
 		resp, err := l.CreateContact(&req)
 		if err != nil {
 			httpx.ErrorCtx(r.Context(), w, err)

+ 4 - 4
internal/handler/Contact/delete_contact_handler.go

@@ -1,16 +1,16 @@
-package Contact
+package contact
 
 import (
 	"net/http"
 
 	"github.com/zeromicro/go-zero/rest/httpx"
 
-	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/logic/contact"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 )
 
-// swagger:route post /contact/delete Contact DeleteContact
+// swagger:route post /contact/delete contact DeleteContact
 //
 // Delete contact information | 删除Contact信息
 //
@@ -33,7 +33,7 @@ func DeleteContactHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 			return
 		}
 
-		l := Contact.NewDeleteContactLogic(r.Context(), svcCtx)
+		l := contact.NewDeleteContactLogic(r.Context(), svcCtx)
 		resp, err := l.DeleteContact(&req)
 		if err != nil {
 			httpx.ErrorCtx(r.Context(), w, err)

+ 4 - 4
internal/handler/Contact/get_contact_by_id_handler.go

@@ -1,16 +1,16 @@
-package Contact
+package contact
 
 import (
 	"net/http"
 
 	"github.com/zeromicro/go-zero/rest/httpx"
 
-	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/logic/contact"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 )
 
-// swagger:route post /contact Contact GetContactById
+// swagger:route post /contact contact GetContactById
 //
 // Get contact by ID | 通过ID获取Contact
 //
@@ -33,7 +33,7 @@ func GetContactByIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 			return
 		}
 
-		l := Contact.NewGetContactByIdLogic(r.Context(), svcCtx)
+		l := contact.NewGetContactByIdLogic(r.Context(), svcCtx)
 		resp, err := l.GetContactById(&req)
 		if err != nil {
 			httpx.ErrorCtx(r.Context(), w, err)

+ 4 - 4
internal/handler/Contact/get_contact_list_handler.go

@@ -1,16 +1,16 @@
-package Contact
+package contact
 
 import (
 	"net/http"
 
 	"github.com/zeromicro/go-zero/rest/httpx"
 
-	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/logic/contact"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 )
 
-// swagger:route post /contact/list Contact GetContactList
+// swagger:route post /contact/list contact GetContactList
 //
 // Get contact list | 获取Contact列表
 //
@@ -33,7 +33,7 @@ func GetContactListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 			return
 		}
 
-		l := Contact.NewGetContactListLogic(r.Context(), svcCtx)
+		l := contact.NewGetContactListLogic(r.Context(), svcCtx)
 		resp, err := l.GetContactList(&req)
 		if err != nil {
 			httpx.ErrorCtx(r.Context(), w, err)

+ 4 - 4
internal/handler/Contact/update_contact_handler.go

@@ -1,16 +1,16 @@
-package Contact
+package contact
 
 import (
 	"net/http"
 
 	"github.com/zeromicro/go-zero/rest/httpx"
 
-	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/logic/contact"
 	"wechat-api/internal/svc"
 	"wechat-api/internal/types"
 )
 
-// swagger:route post /contact/update Contact UpdateContact
+// swagger:route post /contact/update contact UpdateContact
 //
 // Update contact information | 更新Contact
 //
@@ -33,7 +33,7 @@ func UpdateContactHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
 			return
 		}
 
-		l := Contact.NewUpdateContactLogic(r.Context(), svcCtx)
+		l := contact.NewUpdateContactLogic(r.Context(), svcCtx)
 		resp, err := l.UpdateContact(&req)
 		if err != nil {
 			httpx.ErrorCtx(r.Context(), w, err)

+ 44 - 0
internal/handler/label/create_label_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/create label CreateLabel
+//
+// Create label information | 创建Label
+//
+// Create label information | 创建Label
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func CreateLabelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewCreateLabelLogic(r.Context(), svcCtx)
+		resp, err := l.CreateLabel(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/delete_label_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/delete label DeleteLabel
+//
+// Delete label information | 删除Label信息
+//
+// Delete label information | 删除Label信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteLabelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDsReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewDeleteLabelLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteLabel(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/get_label_by_id_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label label GetLabelById
+//
+// Get label by ID | 通过ID获取Label
+//
+// Get label by ID | 通过ID获取Label
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: LabelInfoResp
+
+func GetLabelByIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewGetLabelByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/get_label_contacts_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/contacts label GetLabelContacts
+//
+// Get label contacts | 获取Label联系人
+//
+// Get label contacts | 获取Label联系人
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelListReq
+//
+// Responses:
+//  200: LabelListResp
+
+func GetLabelContactsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelListReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewGetLabelContactsLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelContacts(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/get_label_list_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/list label GetLabelList
+//
+// Get label list | 获取Label列表
+//
+// Get label list | 获取Label列表
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelListReq
+//
+// Responses:
+//  200: LabelListResp
+
+func GetLabelListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelListReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewGetLabelListLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelList(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/get_label_select_list_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/select_list label GetLabelSelectList
+//
+// Get label list | 获取Label列表
+//
+// Get label list | 获取Label列表
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelListReq
+//
+// Responses:
+//  200: LabelListResp
+
+func GetLabelSelectListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelListReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewGetLabelSelectListLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelSelectList(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label/update_label_handler.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label/update label UpdateLabel
+//
+// Update label information | 更新Label
+//
+// Update label information | 更新Label
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func UpdateLabelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label.NewUpdateLabelLogic(r.Context(), svcCtx)
+		resp, err := l.UpdateLabel(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/create_label_relationship_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship/create label_relationship CreateLabelRelationship
+//
+// Create label relationship information | 创建LabelRelationship
+//
+// Create label relationship information | 创建LabelRelationship
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelRelationshipInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func CreateLabelRelationshipHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelRelationshipInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewCreateLabelRelationshipLogic(r.Context(), svcCtx)
+		resp, err := l.CreateLabelRelationship(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/delete_label_relationship_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship/delete label_relationship DeleteLabelRelationship
+//
+// Delete label relationship information | 删除LabelRelationship信息
+//
+// Delete label relationship information | 删除LabelRelationship信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteLabelRelationshipHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDsReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewDeleteLabelRelationshipLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteLabelRelationship(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/get_label_relationship_by_id_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship label_relationship GetLabelRelationshipById
+//
+// Get label relationship by ID | 通过ID获取LabelRelationship
+//
+// Get label relationship by ID | 通过ID获取LabelRelationship
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: LabelRelationshipInfoResp
+
+func GetLabelRelationshipByIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.IDReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewGetLabelRelationshipByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelRelationshipById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/get_label_relationship_list_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship/list label_relationship GetLabelRelationshipList
+//
+// Get label relationship list | 获取LabelRelationship列表
+//
+// Get label relationship list | 获取LabelRelationship列表
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelRelationshipListReq
+//
+// Responses:
+//  200: LabelRelationshipListResp
+
+func GetLabelRelationshipListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelRelationshipListReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewGetLabelRelationshipListLogic(r.Context(), svcCtx)
+		resp, err := l.GetLabelRelationshipList(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/update_label_relationship_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship/update label_relationship UpdateLabelRelationship
+//
+// Update label relationship information | 更新LabelRelationship
+//
+// Update label relationship information | 更新LabelRelationship
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelRelationshipInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func UpdateLabelRelationshipHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelRelationshipInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewUpdateLabelRelationshipLogic(r.Context(), svcCtx)
+		resp, err := l.UpdateLabelRelationship(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/label_relationship/update_label_relationships_handler.go

@@ -0,0 +1,44 @@
+package label_relationship
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/label_relationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /label_relationship/update_contact_labels label_relationship UpdateLabelRelationships
+//
+// Update label relationships information | 批量更新LabelRelationship
+//
+// Update label relationships information | 批量更新LabelRelationship
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: LabelRelationshipsInfo
+//
+// Responses:
+//  200: BaseMsgResp
+
+func UpdateLabelRelationshipsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.LabelRelationshipsInfo
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := label_relationship.NewUpdateLabelRelationshipsLogic(r.Context(), svcCtx)
+		resp, err := l.UpdateLabelRelationships(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 91 - 6
internal/handler/routes.go

@@ -4,12 +4,14 @@ package handler
 import (
 	"net/http"
 
-	Contact "wechat-api/internal/handler/Contact"
 	Message "wechat-api/internal/handler/Message"
 	WechatServer "wechat-api/internal/handler/WechatServer"
 	Wx "wechat-api/internal/handler/Wx"
 	Wxhook "wechat-api/internal/handler/Wxhook"
 	base "wechat-api/internal/handler/base"
+	contact "wechat-api/internal/handler/contact"
+	label "wechat-api/internal/handler/label"
+	label_relationship "wechat-api/internal/handler/label_relationship"
 	"wechat-api/internal/svc"
 
 	"github.com/zeromicro/go-zero/rest"
@@ -140,27 +142,66 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 				{
 					Method:  http.MethodPost,
 					Path:    "/contact/create",
-					Handler: Contact.CreateContactHandler(serverCtx),
+					Handler: contact.CreateContactHandler(serverCtx),
 				},
 				{
 					Method:  http.MethodPost,
 					Path:    "/contact/update",
-					Handler: Contact.UpdateContactHandler(serverCtx),
+					Handler: contact.UpdateContactHandler(serverCtx),
 				},
 				{
 					Method:  http.MethodPost,
 					Path:    "/contact/delete",
-					Handler: Contact.DeleteContactHandler(serverCtx),
+					Handler: contact.DeleteContactHandler(serverCtx),
 				},
 				{
 					Method:  http.MethodPost,
 					Path:    "/contact/list",
-					Handler: Contact.GetContactListHandler(serverCtx),
+					Handler: contact.GetContactListHandler(serverCtx),
 				},
 				{
 					Method:  http.MethodPost,
 					Path:    "/contact",
-					Handler: Contact.GetContactByIdHandler(serverCtx),
+					Handler: contact.GetContactByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship/create",
+					Handler: label_relationship.CreateLabelRelationshipHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship/update",
+					Handler: label_relationship.UpdateLabelRelationshipHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship/update_contact_labels",
+					Handler: label_relationship.UpdateLabelRelationshipsHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship/delete",
+					Handler: label_relationship.DeleteLabelRelationshipHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship/list",
+					Handler: label_relationship.GetLabelRelationshipListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label_relationship",
+					Handler: label_relationship.GetLabelRelationshipByIdHandler(serverCtx),
 				},
 			}...,
 		),
@@ -200,4 +241,48 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 		),
 		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
 	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/create",
+					Handler: label.CreateLabelHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/update",
+					Handler: label.UpdateLabelHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/delete",
+					Handler: label.DeleteLabelHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/list",
+					Handler: label.GetLabelListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/select_list",
+					Handler: label.GetLabelSelectListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label/contacts",
+					Handler: label.GetLabelContactsHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/label",
+					Handler: label.GetLabelByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
 }

+ 1 - 1
internal/logic/Contact/create_contact_logic.go

@@ -1,4 +1,4 @@
-package Contact
+package contact
 
 import (
 	"context"

+ 1 - 1
internal/logic/Contact/delete_contact_logic.go

@@ -1,4 +1,4 @@
-package Contact
+package contact
 
 import (
 	"context"

+ 1 - 1
internal/logic/Contact/get_contact_by_id_logic.go

@@ -1,4 +1,4 @@
-package Contact
+package contact
 
 import (
 	"context"

+ 64 - 26
internal/logic/Contact/get_contact_list_logic.go

@@ -1,7 +1,10 @@
-package Contact
+package contact
 
 import (
 	"context"
+	"wechat-api/ent"
+	"wechat-api/ent/label"
+	"wechat-api/ent/labelrelationship"
 
 	"wechat-api/ent/contact"
 	"wechat-api/ent/predicate"
@@ -9,7 +12,7 @@ import (
 	"wechat-api/internal/types"
 	"wechat-api/internal/utils/dberrorhandler"
 
-    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
 
 	"github.com/suyuan32/simple-admin-common/utils/pointy"
 	"github.com/zeromicro/go-zero/core/logx"
@@ -29,8 +32,31 @@ func NewGetContactListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ge
 	}
 }
 
+func convertLabelToLabelInfo(label *ent.Label) types.LabelInfo {
+	return types.LabelInfo{
+		BaseIDInfo: types.BaseIDInfo{
+			Id:        &label.ID,
+			CreatedAt: pointy.GetPointer(label.CreatedAt.UnixMilli()),
+			UpdatedAt: pointy.GetPointer(label.UpdatedAt.UnixMilli()),
+		},
+		Status:     &label.Status,
+		Type:       &label.Type,
+		Name:       &label.Name,
+		From:       &label.From,
+		Mode:       &label.Mode,
+		Conditions: &label.Conditions,
+	}
+}
+
 func (l *GetContactListLogic) GetContactList(req *types.ContactListReq) (*types.ContactListResp, error) {
 	var predicates []predicate.Contact
+	if len(req.LabelIDs) > 0 {
+		predicates = append(predicates, contact.HasContactRelationshipsWith(
+			labelrelationship.HasLabelsWith(
+				label.IDIn(req.LabelIDs...),
+			),
+		))
+	}
 	if req.WxWxid != nil {
 		predicates = append(predicates, contact.WxWxidContains(*req.WxWxid))
 	}
@@ -40,7 +66,9 @@ func (l *GetContactListLogic) GetContactList(req *types.ContactListReq) (*types.
 	if req.Account != nil {
 		predicates = append(predicates, contact.AccountContains(*req.Account))
 	}
-	data, err := l.svcCtx.DB.Contact.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+	data, err := l.svcCtx.DB.Contact.Query().Where(predicates...).WithContactRelationships(func(query *ent.LabelRelationshipQuery) {
+		query.WithLabels()
+	}).Page(l.ctx, req.Page, req.PageSize)
 
 	if err != nil {
 		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
@@ -51,30 +79,40 @@ func (l *GetContactListLogic) GetContactList(req *types.ContactListReq) (*types.
 	resp.Data.Total = data.PageDetails.Total
 
 	for _, v := range data.List {
+		labelRelationships := make([]types.ContactLabelList, 0)
+		if v.Edges.ContactRelationships != nil {
+			for _, lr := range v.Edges.ContactRelationships {
+				labelRelationships = append(labelRelationships, types.ContactLabelList{
+					Label: &lr.Edges.Labels.Name,
+					Value: &lr.LabelID,
+				})
+			}
+		}
 		resp.Data.Data = append(resp.Data.Data,
-		types.ContactInfo{
-			BaseIDInfo:    types.BaseIDInfo{
-				Id:          &v.ID,
-				CreatedAt:    pointy.GetPointer(v.CreatedAt.UnixMilli()),
-				UpdatedAt:    pointy.GetPointer(v.UpdatedAt.UnixMilli()),
-            },
-			Status:	&v.Status,
-			WxWxid:	&v.WxWxid,
-			Type:	&v.Type,
-			Wxid:	&v.Wxid,
-			Account:	&v.Account,
-			Nickname:	&v.Nickname,
-			Markname:	&v.Markname,
-			Headimg:	&v.Headimg,
-			Sex:	&v.Sex,
-			Starrole:	&v.Starrole,
-			Dontseeit:	&v.Dontseeit,
-			Dontseeme:	&v.Dontseeme,
-			Lag:	&v.Lag,
-			Gid:	&v.Gid,
-			Gname:	&v.Gname,
-			V3:	&v.V3,
-		})
+			types.ContactInfo{
+				BaseIDInfo: types.BaseIDInfo{
+					Id:        &v.ID,
+					CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
+					UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+				},
+				Status:             &v.Status,
+				WxWxid:             &v.WxWxid,
+				Type:               &v.Type,
+				Wxid:               &v.Wxid,
+				Account:            &v.Account,
+				Nickname:           &v.Nickname,
+				Markname:           &v.Markname,
+				Headimg:            &v.Headimg,
+				Sex:                &v.Sex,
+				Starrole:           &v.Starrole,
+				Dontseeit:          &v.Dontseeit,
+				Dontseeme:          &v.Dontseeme,
+				Lag:                &v.Lag,
+				Gid:                &v.Gid,
+				Gname:              &v.Gname,
+				V3:                 &v.V3,
+				LabelRelationships: labelRelationships,
+			})
 	}
 
 	return resp, nil

+ 1 - 1
internal/logic/Contact/update_contact_logic.go

@@ -1,4 +1,4 @@
-package Contact
+package contact
 
 import (
 	"context"

+ 124 - 0
internal/logic/base/init_api_data.go

@@ -6,6 +6,130 @@ import (
 )
 
 func (l *InitDatabaseLogic) insertApiData() (err error) {
+	// LabelRelationship
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label_relationship/create"),
+		Description: pointy.GetPointer("apiDesc.createLabelRelationship"),
+		ApiGroup:    pointy.GetPointer("label_relationship"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label_relationship/update"),
+		Description: pointy.GetPointer("apiDesc.updateLabelRelationship"),
+		ApiGroup:    pointy.GetPointer("label_relationship"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label_relationship/delete"),
+		Description: pointy.GetPointer("apiDesc.deleteLabelRelationship"),
+		ApiGroup:    pointy.GetPointer("label_relationship"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label_relationship/list"),
+		Description: pointy.GetPointer("apiDesc.getLabelRelationshipList"),
+		ApiGroup:    pointy.GetPointer("label_relationship"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label_relationship"),
+		Description: pointy.GetPointer("apiDesc.getLabelRelationshipById"),
+		ApiGroup:    pointy.GetPointer("label_relationship"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	// Label
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label/create"),
+		Description: pointy.GetPointer("apiDesc.createLabel"),
+		ApiGroup:    pointy.GetPointer("label"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label/update"),
+		Description: pointy.GetPointer("apiDesc.updateLabel"),
+		ApiGroup:    pointy.GetPointer("label"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label/delete"),
+		Description: pointy.GetPointer("apiDesc.deleteLabel"),
+		ApiGroup:    pointy.GetPointer("label"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label/list"),
+		Description: pointy.GetPointer("apiDesc.getLabelList"),
+		ApiGroup:    pointy.GetPointer("label"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
+	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{
+		ServiceName: pointy.GetPointer("Wechat"),
+		Path:        pointy.GetPointer("/label"),
+		Description: pointy.GetPointer("apiDesc.getLabelById"),
+		ApiGroup:    pointy.GetPointer("label"),
+		Method:      pointy.GetPointer("POST"),
+	})
+
+	if err != nil {
+		return err
+	}
+
 	// Contact
 
 	_, err = l.svcCtx.CoreRpc.CreateApi(l.ctx, &core.ApiInfo{

+ 44 - 0
internal/logic/label/create_label_logic.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type CreateLabelLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateLabelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLabelLogic {
+	return &CreateLabelLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateLabelLogic) CreateLabel(req *types.LabelInfo) (*types.BaseMsgResp, error) {
+    _, err := l.svcCtx.DB.Label.Create().
+			SetNotNilStatus(req.Status).
+			SetNotNilType(req.Type).
+			SetNotNilName(req.Name).
+			SetNotNilFrom(req.From).
+			SetNotNilMode(req.Mode).
+			SetNotNilConditions(req.Conditions).
+			Save(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.CreateSuccess}, nil
+}

+ 37 - 0
internal/logic/label/delete_label_logic.go

@@ -0,0 +1,37 @@
+package label
+
+import (
+	"context"
+
+    "wechat-api/ent/label"
+    "wechat-api/internal/svc"
+    "wechat-api/internal/types"
+    "wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+    "github.com/zeromicro/go-zero/core/logx"
+)
+
+type DeleteLabelLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteLabelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteLabelLogic {
+	return &DeleteLabelLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteLabelLogic) DeleteLabel(req *types.IDsReq) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.Label.Delete().Where(label.IDIn(req.Ids...)).Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 56 - 0
internal/logic/label/get_label_by_id_logic.go

@@ -0,0 +1,56 @@
+package label
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetLabelByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelByIdLogic {
+	return &GetLabelByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetLabelByIdLogic) GetLabelById(req *types.IDReq) (*types.LabelInfoResp, error) {
+	data, err := l.svcCtx.DB.Label.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.LabelInfoResp{
+	    BaseDataInfo: types.BaseDataInfo{
+            Code: 0,
+            Msg:  errormsg.Success,
+        },
+        Data: types.LabelInfo{
+            BaseIDInfo:    types.BaseIDInfo{
+				Id:          &data.ID,
+				CreatedAt:    pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+            },
+			Status:	&data.Status,
+			Type:	&data.Type,
+			Name:	&data.Name,
+			From:	&data.From,
+			Mode:	&data.Mode,
+			Conditions:	&data.Conditions,
+        },
+	}, nil
+}
+

+ 100 - 0
internal/logic/label/get_label_contacts_logic.go

@@ -0,0 +1,100 @@
+package label
+
+import (
+	"context"
+	"errors"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
+	"wechat-api/ent"
+	"wechat-api/ent/label"
+	"wechat-api/ent/predicate"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelContactsLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewGetLabelContactsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelContactsLogic {
+	return &GetLabelContactsLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *GetLabelContactsLogic) GetLabelContacts(req *types.LabelListReq) (*types.LabelListResp, error) {
+	if len(req.LabelIDs) == 0 {
+		return nil, errors.New("label id list cannot be empty")
+	}
+	var predicates []predicate.Label
+	if len(req.LabelIDs) > 0 {
+		predicates = append(predicates, label.IDIn(req.LabelIDs...))
+	}
+	if req.Type != nil {
+		predicates = append(predicates, label.TypeEQ(*req.Type))
+	}
+	if req.Name != nil {
+		predicates = append(predicates, label.NameContains(*req.Name))
+	}
+	if req.From != nil {
+		predicates = append(predicates, label.FromEQ(*req.From))
+	}
+	if req.Mode != nil {
+		predicates = append(predicates, label.ModeEQ(*req.Mode))
+	}
+
+	data, err := l.svcCtx.DB.Label.Query().Where(predicates...).WithLabelRelationships(func(query *ent.LabelRelationshipQuery) {
+		query.WithContacts()
+	}).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.LabelListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		labelRelationships := make([]types.LabelRelationshipInfo, 0)
+		if v.Edges.LabelRelationships != nil {
+			for _, lr := range v.Edges.LabelRelationships {
+				labelRelationships = append(labelRelationships, types.LabelRelationshipInfo{
+					BaseIDInfo: types.BaseIDInfo{
+						Id:        &lr.ID,
+						CreatedAt: pointy.GetPointer(lr.CreatedAt.UnixMilli()),
+						UpdatedAt: pointy.GetPointer(lr.UpdatedAt.UnixMilli()),
+					},
+					Status:    &lr.Status,
+					LabelId:   &lr.LabelID,
+					ContactId: &lr.ContactID,
+					Contact:   convertContactToContactInfo(lr.Edges.Contacts),
+				})
+			}
+		}
+		resp.Data.Data = append(resp.Data.Data,
+			types.LabelInfo{
+				BaseIDInfo: types.BaseIDInfo{
+					Id:        &v.ID,
+					CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
+					UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+				},
+				Status:             &v.Status,
+				Type:               &v.Type,
+				Name:               &v.Name,
+				From:               &v.From,
+				Mode:               &v.Mode,
+				Conditions:         &v.Conditions,
+				LabelRelationships: labelRelationships,
+			})
+	}
+
+	return resp, nil
+}

+ 101 - 0
internal/logic/label/get_label_list_logic.go

@@ -0,0 +1,101 @@
+package label
+
+import (
+	"context"
+	"wechat-api/ent"
+
+	"wechat-api/ent/label"
+	"wechat-api/ent/predicate"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetLabelListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelListLogic {
+	return &GetLabelListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func convertContactToContactInfo(label *ent.Contact) types.ContactInfo {
+	return types.ContactInfo{
+		BaseIDInfo: types.BaseIDInfo{
+			Id:        &label.ID,
+			CreatedAt: pointy.GetPointer(label.CreatedAt.UnixMilli()),
+			UpdatedAt: pointy.GetPointer(label.UpdatedAt.UnixMilli()),
+		},
+		Status:    &label.Status,
+		WxWxid:    &label.WxWxid,
+		Type:      &label.Type,
+		Wxid:      &label.Wxid,
+		Account:   &label.Account,
+		Nickname:  &label.Nickname,
+		Markname:  &label.Markname,
+		Headimg:   &label.Headimg,
+		Sex:       &label.Sex,
+		Starrole:  &label.Starrole,
+		Dontseeit: &label.Dontseeit,
+		Dontseeme: &label.Dontseeme,
+		Lag:       &label.Lag,
+		Gid:       &label.Gid,
+		Gname:     &label.Gname,
+		V3:        &label.V3,
+	}
+}
+
+func (l *GetLabelListLogic) GetLabelList(req *types.LabelListReq) (*types.LabelListResp, error) {
+	var predicates []predicate.Label
+	if req.Type != nil {
+		predicates = append(predicates, label.TypeEQ(*req.Type))
+	}
+	if req.Name != nil {
+		predicates = append(predicates, label.NameContains(*req.Name))
+	}
+	if req.From != nil {
+		predicates = append(predicates, label.FromEQ(*req.From))
+	}
+	if req.Mode != nil {
+		predicates = append(predicates, label.ModeEQ(*req.Mode))
+	}
+	data, err := l.svcCtx.DB.Label.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.LabelListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		resp.Data.Data = append(resp.Data.Data,
+			types.LabelInfo{
+				BaseIDInfo: types.BaseIDInfo{
+					Id:        &v.ID,
+					CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
+					UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+				},
+				Status:     &v.Status,
+				Type:       &v.Type,
+				Name:       &v.Name,
+				From:       &v.From,
+				Mode:       &v.Mode,
+				Conditions: &v.Conditions,
+			})
+	}
+
+	return resp, nil
+}

+ 61 - 0
internal/logic/label/get_label_select_list_logic.go

@@ -0,0 +1,61 @@
+package label
+
+import (
+	"context"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/ent/label"
+	"wechat-api/ent/predicate"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelSelectListLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewGetLabelSelectListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelSelectListLogic {
+	return &GetLabelSelectListLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *GetLabelSelectListLogic) GetLabelSelectList(req *types.LabelListReq) (*types.LabelSelectListResp, error) {
+	var predicates []predicate.Label
+	if req.Type != nil {
+		predicates = append(predicates, label.TypeEQ(*req.Type))
+	}
+	if req.Name != nil {
+		predicates = append(predicates, label.NameContains(*req.Name))
+	}
+	if req.From != nil {
+		predicates = append(predicates, label.FromEQ(*req.From))
+	}
+	if req.Mode != nil {
+		predicates = append(predicates, label.ModeEQ(*req.Mode))
+	}
+	data, err := l.svcCtx.DB.Label.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.LabelSelectListResp{}
+	resp.Msg = errormsg.Success
+
+	for _, v := range data.List {
+		resp.Data = append(resp.Data,
+			types.LabelSelectListInfo{
+				Value: &v.ID,
+				Label: &v.Name,
+			})
+	}
+
+	return resp, nil
+}

+ 44 - 0
internal/logic/label/update_label_logic.go

@@ -0,0 +1,44 @@
+package label
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type UpdateLabelLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateLabelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLabelLogic {
+	return &UpdateLabelLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateLabelLogic) UpdateLabel(req *types.LabelInfo) (*types.BaseMsgResp, error) {
+    err := l.svcCtx.DB.Label.UpdateOneID(*req.Id).
+			SetNotNilStatus(req.Status).
+			SetNotNilType(req.Type).
+			SetNotNilName(req.Name).
+			SetNotNilFrom(req.From).
+			SetNotNilMode(req.Mode).
+			SetNotNilConditions(req.Conditions).
+			Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 41 - 0
internal/logic/label_relationship/create_label_relationship_logic.go

@@ -0,0 +1,41 @@
+package label_relationship
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type CreateLabelRelationshipLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateLabelRelationshipLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLabelRelationshipLogic {
+	return &CreateLabelRelationshipLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateLabelRelationshipLogic) CreateLabelRelationship(req *types.LabelRelationshipInfo) (*types.BaseMsgResp, error) {
+    _, err := l.svcCtx.DB.LabelRelationship.Create().
+			SetNotNilStatus(req.Status).
+			SetNotNilLabelID(req.LabelId).
+			SetNotNilContactID(req.ContactId).
+			Save(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.CreateSuccess}, nil
+}

+ 37 - 0
internal/logic/label_relationship/delete_label_relationship_logic.go

@@ -0,0 +1,37 @@
+package label_relationship
+
+import (
+	"context"
+
+    "wechat-api/ent/labelrelationship"
+    "wechat-api/internal/svc"
+    "wechat-api/internal/types"
+    "wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+    "github.com/zeromicro/go-zero/core/logx"
+)
+
+type DeleteLabelRelationshipLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteLabelRelationshipLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteLabelRelationshipLogic {
+	return &DeleteLabelRelationshipLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteLabelRelationshipLogic) DeleteLabelRelationship(req *types.IDsReq) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.LabelRelationship.Delete().Where(labelrelationship.IDIn(req.Ids...)).Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 53 - 0
internal/logic/label_relationship/get_label_relationship_by_id_logic.go

@@ -0,0 +1,53 @@
+package label_relationship
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+    "github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelRelationshipByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetLabelRelationshipByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelRelationshipByIdLogic {
+	return &GetLabelRelationshipByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetLabelRelationshipByIdLogic) GetLabelRelationshipById(req *types.IDReq) (*types.LabelRelationshipInfoResp, error) {
+	data, err := l.svcCtx.DB.LabelRelationship.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.LabelRelationshipInfoResp{
+	    BaseDataInfo: types.BaseDataInfo{
+            Code: 0,
+            Msg:  errormsg.Success,
+        },
+        Data: types.LabelRelationshipInfo{
+            BaseIDInfo:    types.BaseIDInfo{
+				Id:          &data.ID,
+				CreatedAt:    pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+            },
+			Status:	&data.Status,
+			LabelId:	&data.LabelID,
+			ContactId:	&data.ContactID,
+        },
+	}, nil
+}
+

+ 58 - 0
internal/logic/label_relationship/get_label_relationship_list_logic.go

@@ -0,0 +1,58 @@
+package label_relationship
+
+import (
+	"context"
+
+	"wechat-api/ent/predicate"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+
+	"github.com/suyuan32/simple-admin-common/utils/pointy"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetLabelRelationshipListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetLabelRelationshipListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLabelRelationshipListLogic {
+	return &GetLabelRelationshipListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetLabelRelationshipListLogic) GetLabelRelationshipList(req *types.LabelRelationshipListReq) (*types.LabelRelationshipListResp, error) {
+	var predicates []predicate.LabelRelationship
+	data, err := l.svcCtx.DB.LabelRelationship.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.LabelRelationshipListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		resp.Data.Data = append(resp.Data.Data,
+			types.LabelRelationshipInfo{
+				BaseIDInfo: types.BaseIDInfo{
+					Id:        &v.ID,
+					CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
+					UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+				},
+				Status:    &v.Status,
+				LabelId:   &v.LabelID,
+				ContactId: &v.ContactID,
+			})
+	}
+
+	return resp, nil
+}

+ 41 - 0
internal/logic/label_relationship/update_label_relationship_logic.go

@@ -0,0 +1,41 @@
+package label_relationship
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type UpdateLabelRelationshipLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateLabelRelationshipLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLabelRelationshipLogic {
+	return &UpdateLabelRelationshipLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateLabelRelationshipLogic) UpdateLabelRelationship(req *types.LabelRelationshipInfo) (*types.BaseMsgResp, error) {
+    err := l.svcCtx.DB.LabelRelationship.UpdateOneID(*req.Id).
+			SetNotNilStatus(req.Status).
+			SetNotNilLabelID(req.LabelId).
+			SetNotNilContactID(req.ContactId).
+			Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 103 - 0
internal/logic/label_relationship/update_label_relationships_logic.go

@@ -0,0 +1,103 @@
+package label_relationship
+
+import (
+	"context"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/ent/labelrelationship"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type UpdateLabelRelationshipsLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewUpdateLabelRelationshipsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLabelRelationshipsLogic {
+	return &UpdateLabelRelationshipsLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *UpdateLabelRelationshipsLogic) UpdateLabelRelationships(req *types.LabelRelationshipsInfo) (resp *types.BaseMsgResp, err error) {
+	l.Logger.Info("Start processing UpdateLabelRelationships request", "request", req)
+	defer func() {
+		if err != nil {
+			l.Logger.Error("Error occurred in UpdateLabelRelationships", "error", err)
+		} else {
+			l.Logger.Info("Successfully processed UpdateLabelRelationships request")
+		}
+	}()
+	// 获取联系人当前已关联的标签
+	currentLabelRelationships, err := l.svcCtx.DB.LabelRelationship.Query().Where(labelrelationship.ContactID(*req.ContactId)).All(l.ctx)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	// 提取当前标签ID
+	var currentLabelIds []uint64
+	for _, relationship := range currentLabelRelationships {
+		currentLabelIds = append(currentLabelIds, relationship.LabelID)
+	}
+
+	// 对比新旧标签ID,找出需要新增和移除的标签
+	addLabelIds, removeLabelIds := compareLabelIds(req.LabelIds, currentLabelIds)
+
+	// 删除需要移除的标签关系
+	for _, id := range removeLabelIds {
+		_, err := l.svcCtx.DB.LabelRelationship.
+			Delete().
+			Where(
+				labelrelationship.ContactID(*req.ContactId),
+				labelrelationship.LabelID(id),
+			).
+			Exec(l.ctx)
+		if err != nil {
+			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+		}
+	}
+
+	// 创建需要新增的标签关系
+	for _, id := range addLabelIds {
+		_, err := l.svcCtx.DB.LabelRelationship.Create().
+			SetLabelID(id).
+			SetContactID(*req.ContactId).
+			SetStatus(*req.Status).
+			Save(l.ctx)
+		if err != nil {
+			return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+		}
+	}
+
+	return &types.BaseMsgResp{
+		Code: 0,
+		Msg:  errormsg.Success,
+	}, nil
+}
+
+// compareLabelIds compares the new label ids with the current ones and returns the ids to be added and removed
+func compareLabelIds(newLabelIds []uint64, currentLabelIds []uint64) (addLabelIds []uint64, removeLabelIds []uint64) {
+	newLabelIdSet := make(map[uint64]struct{}, len(newLabelIds))
+	for _, id := range newLabelIds {
+		newLabelIdSet[id] = struct{}{}
+	}
+
+	for _, id := range currentLabelIds {
+		if _, ok := newLabelIdSet[id]; ok {
+			delete(newLabelIdSet, id)
+		} else {
+			removeLabelIds = append(removeLabelIds, id)
+		}
+	}
+
+	for id := range newLabelIdSet {
+		addLabelIds = append(addLabelIds, id)
+	}
+
+	return
+}

+ 170 - 24
internal/types/types.go

@@ -397,6 +397,52 @@ type SendPicMsgLocalReq struct {
 	Picpath *string `json:"picpath"`
 }
 
+// The response data of contact list | Contact列表数据
+// swagger:model ContactListResp
+type ContactListResp struct {
+	BaseDataInfo
+	// Contact list data | Contact列表数据
+	Data ContactListInfo `json:"data"`
+}
+
+// Contact list data | Contact列表数据
+// swagger:model ContactListInfo
+type ContactListInfo struct {
+	BaseListInfo
+	// The API list data | Contact列表数据
+	Data []ContactInfo `json:"data"`
+}
+
+// Get contact list request params | Contact列表请求参数
+// swagger:model ContactListReq
+type ContactListReq struct {
+	PageInfo
+	// Label ID list | 标签ID列表
+	LabelIDs []uint64 `json:"labelIDs,optional"`
+	// 属主微信id
+	WxWxid *string `json:"wxWxid,optional"`
+	// 微信id 公众号微信ID
+	Wxid *string `json:"wxid,optional"`
+	// 微信账号
+	Account *string `json:"account,optional"`
+}
+
+// Contact information response | Contact信息返回体
+// swagger:model ContactInfoResp
+type ContactInfoResp struct {
+	BaseDataInfo
+	// Contact information | Contact数据
+	Data ContactInfo `json:"data"`
+}
+
+// ContactLabelList | Contact标签列表
+type ContactLabelList struct {
+	// label
+	Label *string `json:"label,optional"`
+	// value
+	Value *uint64 `json:"value,optional"`
+}
+
 // The response data of contact information | Contact信息
 // swagger:model ContactInfo
 type ContactInfo struct {
@@ -433,42 +479,86 @@ type ContactInfo struct {
 	Gname *string `json:"gname,optional"`
 	// v3数据
 	V3 *string `json:"v3,optional"`
+	// Label Relationships | 标签关系
+	LabelRelationships []ContactLabelList `json:"labelRelationships,optional"`
 }
 
-// The response data of contact list | Contact列表数据
-// swagger:model ContactListResp
-type ContactListResp struct {
+// The response data of label information | Label信息
+// swagger:model LabelInfo
+type LabelInfo struct {
+	BaseIDInfo
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status *uint8 `json:"status,optional"`
+	// 标签类型:1好友,2群组,3公众号,4企业微信联系人
+	Type *int `json:"type,optional"`
+	// 标签名称
+	Name *string `json:"name,optional"`
+	// 标签来源:1后台创建 2个微同步
+	From *int `json:"from,optional"`
+	// 标签模式:1动态 2静态
+	Mode *int `json:"mode,optional"`
+	// 标签的触达条件
+	Conditions *string `json:"conditions,optional"`
+	// Label Relationships | 标签关系
+	LabelRelationships []LabelRelationshipInfo `json:"labelRelationships,optional"`
+}
+
+// The response data of label relationship information | LabelRelationship信息
+// swagger:model LabelRelationshipInfo
+type LabelRelationshipInfo struct {
+	BaseIDInfo
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status *uint8 `json:"status,optional"`
+	// 标签 ID
+	LabelId *uint64 `json:"labelId,optional"`
+	// 联系人 ID
+	ContactId *uint64 `json:"contactId,optional"`
+	// Contact information | 联系人信息
+	Contact ContactInfo `json:"contact,optional"`
+	// Label information | 标签信息
+	Label LabelInfo `json:"label,optional"`
+}
+
+// The response data of label relationship information | LabelRelationship信息
+// swagger:model LabelRelationshipsInfo
+type LabelRelationshipsInfo struct {
+	BaseIDInfo
+	// Status 1: normal 2: ban | 状态 1 正常 2 禁用
+	Status *uint8 `json:"status,optional"`
+	// 标签 ID
+	LabelIds []uint64 `json:"labelIds,optional"`
+	// 联系人 ID
+	ContactId *uint64 `json:"contactId,optional"`
+}
+
+// The response data of label relationship list | LabelRelationship列表数据
+// swagger:model LabelRelationshipListResp
+type LabelRelationshipListResp struct {
 	BaseDataInfo
-	// Contact list data | Contact列表数据
-	Data ContactListInfo `json:"data"`
+	// LabelRelationship list data | LabelRelationship列表数据
+	Data LabelRelationshipListInfo `json:"data"`
 }
 
-// Contact list data | Contact列表数据
-// swagger:model ContactListInfo
-type ContactListInfo struct {
+// LabelRelationship list data | LabelRelationship列表数据
+// swagger:model LabelRelationshipListInfo
+type LabelRelationshipListInfo struct {
 	BaseListInfo
-	// The API list data | Contact列表数据
-	Data []ContactInfo `json:"data"`
+	// The API list data | LabelRelationship列表数据
+	Data []LabelRelationshipInfo `json:"data"`
 }
 
-// Get contact list request params | Contact列表请求参数
-// swagger:model ContactListReq
-type ContactListReq struct {
+// Get label relationship list request params | LabelRelationship列表请求参数
+// swagger:model LabelRelationshipListReq
+type LabelRelationshipListReq struct {
 	PageInfo
-	// 属主微信id
-	WxWxid *string `json:"wxWxid,optional"`
-	// 微信id 公众号微信ID
-	Wxid *string `json:"wxid,optional"`
-	// 微信账号
-	Account *string `json:"account,optional"`
 }
 
-// Contact information response | Contact信息返回体
-// swagger:model ContactInfoResp
-type ContactInfoResp struct {
+// LabelRelationship information response | LabelRelationship信息返回体
+// swagger:model LabelRelationshipInfoResp
+type LabelRelationshipInfoResp struct {
 	BaseDataInfo
-	// Contact information | Contact数据
-	Data ContactInfo `json:"data"`
+	// LabelRelationship information | LabelRelationship数据
+	Data LabelRelationshipInfo `json:"data"`
 }
 
 // The response data of message information | Message信息
@@ -516,3 +606,59 @@ type MessageInfoResp struct {
 	// Message information | Message数据
 	Data MessageInfo `json:"data"`
 }
+
+// The response data of label list | Label列表数据
+// swagger:model LabelSelectListResp
+type LabelSelectListResp struct {
+	BaseDataInfo
+	// Label list data | Label列表数据
+	Data []LabelSelectListInfo `json:"data"`
+}
+
+// The response data of label list | Label列表数据
+// swagger:model LabelListResp
+type LabelListResp struct {
+	BaseDataInfo
+	// Label list data | Label列表数据
+	Data LabelListInfo `json:"data"`
+}
+
+// Label list data | Label列表数据
+// swagger:model LabelListInfo
+type LabelListInfo struct {
+	BaseListInfo
+	// The API list data | Label列表数据
+	Data []LabelInfo `json:"data"`
+}
+
+// Get label list request params | Label列表请求参数
+// swagger:model LabelListReq
+type LabelListReq struct {
+	PageInfo
+	// Label ID list | Label ID列表
+	LabelIDs []uint64 `json:"labelIDs,optional"`
+	// 标签类型:1好友,2群组,3公众号,4企业微信联系人
+	Type *int `json:"type,optional"`
+	// 标签名称
+	Name *string `json:"name,optional"`
+	// 标签来源:1后台创建 2个微同步
+	From *int `json:"from,optional"`
+	// 标签模式:1动态 2静态
+	Mode *int `json:"mode,optional"`
+}
+
+// Label information response | Label信息返回体
+// swagger:model LabelInfoResp
+type LabelInfoResp struct {
+	BaseDataInfo
+	// Label information | Label数据
+	Data LabelInfo `json:"data"`
+}
+
+// swagger:model LabelSelectListInfo
+type LabelSelectListInfo struct {
+	// label
+	Label *string `json:"label,optional"`
+	// value
+	Value *uint64 `json:"value,optional"`
+}