rowan.wu преди 11 месеца
ревизия
60b5259734
променени са 100 файла, в които са добавени 24621 реда и са изтрити 0 реда
  1. 32 0
      .gitignore
  2. 21 0
      Dockerfile
  3. 117 0
      Makefile
  4. 5 0
      desc/all.api
  5. 218 0
      desc/base.api
  6. 122 0
      desc/wechat/contact.api
  7. 89 0
      desc/wechat/server.api
  8. 104 0
      desc/wechat/wx.api
  9. 54 0
      desc/wechat/wxhook.api
  10. 692 0
      ent/client.go
  11. 304 0
      ent/contact.go
  12. 242 0
      ent/contact/contact.go
  13. 1240 0
      ent/contact/where.go
  14. 1812 0
      ent/contact_create.go
  15. 88 0
      ent/contact_delete.go
  16. 526 0
      ent/contact_query.go
  17. 974 0
      ent/contact_update.go
  18. 612 0
      ent/ent.go
  19. 84 0
      ent/enttest/enttest.go
  20. 3 0
      ent/generate.go
  21. 222 0
      ent/hook/hook.go
  22. 209 0
      ent/intercept/intercept.go
  23. 64 0
      ent/migrate/migrate.go
  24. 175 0
      ent/migrate/schema.go
  25. 3597 0
      ent/mutation.go
  26. 294 0
      ent/pagination.go
  27. 16 0
      ent/predicate/predicate.go
  28. 5 0
      ent/runtime.go
  29. 193 0
      ent/runtime/runtime.go
  30. 89 0
      ent/schema/contact.go
  31. 90 0
      ent/schema/localmixin/soft_delete.go
  32. 58 0
      ent/schema/server.go
  33. 77 0
      ent/schema/wx.go
  34. 209 0
      ent/server.go
  35. 155 0
      ent/server/server.go
  36. 574 0
      ent/server/where.go
  37. 967 0
      ent/server_create.go
  38. 88 0
      ent/server_delete.go
  39. 605 0
      ent/server_query.go
  40. 647 0
      ent/server_update.go
  41. 893 0
      ent/set_not_nil.go
  42. 168 0
      ent/template/pagination.tmpl
  43. 32 0
      ent/template/set_not_nil.tmpl
  44. 242 0
      ent/tx.go
  45. 267 0
      ent/wx.go
  46. 889 0
      ent/wx/where.go
  47. 206 0
      ent/wx/wx.go
  48. 1344 0
      ent/wx_create.go
  49. 88 0
      ent/wx_delete.go
  50. 605 0
      ent/wx_query.go
  51. 741 0
      ent/wx_update.go
  52. 64 0
      etc/wechat.yaml
  53. 143 0
      go.mod
  54. 837 0
      go.sum
  55. 18 0
      hook/contact.go
  56. 43 0
      hook/init.go
  57. 19 0
      hook/message.go
  58. 114 0
      hook/sys.go
  59. 107 0
      hook/type.go
  60. 16 0
      hook/user.go
  61. 19 0
      internal/config/config.go
  62. 44 0
      internal/handler/Contact/create_contact_handler.go
  63. 44 0
      internal/handler/Contact/delete_contact_handler.go
  64. 44 0
      internal/handler/Contact/get_contact_by_id_handler.go
  65. 44 0
      internal/handler/Contact/get_contact_list_handler.go
  66. 44 0
      internal/handler/Contact/update_contact_handler.go
  67. 44 0
      internal/handler/WechatServer/create_server_handler.go
  68. 44 0
      internal/handler/WechatServer/delete_server_handler.go
  69. 44 0
      internal/handler/WechatServer/get_server_by_id_handler.go
  70. 44 0
      internal/handler/WechatServer/get_server_list_handler.go
  71. 44 0
      internal/handler/WechatServer/update_server_handler.go
  72. 44 0
      internal/handler/Wx/create_wx_handler.go
  73. 44 0
      internal/handler/Wx/delete_wx_handler.go
  74. 44 0
      internal/handler/Wx/get_wx_by_id_handler.go
  75. 44 0
      internal/handler/Wx/get_wx_list_handler.go
  76. 44 0
      internal/handler/Wx/refresh_login_q_r_handler.go
  77. 44 0
      internal/handler/Wx/update_wx_handler.go
  78. 44 0
      internal/handler/Wxhook/get_friends_and_groups_handler.go
  79. 44 0
      internal/handler/Wxhook/logout_handler.go
  80. 44 0
      internal/handler/Wxhook/refresh_login_q_r_handler.go
  81. 31 0
      internal/handler/base/init_database_handler.go
  82. 153 0
      internal/handler/routes.go
  83. 54 0
      internal/logic/Contact/create_contact_logic.go
  84. 37 0
      internal/logic/Contact/delete_contact_logic.go
  85. 66 0
      internal/logic/Contact/get_contact_by_id_logic.go
  86. 81 0
      internal/logic/Contact/get_contact_list_logic.go
  87. 54 0
      internal/logic/Contact/update_contact_logic.go
  88. 43 0
      internal/logic/WechatServer/create_server_logic.go
  89. 37 0
      internal/logic/WechatServer/delete_server_logic.go
  90. 54 0
      internal/logic/WechatServer/get_server_by_id_logic.go
  91. 70 0
      internal/logic/WechatServer/get_server_list_logic.go
  92. 42 0
      internal/logic/WechatServer/update_server_logic.go
  93. 111 0
      internal/logic/Wx/create_wx_logic.go
  94. 38 0
      internal/logic/Wx/delete_wx_logic.go
  95. 60 0
      internal/logic/Wx/get_wx_by_id_logic.go
  96. 75 0
      internal/logic/Wx/get_wx_list_logic.go
  97. 29 0
      internal/logic/Wx/refresh_login_q_r_logic.go
  98. 48 0
      internal/logic/Wx/update_wx_logic.go
  99. 115 0
      internal/logic/Wxhook/get_friends_and_groups_logic.go
  100. 59 0
      internal/logic/Wxhook/logout_logic.go

+ 32 - 0
.gitignore

@@ -0,0 +1,32 @@
+### Go template
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+*.gz
+*.rar
+*.tmp
+
+# Other files and folders
+.settings/
+.idea/
+.vscode/
+
+# config file avoid exposing private data
+*_dev.yaml
+
+# Build files
+*_api
+*_rpc

+ 21 - 0
Dockerfile

@@ -0,0 +1,21 @@
+FROM alpine:3.19
+
+# Define the project name | 定义项目名称
+ARG PROJECT=wechat
+# Define the config file name | 定义配置文件名
+ARG CONFIG_FILE=wechat.yaml
+# Define the author | 定义作者
+ARG AUTHOR="example@example.com"
+
+LABEL org.opencontainers.image.authors=${AUTHOR}
+
+WORKDIR /app
+ENV PROJECT=${PROJECT}
+ENV CONFIG_FILE=${CONFIG_FILE}
+
+COPY ./${PROJECT}_api ./
+COPY ./etc/${CONFIG_FILE} ./etc/
+
+EXPOSE 19101
+
+ENTRYPOINT ./${PROJECT}_api -f etc/${CONFIG_FILE}

+ 117 - 0
Makefile

@@ -0,0 +1,117 @@
+# Custom configuration | 独立配置
+# Service name | 项目名称
+SERVICE=Wechat
+# Service name in specific style | 项目经过style格式化的名称
+SERVICE_STYLE=wechat
+# Service name in lowercase | 项目名称全小写格式
+SERVICE_LOWER=wechat
+# Service name in snake format | 项目名称下划线格式
+SERVICE_SNAKE=wechat
+# Service name in snake format | 项目名称短杠格式
+SERVICE_DASH=wechat
+
+# The project version, if you don't use git, you should set it manually | 项目版本,如果不使用git请手动设置
+VERSION=$(shell git describe --tags --always)
+
+# The project file name style | 项目文件命名风格
+PROJECT_STYLE=go_zero
+
+# Whether to use i18n | 是否启用 i18n
+PROJECT_I18N=false
+
+# The suffix after build or compile | 构建后缀
+PROJECT_BUILD_SUFFIX=api
+
+# Swagger type, support yml,json | Swagger 文件类型,支持yml,json
+SWAGGER_TYPE=json
+
+# Ent enabled features | Ent 启用的官方特性
+ENT_FEATURE=sql/execquery,sql/upsert,intercept
+
+# Auto generate API data for initialization | 自动生成 API 初始化数据
+AUTO_API_INIT_DATA=true
+
+# The arch of the build | 构建的架构
+GOARCH=amd64
+
+# ---- You may not need to modify the codes below | 下面的代码大概率不需要更改 ----
+
+GO ?= go
+GOFMT ?= gofmt "-s"
+GOFILES := $(shell find . -name "*.go")
+LDFLAGS := -s -w
+
+.PHONY: test
+test: # Run test for the project | 运行项目测试
+	go test -v --cover ./internal/..
+
+.PHONY: fmt
+fmt: # Format the codes | 格式化代码
+	$(GOFMT) -w $(GOFILES)
+
+.PHONY: lint
+lint: # Run go linter | 运行代码错误分析
+	golangci-lint run -D staticcheck
+
+.PHONY: tools
+tools: # Install the necessary tools | 安装必要的工具
+	$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest;
+	$(GO) install github.com/go-swagger/go-swagger/cmd/swagger@latest
+
+
+.PHONY: docker
+docker: # Build the docker image | 构建 docker 镜像
+	docker build -f Dockerfile -t ${DOCKER_USERNAME}/$(SERVICE_DASH)-$(PROJECT_BUILD_SUFFIX):${VERSION} .
+	@echo "Build docker successfully"
+
+.PHONY: publish-docker
+publish-docker: # Publish docker image | 发布 docker 镜像
+	echo "${DOCKER_PASSWORD}" | docker login --username ${DOCKER_USERNAME} --password-stdin https://${REPO}
+	docker push ${DOCKER_USERNAME}/$(SERVICE_DASH)-$(PROJECT_BUILD_SUFFIX):${VERSION}
+	@echo "Publish docker successfully"
+
+.PHONY: gen-swagger
+gen-swagger: # Generate swagger file | 生成 swagger 文件
+	swagger generate spec --output=./$(SERVICE_STYLE).$(SWAGGER_TYPE) --scan-models
+	@echo "Generate swagger successfully"
+
+.PHONY: serve-swagger
+serve-swagger: # Run the swagger server | 运行 swagger 服务
+	lsof -i:36666 | awk 'NR!=1 {print $2}' | xargs killall -9 || true
+	swagger serve -F=swagger --port 36666 $(SERVICE_STYLE).$(SWAGGER_TYPE)
+	@echo "Serve swagger-ui successfully"
+
+.PHONY: gen-api
+gen-api: # Generate API files | 生成 API 的代码
+	goctls api go --api ./desc/all.api --dir ./ --trans_err=false --style=$(PROJECT_STYLE)
+#	swagger generate spec --output=./$(SERVICE_STYLE).$(SWAGGER_TYPE) --scan-models
+	@echo "Generate API codes successfully"
+
+.PHONY: gen-ent
+gen-ent: # Generate Ent codes | 生成 Ent 的代码
+	go run -mod=mod entgo.io/ent/cmd/ent generate --template glob="./ent/template/*.tmpl" ./ent/schema --feature $(ENT_FEATURE)
+	@echo "Generate Ent codes successfully"
+
+.PHONY: gen-api-ent-logic
+gen-api-ent-logic: # Generate CRUD logic from Ent, need to set model and group | 根据 Ent 生成 CRUD 代码,需要设置 model 和 group
+	goctls api ent --schema=./ent/schema --style=$(PROJECT_STYLE) --api_service_name=$(SERVICE) --output=./ --model=$(model) --group=$(group) --i18n=$(PROJECT_I18N) --overwrite=true --api_data=$(AUTO_API_INIT_DATA)
+	@echo "Generate CRUD codes from Ent successfully"
+
+.PHONY: build-win
+build-win: # Build project for Windows | 构建Windows下的可执行文件
+	env CGO_ENABLED=0 GOOS=windows GOARCH=$(GOARCH) go build -ldflags "$(LDFLAGS)" -trimpath -o $(SERVICE_STYLE)_$(PROJECT_BUILD_SUFFIX).exe $(SERVICE_STYLE).go
+	@echo "Build project for Windows successfully"
+
+.PHONY: build-mac
+build-mac: # Build project for MacOS | 构建MacOS下的可执行文件
+	env CGO_ENABLED=0 GOOS=darwin GOARCH=$(GOARCH) go build -ldflags "$(LDFLAGS)" -trimpath -o $(SERVICE_STYLE)_$(PROJECT_BUILD_SUFFIX) $(SERVICE_STYLE).go
+	@echo "Build project for MacOS successfully"
+
+.PHONY: build-linux
+build-linux: # Build project for Linux | 构建Linux下的可执行文件
+	env CGO_ENABLED=0 GOOS=linux GOARCH=$(GOARCH) go build -ldflags "$(LDFLAGS)" -trimpath -o $(SERVICE_STYLE)_$(PROJECT_BUILD_SUFFIX) $(SERVICE_STYLE).go
+	@echo "Build project for Linux successfully"
+
+.PHONY: help
+help: # Show help | 显示帮助
+	@grep -E '^[a-zA-Z0-9 -]+:.*#'  Makefile | sort | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done

+ 5 - 0
desc/all.api

@@ -0,0 +1,5 @@
+import "base.api"
+import "./wechat/server.api"
+import "./wechat/wx.api"
+import "./wechat/wxhook.api"
+import "./wechat/contact.api"

+ 218 - 0
desc/base.api

@@ -0,0 +1,218 @@
+syntax = "v1"
+
+// The basic response with data | 基础带数据信息
+type BaseDataInfo {
+    // Error code | 错误代码
+    Code int    `json:"code"`
+
+    // Message | 提示信息
+    Msg  string `json:"msg"`
+
+    // Data | 数据
+    Data string `json:"data,omitempty"`
+}
+
+// The basic response with data | 基础带数据信息
+type BaseListInfo {
+    // The total number of data | 数据总数
+    Total uint64 `json:"total"`
+
+    // Data | 数据
+    Data string `json:"data,omitempty"`
+}
+
+// The basic response without data | 基础不带数据信息
+type BaseMsgResp {
+    // Error code | 错误代码
+    Code int    `json:"code"`
+
+    // Message | 提示信息
+    Msg  string `json:"msg"`
+}
+
+// The page request parameters | 列表请求参数
+type PageInfo {
+    // Page number | 第几页
+    Page   uint64    `json:"page" validate:"required,number,gt=0"`
+
+    // Page size | 单页数据行数
+    PageSize  uint64    `json:"pageSize" validate:"required,number,lt=100000"`
+}
+
+// Basic ID request | 基础ID参数请求
+type IDReq {
+    // ID
+    // Required: true
+    Id  uint64 `json:"id" validate:"number"`
+}
+
+// Basic IDs request | 基础ID数组参数请求
+type IDsReq {
+    // IDs
+    // Required: true
+    Ids  []uint64 `json:"ids"`
+}
+
+
+// Basic ID request | 基础ID地址参数请求
+type IDPathReq {
+    // ID
+    // Required: true
+    Id  uint64 `path:"id"`
+}
+
+// Basic ID request (int32) | 基础ID参数请求 (int32)
+type IDInt32Req {
+    // ID
+    // Required: true
+    Id  int32 `json:"id" validate:"number"`
+}
+
+// Basic IDs request (int32) | 基础ID数组参数请求 (int32)
+type IDsInt32Req {
+    // IDs
+    // Required: true
+    Ids  []int32 `json:"ids"`
+}
+
+// Basic ID request (int32) | 基础ID地址参数请求 (int32)
+type IDInt32PathReq {
+    // ID
+    // Required: true
+    Id  int32 `path:"id"`
+}
+
+// Basic ID request (uint32) | 基础ID参数请求 (uint32)
+type IDUint32Req {
+    // ID
+    // Required: true
+    Id  uint32 `json:"id" validate:"number"`
+}
+
+// Basic IDs request (uint32) | 基础ID数组参数请求 (uint32)
+type IDsUint32Req {
+    // IDs
+    // Required: true
+    Ids  []uint32 `json:"ids"`
+}
+
+// Basic ID request (uint32) | 基础ID地址参数请求 (uint32)
+type IDUint32PathReq {
+    // ID
+    // Required: true
+    Id  uint32 `path:"id"`
+}
+
+// Basic ID request (int64) | 基础ID参数请求 (int64)
+type IDInt64Req {
+    // ID
+    // Required: true
+    Id  int64 `json:"id" validate:"number"`
+}
+
+// Basic IDs request (int64) | 基础ID数组参数请求 (int64)
+type IDsInt64Req {
+    // IDs
+    // Required: true
+    Ids  []int64 `json:"ids"`
+}
+
+
+// Basic ID request (int64) | 基础ID地址参数请求 (int64)
+type IDInt64PathReq {
+    // ID
+    // Required: true
+    Id  int64 `path:"id"`
+}
+
+
+// Basic UUID request in path | 基础UUID地址参数请求
+type UUIDPathReq {
+    // ID
+    // Required: true
+    Id  string `path:"id"`
+}
+
+// Basic UUID request | 基础UUID参数请求
+type UUIDReq {
+    // ID
+    Id string `json:"id" validate:"required,len=36"`
+}
+
+// Basic UUID array request | 基础UUID数组参数请求
+type UUIDsReq {
+    // Ids
+    // Required: true
+    Ids []string `json:"ids"`
+}
+
+// The base ID response data | 基础ID信息
+type BaseIDInfo {
+    // ID
+    Id        *uint64    `json:"id,optional"`
+
+    // Create date | 创建日期
+    CreatedAt *int64     `json:"createdAt,optional"`
+
+    // Update date | 更新日期
+    UpdatedAt *int64     `json:"updatedAt,optional"`
+}
+
+// The base ID response data (int64) | 基础ID信息 (int64)
+type BaseIDInt64Info {
+    // ID
+    Id        *int64    `json:"id,optional"`
+
+    // Create date | 创建日期
+    CreatedAt *int64     `json:"createdAt,optional"`
+
+    // Update date | 更新日期
+    UpdatedAt *int64     `json:"updatedAt,optional"`
+}
+
+// The base ID response data (int32) | 基础ID信息 (int32)
+type BaseIDInt32Info {
+    // ID
+    Id        *int32    `json:"id,optional"`
+
+    // Create date | 创建日期
+    CreatedAt *int64     `json:"createdAt,optional"`
+
+    // Update date | 更新日期
+    UpdatedAt *int64     `json:"updatedAt,optional"`
+}
+
+// The base ID response data (uint32) | 基础ID信息 (uint32)
+type BaseIDUint32Info {
+    // ID
+    Id        *uint32    `json:"id,optional"`
+
+    // Create date | 创建日期
+    CreatedAt *int64     `json:"createdAt,optional"`
+
+    // Update date | 更新日期
+    UpdatedAt *int64     `json:"updatedAt,optional"`
+}
+
+// The base UUID response data | 基础UUID信息
+type BaseUUIDInfo {
+    // ID
+    Id        *string    `json:"id,optional"`
+
+    // Create date | 创建日期
+    CreatedAt *int64     `json:"createdAt,optional"`
+
+    // Update date | 更新日期
+    UpdatedAt *int64     `json:"updatedAt,optional"`
+}
+
+
+@server(
+	group: base
+)
+
+service Wechat {
+	// Initialize database | 初始化数据库
+	@handler initDatabase
+	get /init/database returns (BaseMsgResp)
+}

+ 122 - 0
desc/wechat/contact.api

@@ -0,0 +1,122 @@
+import "../base.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
+
+        // Contact list data | Contact列表数据
+        Data ContactListInfo `json:"data"`
+    }
+
+    // Contact list data | Contact列表数据
+    ContactListInfo {
+        BaseListInfo
+
+        // The API list data | Contact列表数据
+        Data  []ContactInfo  `json:"data"`
+    }
+
+    // Get contact list request params | Contact列表请求参数
+    ContactListReq {
+        PageInfo
+
+        // 属主微信id 
+        WxWxid  *string `json:"wxWxid,optional"`
+
+        // 微信id 公众号微信ID 
+        Wxid  *string `json:"wxid,optional"`
+
+        // 微信账号 
+        Account  *string `json:"account,optional"`
+    }
+
+    // Contact information response | Contact信息返回体
+    ContactInfoResp {
+        BaseDataInfo
+
+        // Contact information | Contact数据
+        Data ContactInfo `json:"data"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: Contact
+    middleware: Authority
+)
+
+service Wechat {
+    // Create contact information | 创建Contact
+    @handler createContact
+    post /contact/create (ContactInfo) returns (BaseMsgResp)
+
+    // Update contact information | 更新Contact
+    @handler updateContact
+    post /contact/update (ContactInfo) returns (BaseMsgResp)
+
+    // Delete contact information | 删除Contact信息
+    @handler deleteContact
+    post /contact/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get contact list | 获取Contact列表
+    @handler getContactList
+    post /contact/list (ContactListReq) returns (ContactListResp)
+
+    // Get contact by ID | 通过ID获取Contact
+    @handler getContactById
+    post /contact (IDReq) returns (ContactInfoResp)
+}

+ 89 - 0
desc/wechat/server.api

@@ -0,0 +1,89 @@
+import "../base.api"
+
+type (
+    // The response data of server information | Server信息
+    ServerInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用 
+        Status  *uint8 `json:"status,optional"`
+
+        // 名称 
+        Name  *string `json:"name,optional"`
+
+        // 公网ip 
+        PublicIp  *string `json:"publicIp,optional"`
+
+        // 内网ip 
+        PrivateIp  *string `json:"privateIp,optional"`
+
+        // 管理端口 
+        AdminPort  *string `json:"adminPort,optional"`
+    }
+
+    // The response data of server list | Server列表数据
+    ServerListResp {
+        BaseDataInfo
+
+        // Server list data | Server列表数据
+        Data ServerListInfo `json:"data"`
+    }
+
+    // Server list data | Server列表数据
+    ServerListInfo {
+        BaseListInfo
+
+        // The API list data | Server列表数据
+        Data  []ServerInfo  `json:"data"`
+    }
+
+    // Get server list request params | Server列表请求参数
+    ServerListReq {
+        PageInfo
+
+        // 名称 
+        Name  *string `json:"name,optional"`
+
+        // 公网ip 
+        PublicIp  *string `json:"publicIp,optional"`
+
+        // 内网ip 
+        PrivateIp  *string `json:"privateIp,optional"`
+    }
+
+    // Server information response | Server信息返回体
+    ServerInfoResp {
+        BaseDataInfo
+
+        // Server information | Server数据
+        Data ServerInfo `json:"data"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: WechatServer
+    middleware: Authority
+)
+
+service Wechat {
+    // Create server information | 创建Server
+    @handler createServer
+    post /server/create (ServerInfo) returns (BaseMsgResp)
+
+    // Update server information | 更新Server
+    @handler updateServer
+    post /server/update (ServerInfo) returns (BaseMsgResp)
+
+    // Delete server information | 删除Server信息
+    @handler deleteServer
+    post /server/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get server list | 获取Server列表
+    @handler getServerList
+    post /server/list (ServerListReq) returns (ServerListResp)
+
+    // Get server by ID | 通过ID获取Server
+    @handler getServerById
+    post /server (IDReq) returns (ServerInfoResp)
+}

+ 104 - 0
desc/wechat/wx.api

@@ -0,0 +1,104 @@
+import "../base.api"
+
+type (
+    // The response data of wx information | Wx信息
+    WxInfo {
+        BaseIDInfo
+
+        // Status 1: normal 2: ban | 状态 1 正常 2 禁用 
+        Status  *uint8 `json:"status,optional"`
+
+        // 服务器id 
+        ServerId  *uint64 `json:"serverId,optional"`
+
+        // 端口号 
+        Port  *string `json:"port,optional"`
+
+        // 进程号 
+        ProcessId  *string `json:"processId,optional"`
+
+        // 回调地址 
+        Callback  *string `json:"callback,optional"`
+
+        // 微信id 
+        Wxid  *string `json:"wxid,optional"`
+
+        // 微信账号 
+        Account  *string `json:"account,optional"`
+
+        // 微信昵称 
+        Nickname  *string `json:"nickname,optional"`
+
+        // 手机号 
+        Tel  *string `json:"tel,optional"`
+
+        // 微信头像 
+        HeadBig  *string `json:"headBig,optional"`
+    }
+
+    // The response data of wx list | Wx列表数据
+    WxListResp {
+        BaseDataInfo
+
+        // Wx list data | Wx列表数据
+        Data WxListInfo `json:"data"`
+    }
+
+    // Wx list data | Wx列表数据
+    WxListInfo {
+        BaseListInfo
+
+        // The API list data | Wx列表数据
+        Data  []WxInfo  `json:"data"`
+    }
+
+    // Get wx list request params | Wx列表请求参数
+    WxListReq {
+        PageInfo
+
+        // 端口号 
+        Port  *string `json:"port,optional"`
+
+        // 进程号 
+        ProcessId  *string `json:"processId,optional"`
+
+        // 回调地址 
+        Callback  *string `json:"callback,optional"`
+    }
+
+    // Wx information response | Wx信息返回体
+    WxInfoResp {
+        BaseDataInfo
+
+        // Wx information | Wx数据
+        Data WxInfo `json:"data"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: Wx
+    middleware: Authority
+)
+
+service Wechat {
+    // Create wx information | 创建Wx
+    @handler createWx
+    post /wx/create (WxInfo) returns (BaseMsgResp)
+
+    // Update wx information | 更新Wx
+    @handler updateWx
+    post /wx/update (WxInfo) returns (BaseMsgResp)
+
+    // Delete wx information | 删除Wx信息
+    @handler deleteWx
+    post /wx/delete (IDsReq) returns (BaseMsgResp)
+
+    // Get wx list | 获取Wx列表
+    @handler getWxList
+    post /wx/list (WxListReq) returns (WxListResp)
+
+    // Get wx by ID | 通过ID获取Wx
+    @handler getWxById
+    post /wx (IDReq) returns (WxInfoResp)
+}

+ 54 - 0
desc/wechat/wxhook.api

@@ -0,0 +1,54 @@
+import "../base.api"
+
+type (
+
+    LoginQRStatus  {
+        // 登陆二维码
+        QRCode  string `json:"qRCode,optional"`
+
+        // 登陆二维码状态
+        Status  string `json:"status,optional"`
+
+        // 登陆二维码状态描述
+        StatusDesc  string `json:"statusDesc,optional"`
+    }
+
+    // 刷新登陆二维码请求参数
+    RefreshLoginQRReq {
+        // 服务器id 
+        ServerId  *uint64 `json:"serverId,optional"`
+
+        // 端口号 
+        Port  *string `json:"port,optional"`
+
+        // 回调地址 
+        Callback  *string `json:"callback,optional"`
+    }
+
+    // 刷新登陆二维码返回参数
+    RefreshLoginQRResp {
+        BaseDataInfo
+        // 二维码Base64
+        Data  LoginQRStatus  `json:"data,optional"`
+    }
+)
+
+@server(
+    jwt: Auth
+    group: Wxhook
+    middleware: Authority
+)
+
+service Wechat {
+    // Refresh login QR code | 刷新登陆二维码
+    @handler refreshLoginQR
+    post /wxhook/refreshLoginQR (RefreshLoginQRReq) returns (RefreshLoginQRResp)
+
+    // 退出登陆
+    @handler logout
+    post /wxhook/logout (IDReq) returns (BaseMsgResp)
+
+    // 获取好友和群信息
+    @handler getFriendsAndGroups
+    post /wxhook/getFriendsAndGroups (IDReq) returns (BaseMsgResp)
+}

+ 692 - 0
ent/client.go

@@ -0,0 +1,692 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"log"
+	"reflect"
+
+	"wechat-api/ent/migrate"
+
+	"wechat-api/ent/contact"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+
+	stdsql "database/sql"
+)
+
+// Client is the client that holds all ent builders.
+type Client struct {
+	config
+	// Schema is the client for creating, migrating and dropping schema.
+	Schema *migrate.Schema
+	// Contact is the client for interacting with the Contact builders.
+	Contact *ContactClient
+	// Server is the client for interacting with the Server builders.
+	Server *ServerClient
+	// Wx is the client for interacting with the Wx builders.
+	Wx *WxClient
+}
+
+// NewClient creates a new client configured with the given options.
+func NewClient(opts ...Option) *Client {
+	client := &Client{config: newConfig(opts...)}
+	client.init()
+	return client
+}
+
+func (c *Client) init() {
+	c.Schema = migrate.NewSchema(c.driver)
+	c.Contact = NewContactClient(c.config)
+	c.Server = NewServerClient(c.config)
+	c.Wx = NewWxClient(c.config)
+}
+
+type (
+	// config is the configuration for the client and its builder.
+	config struct {
+		// driver used for executing database requests.
+		driver dialect.Driver
+		// debug enable a debug logging.
+		debug bool
+		// log used for logging on debug mode.
+		log func(...any)
+		// hooks to execute on mutations.
+		hooks *hooks
+		// interceptors to execute on queries.
+		inters *inters
+	}
+	// Option function to configure the client.
+	Option func(*config)
+)
+
+// newConfig creates a new config for the client.
+func newConfig(opts ...Option) config {
+	cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}
+	cfg.options(opts...)
+	return cfg
+}
+
+// options applies the options on the config object.
+func (c *config) options(opts ...Option) {
+	for _, opt := range opts {
+		opt(c)
+	}
+	if c.debug {
+		c.driver = dialect.Debug(c.driver, c.log)
+	}
+}
+
+// Debug enables debug logging on the ent.Driver.
+func Debug() Option {
+	return func(c *config) {
+		c.debug = true
+	}
+}
+
+// Log sets the logging function for debug mode.
+func Log(fn func(...any)) Option {
+	return func(c *config) {
+		c.log = fn
+	}
+}
+
+// Driver configures the client driver.
+func Driver(driver dialect.Driver) Option {
+	return func(c *config) {
+		c.driver = driver
+	}
+}
+
+// Open opens a database/sql.DB specified by the driver name and
+// the data source name, and returns a new client attached to it.
+// Optional parameters can be added for configuring the client.
+func Open(driverName, dataSourceName string, options ...Option) (*Client, error) {
+	switch driverName {
+	case dialect.MySQL, dialect.Postgres, dialect.SQLite:
+		drv, err := sql.Open(driverName, dataSourceName)
+		if err != nil {
+			return nil, err
+		}
+		return NewClient(append(options, Driver(drv))...), nil
+	default:
+		return nil, fmt.Errorf("unsupported driver: %q", driverName)
+	}
+}
+
+// ErrTxStarted is returned when trying to start a new transaction from a transactional client.
+var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction")
+
+// Tx returns a new transactional client. The provided context
+// is used until the transaction is committed or rolled back.
+func (c *Client) Tx(ctx context.Context) (*Tx, error) {
+	if _, ok := c.driver.(*txDriver); ok {
+		return nil, ErrTxStarted
+	}
+	tx, err := newTx(ctx, c.driver)
+	if err != nil {
+		return nil, fmt.Errorf("ent: starting a transaction: %w", err)
+	}
+	cfg := c.config
+	cfg.driver = tx
+	return &Tx{
+		ctx:     ctx,
+		config:  cfg,
+		Contact: NewContactClient(cfg),
+		Server:  NewServerClient(cfg),
+		Wx:      NewWxClient(cfg),
+	}, nil
+}
+
+// BeginTx returns a transactional client with specified options.
+func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
+	if _, ok := c.driver.(*txDriver); ok {
+		return nil, errors.New("ent: cannot start a transaction within a transaction")
+	}
+	tx, err := c.driver.(interface {
+		BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
+	}).BeginTx(ctx, opts)
+	if err != nil {
+		return nil, fmt.Errorf("ent: starting a transaction: %w", err)
+	}
+	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),
+	}, nil
+}
+
+// Debug returns a new debug-client. It's used to get verbose logging on specific operations.
+//
+//	client.Debug().
+//		Contact.
+//		Query().
+//		Count(ctx)
+func (c *Client) Debug() *Client {
+	if c.debug {
+		return c
+	}
+	cfg := c.config
+	cfg.driver = dialect.Debug(c.driver, c.log)
+	client := &Client{config: cfg}
+	client.init()
+	return client
+}
+
+// Close closes the database connection and prevents new queries from starting.
+func (c *Client) Close() error {
+	return c.driver.Close()
+}
+
+// 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...)
+}
+
+// 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...)
+}
+
+// Mutate implements the ent.Mutator interface.
+func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
+	switch m := m.(type) {
+	case *ContactMutation:
+		return c.Contact.mutate(ctx, m)
+	case *ServerMutation:
+		return c.Server.mutate(ctx, m)
+	case *WxMutation:
+		return c.Wx.mutate(ctx, m)
+	default:
+		return nil, fmt.Errorf("ent: unknown mutation type %T", m)
+	}
+}
+
+// ContactClient is a client for the Contact schema.
+type ContactClient struct {
+	config
+}
+
+// NewContactClient returns a client for the Contact from the given config.
+func NewContactClient(c config) *ContactClient {
+	return &ContactClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `contact.Hooks(f(g(h())))`.
+func (c *ContactClient) Use(hooks ...Hook) {
+	c.hooks.Contact = append(c.hooks.Contact, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `contact.Intercept(f(g(h())))`.
+func (c *ContactClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Contact = append(c.inters.Contact, interceptors...)
+}
+
+// Create returns a builder for creating a Contact entity.
+func (c *ContactClient) Create() *ContactCreate {
+	mutation := newContactMutation(c.config, OpCreate)
+	return &ContactCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Contact entities.
+func (c *ContactClient) CreateBulk(builders ...*ContactCreate) *ContactCreateBulk {
+	return &ContactCreateBulk{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 *ContactClient) MapCreateBulk(slice any, setFunc func(*ContactCreate, int)) *ContactCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &ContactCreateBulk{err: fmt.Errorf("calling to ContactClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*ContactCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &ContactCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Contact.
+func (c *ContactClient) Update() *ContactUpdate {
+	mutation := newContactMutation(c.config, OpUpdate)
+	return &ContactUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *ContactClient) UpdateOne(co *Contact) *ContactUpdateOne {
+	mutation := newContactMutation(c.config, OpUpdateOne, withContact(co))
+	return &ContactUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *ContactClient) UpdateOneID(id uint64) *ContactUpdateOne {
+	mutation := newContactMutation(c.config, OpUpdateOne, withContactID(id))
+	return &ContactUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Contact.
+func (c *ContactClient) Delete() *ContactDelete {
+	mutation := newContactMutation(c.config, OpDelete)
+	return &ContactDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *ContactClient) DeleteOne(co *Contact) *ContactDeleteOne {
+	return c.DeleteOneID(co.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *ContactClient) DeleteOneID(id uint64) *ContactDeleteOne {
+	builder := c.Delete().Where(contact.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &ContactDeleteOne{builder}
+}
+
+// Query returns a query builder for Contact.
+func (c *ContactClient) Query() *ContactQuery {
+	return &ContactQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeContact},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Contact entity by its id.
+func (c *ContactClient) Get(ctx context.Context, id uint64) (*Contact, error) {
+	return c.Query().Where(contact.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *ContactClient) GetX(ctx context.Context, id uint64) *Contact {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// Hooks returns the client hooks.
+func (c *ContactClient) Hooks() []Hook {
+	hooks := c.hooks.Contact
+	return append(hooks[:len(hooks):len(hooks)], contact.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *ContactClient) Interceptors() []Interceptor {
+	inters := c.inters.Contact
+	return append(inters[:len(inters):len(inters)], contact.Interceptors[:]...)
+}
+
+func (c *ContactClient) mutate(ctx context.Context, m *ContactMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&ContactCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&ContactUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&ContactUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&ContactDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Contact mutation op: %q", m.Op())
+	}
+}
+
+// ServerClient is a client for the Server schema.
+type ServerClient struct {
+	config
+}
+
+// NewServerClient returns a client for the Server from the given config.
+func NewServerClient(c config) *ServerClient {
+	return &ServerClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `server.Hooks(f(g(h())))`.
+func (c *ServerClient) Use(hooks ...Hook) {
+	c.hooks.Server = append(c.hooks.Server, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `server.Intercept(f(g(h())))`.
+func (c *ServerClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Server = append(c.inters.Server, interceptors...)
+}
+
+// Create returns a builder for creating a Server entity.
+func (c *ServerClient) Create() *ServerCreate {
+	mutation := newServerMutation(c.config, OpCreate)
+	return &ServerCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Server entities.
+func (c *ServerClient) CreateBulk(builders ...*ServerCreate) *ServerCreateBulk {
+	return &ServerCreateBulk{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 *ServerClient) MapCreateBulk(slice any, setFunc func(*ServerCreate, int)) *ServerCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &ServerCreateBulk{err: fmt.Errorf("calling to ServerClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*ServerCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &ServerCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Server.
+func (c *ServerClient) Update() *ServerUpdate {
+	mutation := newServerMutation(c.config, OpUpdate)
+	return &ServerUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *ServerClient) UpdateOne(s *Server) *ServerUpdateOne {
+	mutation := newServerMutation(c.config, OpUpdateOne, withServer(s))
+	return &ServerUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *ServerClient) UpdateOneID(id uint64) *ServerUpdateOne {
+	mutation := newServerMutation(c.config, OpUpdateOne, withServerID(id))
+	return &ServerUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Server.
+func (c *ServerClient) Delete() *ServerDelete {
+	mutation := newServerMutation(c.config, OpDelete)
+	return &ServerDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *ServerClient) DeleteOne(s *Server) *ServerDeleteOne {
+	return c.DeleteOneID(s.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *ServerClient) DeleteOneID(id uint64) *ServerDeleteOne {
+	builder := c.Delete().Where(server.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &ServerDeleteOne{builder}
+}
+
+// Query returns a query builder for Server.
+func (c *ServerClient) Query() *ServerQuery {
+	return &ServerQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeServer},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Server entity by its id.
+func (c *ServerClient) Get(ctx context.Context, id uint64) (*Server, error) {
+	return c.Query().Where(server.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *ServerClient) GetX(ctx context.Context, id uint64) *Server {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QueryWxs queries the wxs edge of a Server.
+func (c *ServerClient) QueryWxs(s *Server) *WxQuery {
+	query := (&WxClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := s.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(server.Table, server.FieldID, id),
+			sqlgraph.To(wx.Table, wx.FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, server.WxsTable, server.WxsColumn),
+		)
+		fromV = sqlgraph.Neighbors(s.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *ServerClient) Hooks() []Hook {
+	hooks := c.hooks.Server
+	return append(hooks[:len(hooks):len(hooks)], server.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *ServerClient) Interceptors() []Interceptor {
+	inters := c.inters.Server
+	return append(inters[:len(inters):len(inters)], server.Interceptors[:]...)
+}
+
+func (c *ServerClient) mutate(ctx context.Context, m *ServerMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&ServerCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&ServerUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&ServerUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&ServerDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Server mutation op: %q", m.Op())
+	}
+}
+
+// WxClient is a client for the Wx schema.
+type WxClient struct {
+	config
+}
+
+// NewWxClient returns a client for the Wx from the given config.
+func NewWxClient(c config) *WxClient {
+	return &WxClient{config: c}
+}
+
+// Use adds a list of mutation hooks to the hooks stack.
+// A call to `Use(f, g, h)` equals to `wx.Hooks(f(g(h())))`.
+func (c *WxClient) Use(hooks ...Hook) {
+	c.hooks.Wx = append(c.hooks.Wx, hooks...)
+}
+
+// Intercept adds a list of query interceptors to the interceptors stack.
+// A call to `Intercept(f, g, h)` equals to `wx.Intercept(f(g(h())))`.
+func (c *WxClient) Intercept(interceptors ...Interceptor) {
+	c.inters.Wx = append(c.inters.Wx, interceptors...)
+}
+
+// Create returns a builder for creating a Wx entity.
+func (c *WxClient) Create() *WxCreate {
+	mutation := newWxMutation(c.config, OpCreate)
+	return &WxCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// CreateBulk returns a builder for creating a bulk of Wx entities.
+func (c *WxClient) CreateBulk(builders ...*WxCreate) *WxCreateBulk {
+	return &WxCreateBulk{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 *WxClient) MapCreateBulk(slice any, setFunc func(*WxCreate, int)) *WxCreateBulk {
+	rv := reflect.ValueOf(slice)
+	if rv.Kind() != reflect.Slice {
+		return &WxCreateBulk{err: fmt.Errorf("calling to WxClient.MapCreateBulk with wrong type %T, need slice", slice)}
+	}
+	builders := make([]*WxCreate, rv.Len())
+	for i := 0; i < rv.Len(); i++ {
+		builders[i] = c.Create()
+		setFunc(builders[i], i)
+	}
+	return &WxCreateBulk{config: c.config, builders: builders}
+}
+
+// Update returns an update builder for Wx.
+func (c *WxClient) Update() *WxUpdate {
+	mutation := newWxMutation(c.config, OpUpdate)
+	return &WxUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOne returns an update builder for the given entity.
+func (c *WxClient) UpdateOne(w *Wx) *WxUpdateOne {
+	mutation := newWxMutation(c.config, OpUpdateOne, withWx(w))
+	return &WxUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// UpdateOneID returns an update builder for the given id.
+func (c *WxClient) UpdateOneID(id uint64) *WxUpdateOne {
+	mutation := newWxMutation(c.config, OpUpdateOne, withWxID(id))
+	return &WxUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// Delete returns a delete builder for Wx.
+func (c *WxClient) Delete() *WxDelete {
+	mutation := newWxMutation(c.config, OpDelete)
+	return &WxDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
+}
+
+// DeleteOne returns a builder for deleting the given entity.
+func (c *WxClient) DeleteOne(w *Wx) *WxDeleteOne {
+	return c.DeleteOneID(w.ID)
+}
+
+// DeleteOneID returns a builder for deleting the given entity by its id.
+func (c *WxClient) DeleteOneID(id uint64) *WxDeleteOne {
+	builder := c.Delete().Where(wx.ID(id))
+	builder.mutation.id = &id
+	builder.mutation.op = OpDeleteOne
+	return &WxDeleteOne{builder}
+}
+
+// Query returns a query builder for Wx.
+func (c *WxClient) Query() *WxQuery {
+	return &WxQuery{
+		config: c.config,
+		ctx:    &QueryContext{Type: TypeWx},
+		inters: c.Interceptors(),
+	}
+}
+
+// Get returns a Wx entity by its id.
+func (c *WxClient) Get(ctx context.Context, id uint64) (*Wx, error) {
+	return c.Query().Where(wx.ID(id)).Only(ctx)
+}
+
+// GetX is like Get, but panics if an error occurs.
+func (c *WxClient) GetX(ctx context.Context, id uint64) *Wx {
+	obj, err := c.Get(ctx, id)
+	if err != nil {
+		panic(err)
+	}
+	return obj
+}
+
+// QueryServer queries the server edge of a Wx.
+func (c *WxClient) QueryServer(w *Wx) *ServerQuery {
+	query := (&ServerClient{config: c.config}).Query()
+	query.path = func(context.Context) (fromV *sql.Selector, _ error) {
+		id := w.ID
+		step := sqlgraph.NewStep(
+			sqlgraph.From(wx.Table, wx.FieldID, id),
+			sqlgraph.To(server.Table, server.FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, wx.ServerTable, wx.ServerColumn),
+		)
+		fromV = sqlgraph.Neighbors(w.driver.Dialect(), step)
+		return fromV, nil
+	}
+	return query
+}
+
+// Hooks returns the client hooks.
+func (c *WxClient) Hooks() []Hook {
+	hooks := c.hooks.Wx
+	return append(hooks[:len(hooks):len(hooks)], wx.Hooks[:]...)
+}
+
+// Interceptors returns the client interceptors.
+func (c *WxClient) Interceptors() []Interceptor {
+	inters := c.inters.Wx
+	return append(inters[:len(inters):len(inters)], wx.Interceptors[:]...)
+}
+
+func (c *WxClient) mutate(ctx context.Context, m *WxMutation) (Value, error) {
+	switch m.Op() {
+	case OpCreate:
+		return (&WxCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdate:
+		return (&WxUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpUpdateOne:
+		return (&WxUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
+	case OpDelete, OpDeleteOne:
+		return (&WxDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
+	default:
+		return nil, fmt.Errorf("ent: unknown Wx mutation op: %q", m.Op())
+	}
+}
+
+// hooks and interceptors per client, for fast access.
+type (
+	hooks struct {
+		Contact, Server, Wx []ent.Hook
+	}
+	inters struct {
+		Contact, Server, Wx []ent.Interceptor
+	}
+)
+
+// ExecContext allows calling the underlying ExecContext method of the driver if it is supported by it.
+// See, database/sql#DB.ExecContext for more information.
+func (c *config) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
+	ex, ok := c.driver.(interface {
+		ExecContext(context.Context, string, ...any) (stdsql.Result, error)
+	})
+	if !ok {
+		return nil, fmt.Errorf("Driver.ExecContext is not supported")
+	}
+	return ex.ExecContext(ctx, query, args...)
+}
+
+// QueryContext allows calling the underlying QueryContext method of the driver if it is supported by it.
+// See, database/sql#DB.QueryContext for more information.
+func (c *config) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
+	q, ok := c.driver.(interface {
+		QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
+	})
+	if !ok {
+		return nil, fmt.Errorf("Driver.QueryContext is not supported")
+	}
+	return q.QueryContext(ctx, query, args...)
+}

+ 304 - 0
ent/contact.go

@@ -0,0 +1,304 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/contact"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Contact is the model entity for the Contact schema.
+type Contact 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
+	WxWxid string `json:"wx_wxid,omitempty"`
+	// 联系人类型:1好友,2群组,3公众号,4企业微信联系人
+	Type int `json:"type,omitempty"`
+	// 微信id 公众号微信ID
+	Wxid string `json:"wxid,omitempty"`
+	// 微信账号
+	Account string `json:"account,omitempty"`
+	// 微信昵称 群备注名称
+	Nickname string `json:"nickname,omitempty"`
+	// 备注名
+	Markname string `json:"markname,omitempty"`
+	// 头像
+	Headimg string `json:"headimg,omitempty"`
+	// 性别 0未知 1男 2女
+	Sex int `json:"sex,omitempty"`
+	// 星标 65/67=星标 1/3=未星标
+	Starrole string `json:"starrole,omitempty"`
+	// 不让他看我的朋友圈 0可以看 1不让看
+	Dontseeit int `json:"dontseeit,omitempty"`
+	// 不看他的朋友圈 0可以看 1不看 1=开启了不看他 128/129=仅聊天
+	Dontseeme int `json:"dontseeme,omitempty"`
+	// 所属标签id清单,多开会用逗号隔开
+	Lag string `json:"lag,omitempty"`
+	// 群组id
+	Gid string `json:"gid,omitempty"`
+	// 群组名称
+	Gname string `json:"gname,omitempty"`
+	// v3数据
+	V3           string `json:"v3,omitempty"`
+	selectValues sql.SelectValues
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Contact) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case contact.FieldID, contact.FieldStatus, contact.FieldType, contact.FieldSex, contact.FieldDontseeit, contact.FieldDontseeme:
+			values[i] = new(sql.NullInt64)
+		case contact.FieldWxWxid, contact.FieldWxid, contact.FieldAccount, contact.FieldNickname, contact.FieldMarkname, contact.FieldHeadimg, contact.FieldStarrole, contact.FieldLag, contact.FieldGid, contact.FieldGname, contact.FieldV3:
+			values[i] = new(sql.NullString)
+		case contact.FieldCreatedAt, contact.FieldUpdatedAt, contact.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 Contact fields.
+func (c *Contact) 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 contact.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			c.ID = uint64(value.Int64)
+		case contact.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 {
+				c.CreatedAt = value.Time
+			}
+		case contact.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 {
+				c.UpdatedAt = value.Time
+			}
+		case contact.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				c.Status = uint8(value.Int64)
+			}
+		case contact.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 {
+				c.DeletedAt = value.Time
+			}
+		case contact.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 {
+				c.WxWxid = value.String
+			}
+		case contact.FieldType:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field type", values[i])
+			} else if value.Valid {
+				c.Type = int(value.Int64)
+			}
+		case contact.FieldWxid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field wxid", values[i])
+			} else if value.Valid {
+				c.Wxid = value.String
+			}
+		case contact.FieldAccount:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field account", values[i])
+			} else if value.Valid {
+				c.Account = value.String
+			}
+		case contact.FieldNickname:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field nickname", values[i])
+			} else if value.Valid {
+				c.Nickname = value.String
+			}
+		case contact.FieldMarkname:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field markname", values[i])
+			} else if value.Valid {
+				c.Markname = value.String
+			}
+		case contact.FieldHeadimg:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field headimg", values[i])
+			} else if value.Valid {
+				c.Headimg = value.String
+			}
+		case contact.FieldSex:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field sex", values[i])
+			} else if value.Valid {
+				c.Sex = int(value.Int64)
+			}
+		case contact.FieldStarrole:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field starrole", values[i])
+			} else if value.Valid {
+				c.Starrole = value.String
+			}
+		case contact.FieldDontseeit:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field dontseeit", values[i])
+			} else if value.Valid {
+				c.Dontseeit = int(value.Int64)
+			}
+		case contact.FieldDontseeme:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field dontseeme", values[i])
+			} else if value.Valid {
+				c.Dontseeme = int(value.Int64)
+			}
+		case contact.FieldLag:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field lag", values[i])
+			} else if value.Valid {
+				c.Lag = value.String
+			}
+		case contact.FieldGid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field gid", values[i])
+			} else if value.Valid {
+				c.Gid = value.String
+			}
+		case contact.FieldGname:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field gname", values[i])
+			} else if value.Valid {
+				c.Gname = value.String
+			}
+		case contact.FieldV3:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field v3", values[i])
+			} else if value.Valid {
+				c.V3 = value.String
+			}
+		default:
+			c.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Contact.
+// This includes values selected through modifiers, order, etc.
+func (c *Contact) Value(name string) (ent.Value, error) {
+	return c.selectValues.Get(name)
+}
+
+// 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.
+func (c *Contact) Update() *ContactUpdateOne {
+	return NewContactClient(c.config).UpdateOne(c)
+}
+
+// Unwrap unwraps the Contact 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 (c *Contact) Unwrap() *Contact {
+	_tx, ok := c.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Contact is not a transactional entity")
+	}
+	c.config.driver = _tx.drv
+	return c
+}
+
+// String implements the fmt.Stringer.
+func (c *Contact) String() string {
+	var builder strings.Builder
+	builder.WriteString("Contact(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", c.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(c.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(c.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", c.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(c.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("wx_wxid=")
+	builder.WriteString(c.WxWxid)
+	builder.WriteString(", ")
+	builder.WriteString("type=")
+	builder.WriteString(fmt.Sprintf("%v", c.Type))
+	builder.WriteString(", ")
+	builder.WriteString("wxid=")
+	builder.WriteString(c.Wxid)
+	builder.WriteString(", ")
+	builder.WriteString("account=")
+	builder.WriteString(c.Account)
+	builder.WriteString(", ")
+	builder.WriteString("nickname=")
+	builder.WriteString(c.Nickname)
+	builder.WriteString(", ")
+	builder.WriteString("markname=")
+	builder.WriteString(c.Markname)
+	builder.WriteString(", ")
+	builder.WriteString("headimg=")
+	builder.WriteString(c.Headimg)
+	builder.WriteString(", ")
+	builder.WriteString("sex=")
+	builder.WriteString(fmt.Sprintf("%v", c.Sex))
+	builder.WriteString(", ")
+	builder.WriteString("starrole=")
+	builder.WriteString(c.Starrole)
+	builder.WriteString(", ")
+	builder.WriteString("dontseeit=")
+	builder.WriteString(fmt.Sprintf("%v", c.Dontseeit))
+	builder.WriteString(", ")
+	builder.WriteString("dontseeme=")
+	builder.WriteString(fmt.Sprintf("%v", c.Dontseeme))
+	builder.WriteString(", ")
+	builder.WriteString("lag=")
+	builder.WriteString(c.Lag)
+	builder.WriteString(", ")
+	builder.WriteString("gid=")
+	builder.WriteString(c.Gid)
+	builder.WriteString(", ")
+	builder.WriteString("gname=")
+	builder.WriteString(c.Gname)
+	builder.WriteString(", ")
+	builder.WriteString("v3=")
+	builder.WriteString(c.V3)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Contacts is a parsable slice of Contact.
+type Contacts []*Contact

+ 242 - 0
ent/contact/contact.go

@@ -0,0 +1,242 @@
+// Code generated by ent, DO NOT EDIT.
+
+package contact
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+const (
+	// Label holds the string label denoting the contact type in the database.
+	Label = "contact"
+	// 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"
+	// FieldWxWxid holds the string denoting the wx_wxid field in the database.
+	FieldWxWxid = "wx_wxid"
+	// FieldType holds the string denoting the type field in the database.
+	FieldType = "type"
+	// FieldWxid holds the string denoting the wxid field in the database.
+	FieldWxid = "wxid"
+	// FieldAccount holds the string denoting the account field in the database.
+	FieldAccount = "account"
+	// FieldNickname holds the string denoting the nickname field in the database.
+	FieldNickname = "nickname"
+	// FieldMarkname holds the string denoting the markname field in the database.
+	FieldMarkname = "markname"
+	// FieldHeadimg holds the string denoting the headimg field in the database.
+	FieldHeadimg = "headimg"
+	// FieldSex holds the string denoting the sex field in the database.
+	FieldSex = "sex"
+	// FieldStarrole holds the string denoting the starrole field in the database.
+	FieldStarrole = "starrole"
+	// FieldDontseeit holds the string denoting the dontseeit field in the database.
+	FieldDontseeit = "dontseeit"
+	// FieldDontseeme holds the string denoting the dontseeme field in the database.
+	FieldDontseeme = "dontseeme"
+	// FieldLag holds the string denoting the lag field in the database.
+	FieldLag = "lag"
+	// FieldGid holds the string denoting the gid field in the database.
+	FieldGid = "gid"
+	// FieldGname holds the string denoting the gname field in the database.
+	FieldGname = "gname"
+	// FieldV3 holds the string denoting the v3 field in the database.
+	FieldV3 = "v3"
+	// Table holds the table name of the contact in the database.
+	Table = "contact"
+)
+
+// Columns holds all SQL columns for contact fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldWxWxid,
+	FieldType,
+	FieldWxid,
+	FieldAccount,
+	FieldNickname,
+	FieldMarkname,
+	FieldHeadimg,
+	FieldSex,
+	FieldStarrole,
+	FieldDontseeit,
+	FieldDontseeme,
+	FieldLag,
+	FieldGid,
+	FieldGname,
+	FieldV3,
+}
+
+// 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
+	// DefaultWxWxid holds the default value on creation for the "wx_wxid" field.
+	DefaultWxWxid string
+	// DefaultType holds the default value on creation for the "type" field.
+	DefaultType int
+	// DefaultWxid holds the default value on creation for the "wxid" field.
+	DefaultWxid string
+	// DefaultAccount holds the default value on creation for the "account" field.
+	DefaultAccount string
+	// DefaultNickname holds the default value on creation for the "nickname" field.
+	DefaultNickname string
+	// DefaultMarkname holds the default value on creation for the "markname" field.
+	DefaultMarkname string
+	// DefaultHeadimg holds the default value on creation for the "headimg" field.
+	DefaultHeadimg string
+	// DefaultSex holds the default value on creation for the "sex" field.
+	DefaultSex int
+	// DefaultStarrole holds the default value on creation for the "starrole" field.
+	DefaultStarrole string
+	// DefaultDontseeit holds the default value on creation for the "dontseeit" field.
+	DefaultDontseeit int
+	// DefaultDontseeme holds the default value on creation for the "dontseeme" field.
+	DefaultDontseeme int
+	// DefaultLag holds the default value on creation for the "lag" field.
+	DefaultLag string
+	// DefaultGid holds the default value on creation for the "gid" field.
+	DefaultGid string
+	// DefaultGname holds the default value on creation for the "gname" field.
+	DefaultGname string
+	// DefaultV3 holds the default value on creation for the "v3" field.
+	DefaultV3 string
+)
+
+// OrderOption defines the ordering options for the Contact 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()
+}
+
+// ByWxWxid orders the results by the wx_wxid field.
+func ByWxWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxWxid, opts...).ToFunc()
+}
+
+// ByType orders the results by the type field.
+func ByType(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldType, opts...).ToFunc()
+}
+
+// ByWxid orders the results by the wxid field.
+func ByWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxid, opts...).ToFunc()
+}
+
+// ByAccount orders the results by the account field.
+func ByAccount(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAccount, opts...).ToFunc()
+}
+
+// ByNickname orders the results by the nickname field.
+func ByNickname(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldNickname, opts...).ToFunc()
+}
+
+// ByMarkname orders the results by the markname field.
+func ByMarkname(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldMarkname, opts...).ToFunc()
+}
+
+// ByHeadimg orders the results by the headimg field.
+func ByHeadimg(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldHeadimg, opts...).ToFunc()
+}
+
+// BySex orders the results by the sex field.
+func BySex(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldSex, opts...).ToFunc()
+}
+
+// ByStarrole orders the results by the starrole field.
+func ByStarrole(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldStarrole, opts...).ToFunc()
+}
+
+// ByDontseeit orders the results by the dontseeit field.
+func ByDontseeit(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDontseeit, opts...).ToFunc()
+}
+
+// ByDontseeme orders the results by the dontseeme field.
+func ByDontseeme(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldDontseeme, opts...).ToFunc()
+}
+
+// ByLag orders the results by the lag field.
+func ByLag(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldLag, opts...).ToFunc()
+}
+
+// ByGid orders the results by the gid field.
+func ByGid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldGid, opts...).ToFunc()
+}
+
+// ByGname orders the results by the gname field.
+func ByGname(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldGname, opts...).ToFunc()
+}
+
+// ByV3 orders the results by the v3 field.
+func ByV3(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldV3, opts...).ToFunc()
+}

+ 1240 - 0
ent/contact/where.go

@@ -0,0 +1,1240 @@
+// Code generated by ent, DO NOT EDIT.
+
+package contact
+
+import (
+	"time"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+)
+
+// ID filters vertices based on their ID field.
+func ID(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.Contact {
+	return predicate.Contact(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.Contact {
+	return predicate.Contact(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.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.Contact {
+	return predicate.Contact(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.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// WxWxid applies equality check predicate on the "wx_wxid" field. It's identical to WxWxidEQ.
+func WxWxid(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldWxWxid, v))
+}
+
+// Type applies equality check predicate on the "type" field. It's identical to TypeEQ.
+func Type(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldType, v))
+}
+
+// Wxid applies equality check predicate on the "wxid" field. It's identical to WxidEQ.
+func Wxid(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldWxid, v))
+}
+
+// Account applies equality check predicate on the "account" field. It's identical to AccountEQ.
+func Account(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldAccount, v))
+}
+
+// Nickname applies equality check predicate on the "nickname" field. It's identical to NicknameEQ.
+func Nickname(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldNickname, v))
+}
+
+// Markname applies equality check predicate on the "markname" field. It's identical to MarknameEQ.
+func Markname(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldMarkname, v))
+}
+
+// Headimg applies equality check predicate on the "headimg" field. It's identical to HeadimgEQ.
+func Headimg(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldHeadimg, v))
+}
+
+// Sex applies equality check predicate on the "sex" field. It's identical to SexEQ.
+func Sex(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldSex, v))
+}
+
+// Starrole applies equality check predicate on the "starrole" field. It's identical to StarroleEQ.
+func Starrole(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldStarrole, v))
+}
+
+// Dontseeit applies equality check predicate on the "dontseeit" field. It's identical to DontseeitEQ.
+func Dontseeit(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDontseeit, v))
+}
+
+// Dontseeme applies equality check predicate on the "dontseeme" field. It's identical to DontseemeEQ.
+func Dontseeme(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDontseeme, v))
+}
+
+// Lag applies equality check predicate on the "lag" field. It's identical to LagEQ.
+func Lag(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldLag, v))
+}
+
+// Gid applies equality check predicate on the "gid" field. It's identical to GidEQ.
+func Gid(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldGid, v))
+}
+
+// Gname applies equality check predicate on the "gname" field. It's identical to GnameEQ.
+func Gname(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldGname, v))
+}
+
+// V3 applies equality check predicate on the "v3" field. It's identical to V3EQ.
+func V3(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldV3, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.Contact {
+	return predicate.Contact(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.Contact {
+	return predicate.Contact(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.Contact {
+	return predicate.Contact(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.Contact {
+	return predicate.Contact(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// WxWxidEQ applies the EQ predicate on the "wx_wxid" field.
+func WxWxidEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldWxWxid, v))
+}
+
+// WxWxidNEQ applies the NEQ predicate on the "wx_wxid" field.
+func WxWxidNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldWxWxid, v))
+}
+
+// WxWxidIn applies the In predicate on the "wx_wxid" field.
+func WxWxidIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldWxWxid, vs...))
+}
+
+// WxWxidNotIn applies the NotIn predicate on the "wx_wxid" field.
+func WxWxidNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldWxWxid, vs...))
+}
+
+// WxWxidGT applies the GT predicate on the "wx_wxid" field.
+func WxWxidGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldWxWxid, v))
+}
+
+// WxWxidGTE applies the GTE predicate on the "wx_wxid" field.
+func WxWxidGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldWxWxid, v))
+}
+
+// WxWxidLT applies the LT predicate on the "wx_wxid" field.
+func WxWxidLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldWxWxid, v))
+}
+
+// WxWxidLTE applies the LTE predicate on the "wx_wxid" field.
+func WxWxidLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldWxWxid, v))
+}
+
+// WxWxidContains applies the Contains predicate on the "wx_wxid" field.
+func WxWxidContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldWxWxid, v))
+}
+
+// WxWxidHasPrefix applies the HasPrefix predicate on the "wx_wxid" field.
+func WxWxidHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldWxWxid, v))
+}
+
+// WxWxidHasSuffix applies the HasSuffix predicate on the "wx_wxid" field.
+func WxWxidHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldWxWxid, v))
+}
+
+// WxWxidIsNil applies the IsNil predicate on the "wx_wxid" field.
+func WxWxidIsNil() predicate.Contact {
+	return predicate.Contact(sql.FieldIsNull(FieldWxWxid))
+}
+
+// WxWxidNotNil applies the NotNil predicate on the "wx_wxid" field.
+func WxWxidNotNil() predicate.Contact {
+	return predicate.Contact(sql.FieldNotNull(FieldWxWxid))
+}
+
+// WxWxidEqualFold applies the EqualFold predicate on the "wx_wxid" field.
+func WxWxidEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldWxWxid, v))
+}
+
+// WxWxidContainsFold applies the ContainsFold predicate on the "wx_wxid" field.
+func WxWxidContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldWxWxid, v))
+}
+
+// TypeEQ applies the EQ predicate on the "type" field.
+func TypeEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldType, v))
+}
+
+// TypeNEQ applies the NEQ predicate on the "type" field.
+func TypeNEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldType, v))
+}
+
+// TypeIn applies the In predicate on the "type" field.
+func TypeIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldType, vs...))
+}
+
+// TypeNotIn applies the NotIn predicate on the "type" field.
+func TypeNotIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldType, vs...))
+}
+
+// TypeGT applies the GT predicate on the "type" field.
+func TypeGT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldType, v))
+}
+
+// TypeGTE applies the GTE predicate on the "type" field.
+func TypeGTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldType, v))
+}
+
+// TypeLT applies the LT predicate on the "type" field.
+func TypeLT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldType, v))
+}
+
+// TypeLTE applies the LTE predicate on the "type" field.
+func TypeLTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldType, v))
+}
+
+// TypeIsNil applies the IsNil predicate on the "type" field.
+func TypeIsNil() predicate.Contact {
+	return predicate.Contact(sql.FieldIsNull(FieldType))
+}
+
+// TypeNotNil applies the NotNil predicate on the "type" field.
+func TypeNotNil() predicate.Contact {
+	return predicate.Contact(sql.FieldNotNull(FieldType))
+}
+
+// WxidEQ applies the EQ predicate on the "wxid" field.
+func WxidEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldWxid, v))
+}
+
+// WxidNEQ applies the NEQ predicate on the "wxid" field.
+func WxidNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldWxid, v))
+}
+
+// WxidIn applies the In predicate on the "wxid" field.
+func WxidIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldWxid, vs...))
+}
+
+// WxidNotIn applies the NotIn predicate on the "wxid" field.
+func WxidNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldWxid, vs...))
+}
+
+// WxidGT applies the GT predicate on the "wxid" field.
+func WxidGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldWxid, v))
+}
+
+// WxidGTE applies the GTE predicate on the "wxid" field.
+func WxidGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldWxid, v))
+}
+
+// WxidLT applies the LT predicate on the "wxid" field.
+func WxidLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldWxid, v))
+}
+
+// WxidLTE applies the LTE predicate on the "wxid" field.
+func WxidLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldWxid, v))
+}
+
+// WxidContains applies the Contains predicate on the "wxid" field.
+func WxidContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldWxid, v))
+}
+
+// WxidHasPrefix applies the HasPrefix predicate on the "wxid" field.
+func WxidHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldWxid, v))
+}
+
+// WxidHasSuffix applies the HasSuffix predicate on the "wxid" field.
+func WxidHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldWxid, v))
+}
+
+// WxidEqualFold applies the EqualFold predicate on the "wxid" field.
+func WxidEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldWxid, v))
+}
+
+// WxidContainsFold applies the ContainsFold predicate on the "wxid" field.
+func WxidContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldWxid, v))
+}
+
+// AccountEQ applies the EQ predicate on the "account" field.
+func AccountEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldAccount, v))
+}
+
+// AccountNEQ applies the NEQ predicate on the "account" field.
+func AccountNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldAccount, v))
+}
+
+// AccountIn applies the In predicate on the "account" field.
+func AccountIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldAccount, vs...))
+}
+
+// AccountNotIn applies the NotIn predicate on the "account" field.
+func AccountNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldAccount, vs...))
+}
+
+// AccountGT applies the GT predicate on the "account" field.
+func AccountGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldAccount, v))
+}
+
+// AccountGTE applies the GTE predicate on the "account" field.
+func AccountGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldAccount, v))
+}
+
+// AccountLT applies the LT predicate on the "account" field.
+func AccountLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldAccount, v))
+}
+
+// AccountLTE applies the LTE predicate on the "account" field.
+func AccountLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldAccount, v))
+}
+
+// AccountContains applies the Contains predicate on the "account" field.
+func AccountContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldAccount, v))
+}
+
+// AccountHasPrefix applies the HasPrefix predicate on the "account" field.
+func AccountHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldAccount, v))
+}
+
+// AccountHasSuffix applies the HasSuffix predicate on the "account" field.
+func AccountHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldAccount, v))
+}
+
+// AccountEqualFold applies the EqualFold predicate on the "account" field.
+func AccountEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldAccount, v))
+}
+
+// AccountContainsFold applies the ContainsFold predicate on the "account" field.
+func AccountContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldAccount, v))
+}
+
+// NicknameEQ applies the EQ predicate on the "nickname" field.
+func NicknameEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldNickname, v))
+}
+
+// NicknameNEQ applies the NEQ predicate on the "nickname" field.
+func NicknameNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldNickname, v))
+}
+
+// NicknameIn applies the In predicate on the "nickname" field.
+func NicknameIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldNickname, vs...))
+}
+
+// NicknameNotIn applies the NotIn predicate on the "nickname" field.
+func NicknameNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldNickname, vs...))
+}
+
+// NicknameGT applies the GT predicate on the "nickname" field.
+func NicknameGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldNickname, v))
+}
+
+// NicknameGTE applies the GTE predicate on the "nickname" field.
+func NicknameGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldNickname, v))
+}
+
+// NicknameLT applies the LT predicate on the "nickname" field.
+func NicknameLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldNickname, v))
+}
+
+// NicknameLTE applies the LTE predicate on the "nickname" field.
+func NicknameLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldNickname, v))
+}
+
+// NicknameContains applies the Contains predicate on the "nickname" field.
+func NicknameContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldNickname, v))
+}
+
+// NicknameHasPrefix applies the HasPrefix predicate on the "nickname" field.
+func NicknameHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldNickname, v))
+}
+
+// NicknameHasSuffix applies the HasSuffix predicate on the "nickname" field.
+func NicknameHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldNickname, v))
+}
+
+// NicknameEqualFold applies the EqualFold predicate on the "nickname" field.
+func NicknameEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldNickname, v))
+}
+
+// NicknameContainsFold applies the ContainsFold predicate on the "nickname" field.
+func NicknameContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldNickname, v))
+}
+
+// MarknameEQ applies the EQ predicate on the "markname" field.
+func MarknameEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldMarkname, v))
+}
+
+// MarknameNEQ applies the NEQ predicate on the "markname" field.
+func MarknameNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldMarkname, v))
+}
+
+// MarknameIn applies the In predicate on the "markname" field.
+func MarknameIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldMarkname, vs...))
+}
+
+// MarknameNotIn applies the NotIn predicate on the "markname" field.
+func MarknameNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldMarkname, vs...))
+}
+
+// MarknameGT applies the GT predicate on the "markname" field.
+func MarknameGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldMarkname, v))
+}
+
+// MarknameGTE applies the GTE predicate on the "markname" field.
+func MarknameGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldMarkname, v))
+}
+
+// MarknameLT applies the LT predicate on the "markname" field.
+func MarknameLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldMarkname, v))
+}
+
+// MarknameLTE applies the LTE predicate on the "markname" field.
+func MarknameLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldMarkname, v))
+}
+
+// MarknameContains applies the Contains predicate on the "markname" field.
+func MarknameContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldMarkname, v))
+}
+
+// MarknameHasPrefix applies the HasPrefix predicate on the "markname" field.
+func MarknameHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldMarkname, v))
+}
+
+// MarknameHasSuffix applies the HasSuffix predicate on the "markname" field.
+func MarknameHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldMarkname, v))
+}
+
+// MarknameEqualFold applies the EqualFold predicate on the "markname" field.
+func MarknameEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldMarkname, v))
+}
+
+// MarknameContainsFold applies the ContainsFold predicate on the "markname" field.
+func MarknameContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldMarkname, v))
+}
+
+// HeadimgEQ applies the EQ predicate on the "headimg" field.
+func HeadimgEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldHeadimg, v))
+}
+
+// HeadimgNEQ applies the NEQ predicate on the "headimg" field.
+func HeadimgNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldHeadimg, v))
+}
+
+// HeadimgIn applies the In predicate on the "headimg" field.
+func HeadimgIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldHeadimg, vs...))
+}
+
+// HeadimgNotIn applies the NotIn predicate on the "headimg" field.
+func HeadimgNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldHeadimg, vs...))
+}
+
+// HeadimgGT applies the GT predicate on the "headimg" field.
+func HeadimgGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldHeadimg, v))
+}
+
+// HeadimgGTE applies the GTE predicate on the "headimg" field.
+func HeadimgGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldHeadimg, v))
+}
+
+// HeadimgLT applies the LT predicate on the "headimg" field.
+func HeadimgLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldHeadimg, v))
+}
+
+// HeadimgLTE applies the LTE predicate on the "headimg" field.
+func HeadimgLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldHeadimg, v))
+}
+
+// HeadimgContains applies the Contains predicate on the "headimg" field.
+func HeadimgContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldHeadimg, v))
+}
+
+// HeadimgHasPrefix applies the HasPrefix predicate on the "headimg" field.
+func HeadimgHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldHeadimg, v))
+}
+
+// HeadimgHasSuffix applies the HasSuffix predicate on the "headimg" field.
+func HeadimgHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldHeadimg, v))
+}
+
+// HeadimgEqualFold applies the EqualFold predicate on the "headimg" field.
+func HeadimgEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldHeadimg, v))
+}
+
+// HeadimgContainsFold applies the ContainsFold predicate on the "headimg" field.
+func HeadimgContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldHeadimg, v))
+}
+
+// SexEQ applies the EQ predicate on the "sex" field.
+func SexEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldSex, v))
+}
+
+// SexNEQ applies the NEQ predicate on the "sex" field.
+func SexNEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldSex, v))
+}
+
+// SexIn applies the In predicate on the "sex" field.
+func SexIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldSex, vs...))
+}
+
+// SexNotIn applies the NotIn predicate on the "sex" field.
+func SexNotIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldSex, vs...))
+}
+
+// SexGT applies the GT predicate on the "sex" field.
+func SexGT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldSex, v))
+}
+
+// SexGTE applies the GTE predicate on the "sex" field.
+func SexGTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldSex, v))
+}
+
+// SexLT applies the LT predicate on the "sex" field.
+func SexLT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldSex, v))
+}
+
+// SexLTE applies the LTE predicate on the "sex" field.
+func SexLTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldSex, v))
+}
+
+// StarroleEQ applies the EQ predicate on the "starrole" field.
+func StarroleEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldStarrole, v))
+}
+
+// StarroleNEQ applies the NEQ predicate on the "starrole" field.
+func StarroleNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldStarrole, v))
+}
+
+// StarroleIn applies the In predicate on the "starrole" field.
+func StarroleIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldStarrole, vs...))
+}
+
+// StarroleNotIn applies the NotIn predicate on the "starrole" field.
+func StarroleNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldStarrole, vs...))
+}
+
+// StarroleGT applies the GT predicate on the "starrole" field.
+func StarroleGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldStarrole, v))
+}
+
+// StarroleGTE applies the GTE predicate on the "starrole" field.
+func StarroleGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldStarrole, v))
+}
+
+// StarroleLT applies the LT predicate on the "starrole" field.
+func StarroleLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldStarrole, v))
+}
+
+// StarroleLTE applies the LTE predicate on the "starrole" field.
+func StarroleLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldStarrole, v))
+}
+
+// StarroleContains applies the Contains predicate on the "starrole" field.
+func StarroleContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldStarrole, v))
+}
+
+// StarroleHasPrefix applies the HasPrefix predicate on the "starrole" field.
+func StarroleHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldStarrole, v))
+}
+
+// StarroleHasSuffix applies the HasSuffix predicate on the "starrole" field.
+func StarroleHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldStarrole, v))
+}
+
+// StarroleEqualFold applies the EqualFold predicate on the "starrole" field.
+func StarroleEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldStarrole, v))
+}
+
+// StarroleContainsFold applies the ContainsFold predicate on the "starrole" field.
+func StarroleContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldStarrole, v))
+}
+
+// DontseeitEQ applies the EQ predicate on the "dontseeit" field.
+func DontseeitEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDontseeit, v))
+}
+
+// DontseeitNEQ applies the NEQ predicate on the "dontseeit" field.
+func DontseeitNEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldDontseeit, v))
+}
+
+// DontseeitIn applies the In predicate on the "dontseeit" field.
+func DontseeitIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldDontseeit, vs...))
+}
+
+// DontseeitNotIn applies the NotIn predicate on the "dontseeit" field.
+func DontseeitNotIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldDontseeit, vs...))
+}
+
+// DontseeitGT applies the GT predicate on the "dontseeit" field.
+func DontseeitGT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldDontseeit, v))
+}
+
+// DontseeitGTE applies the GTE predicate on the "dontseeit" field.
+func DontseeitGTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldDontseeit, v))
+}
+
+// DontseeitLT applies the LT predicate on the "dontseeit" field.
+func DontseeitLT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldDontseeit, v))
+}
+
+// DontseeitLTE applies the LTE predicate on the "dontseeit" field.
+func DontseeitLTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldDontseeit, v))
+}
+
+// DontseemeEQ applies the EQ predicate on the "dontseeme" field.
+func DontseemeEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldDontseeme, v))
+}
+
+// DontseemeNEQ applies the NEQ predicate on the "dontseeme" field.
+func DontseemeNEQ(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldDontseeme, v))
+}
+
+// DontseemeIn applies the In predicate on the "dontseeme" field.
+func DontseemeIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldDontseeme, vs...))
+}
+
+// DontseemeNotIn applies the NotIn predicate on the "dontseeme" field.
+func DontseemeNotIn(vs ...int) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldDontseeme, vs...))
+}
+
+// DontseemeGT applies the GT predicate on the "dontseeme" field.
+func DontseemeGT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldDontseeme, v))
+}
+
+// DontseemeGTE applies the GTE predicate on the "dontseeme" field.
+func DontseemeGTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldDontseeme, v))
+}
+
+// DontseemeLT applies the LT predicate on the "dontseeme" field.
+func DontseemeLT(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldDontseeme, v))
+}
+
+// DontseemeLTE applies the LTE predicate on the "dontseeme" field.
+func DontseemeLTE(v int) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldDontseeme, v))
+}
+
+// LagEQ applies the EQ predicate on the "lag" field.
+func LagEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldLag, v))
+}
+
+// LagNEQ applies the NEQ predicate on the "lag" field.
+func LagNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldLag, v))
+}
+
+// LagIn applies the In predicate on the "lag" field.
+func LagIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldLag, vs...))
+}
+
+// LagNotIn applies the NotIn predicate on the "lag" field.
+func LagNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldLag, vs...))
+}
+
+// LagGT applies the GT predicate on the "lag" field.
+func LagGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldLag, v))
+}
+
+// LagGTE applies the GTE predicate on the "lag" field.
+func LagGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldLag, v))
+}
+
+// LagLT applies the LT predicate on the "lag" field.
+func LagLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldLag, v))
+}
+
+// LagLTE applies the LTE predicate on the "lag" field.
+func LagLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldLag, v))
+}
+
+// LagContains applies the Contains predicate on the "lag" field.
+func LagContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldLag, v))
+}
+
+// LagHasPrefix applies the HasPrefix predicate on the "lag" field.
+func LagHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldLag, v))
+}
+
+// LagHasSuffix applies the HasSuffix predicate on the "lag" field.
+func LagHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldLag, v))
+}
+
+// LagEqualFold applies the EqualFold predicate on the "lag" field.
+func LagEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldLag, v))
+}
+
+// LagContainsFold applies the ContainsFold predicate on the "lag" field.
+func LagContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldLag, v))
+}
+
+// GidEQ applies the EQ predicate on the "gid" field.
+func GidEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldGid, v))
+}
+
+// GidNEQ applies the NEQ predicate on the "gid" field.
+func GidNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldGid, v))
+}
+
+// GidIn applies the In predicate on the "gid" field.
+func GidIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldGid, vs...))
+}
+
+// GidNotIn applies the NotIn predicate on the "gid" field.
+func GidNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldGid, vs...))
+}
+
+// GidGT applies the GT predicate on the "gid" field.
+func GidGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldGid, v))
+}
+
+// GidGTE applies the GTE predicate on the "gid" field.
+func GidGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldGid, v))
+}
+
+// GidLT applies the LT predicate on the "gid" field.
+func GidLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldGid, v))
+}
+
+// GidLTE applies the LTE predicate on the "gid" field.
+func GidLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldGid, v))
+}
+
+// GidContains applies the Contains predicate on the "gid" field.
+func GidContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldGid, v))
+}
+
+// GidHasPrefix applies the HasPrefix predicate on the "gid" field.
+func GidHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldGid, v))
+}
+
+// GidHasSuffix applies the HasSuffix predicate on the "gid" field.
+func GidHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldGid, v))
+}
+
+// GidEqualFold applies the EqualFold predicate on the "gid" field.
+func GidEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldGid, v))
+}
+
+// GidContainsFold applies the ContainsFold predicate on the "gid" field.
+func GidContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldGid, v))
+}
+
+// GnameEQ applies the EQ predicate on the "gname" field.
+func GnameEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldGname, v))
+}
+
+// GnameNEQ applies the NEQ predicate on the "gname" field.
+func GnameNEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldGname, v))
+}
+
+// GnameIn applies the In predicate on the "gname" field.
+func GnameIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldGname, vs...))
+}
+
+// GnameNotIn applies the NotIn predicate on the "gname" field.
+func GnameNotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldGname, vs...))
+}
+
+// GnameGT applies the GT predicate on the "gname" field.
+func GnameGT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldGname, v))
+}
+
+// GnameGTE applies the GTE predicate on the "gname" field.
+func GnameGTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldGname, v))
+}
+
+// GnameLT applies the LT predicate on the "gname" field.
+func GnameLT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldGname, v))
+}
+
+// GnameLTE applies the LTE predicate on the "gname" field.
+func GnameLTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldGname, v))
+}
+
+// GnameContains applies the Contains predicate on the "gname" field.
+func GnameContains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldGname, v))
+}
+
+// GnameHasPrefix applies the HasPrefix predicate on the "gname" field.
+func GnameHasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldGname, v))
+}
+
+// GnameHasSuffix applies the HasSuffix predicate on the "gname" field.
+func GnameHasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldGname, v))
+}
+
+// GnameEqualFold applies the EqualFold predicate on the "gname" field.
+func GnameEqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldGname, v))
+}
+
+// GnameContainsFold applies the ContainsFold predicate on the "gname" field.
+func GnameContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldGname, v))
+}
+
+// V3EQ applies the EQ predicate on the "v3" field.
+func V3EQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEQ(FieldV3, v))
+}
+
+// V3NEQ applies the NEQ predicate on the "v3" field.
+func V3NEQ(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldNEQ(FieldV3, v))
+}
+
+// V3In applies the In predicate on the "v3" field.
+func V3In(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldIn(FieldV3, vs...))
+}
+
+// V3NotIn applies the NotIn predicate on the "v3" field.
+func V3NotIn(vs ...string) predicate.Contact {
+	return predicate.Contact(sql.FieldNotIn(FieldV3, vs...))
+}
+
+// V3GT applies the GT predicate on the "v3" field.
+func V3GT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGT(FieldV3, v))
+}
+
+// V3GTE applies the GTE predicate on the "v3" field.
+func V3GTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldGTE(FieldV3, v))
+}
+
+// V3LT applies the LT predicate on the "v3" field.
+func V3LT(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLT(FieldV3, v))
+}
+
+// V3LTE applies the LTE predicate on the "v3" field.
+func V3LTE(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldLTE(FieldV3, v))
+}
+
+// V3Contains applies the Contains predicate on the "v3" field.
+func V3Contains(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContains(FieldV3, v))
+}
+
+// V3HasPrefix applies the HasPrefix predicate on the "v3" field.
+func V3HasPrefix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasPrefix(FieldV3, v))
+}
+
+// V3HasSuffix applies the HasSuffix predicate on the "v3" field.
+func V3HasSuffix(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldHasSuffix(FieldV3, v))
+}
+
+// V3EqualFold applies the EqualFold predicate on the "v3" field.
+func V3EqualFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldEqualFold(FieldV3, v))
+}
+
+// V3ContainsFold applies the ContainsFold predicate on the "v3" field.
+func V3ContainsFold(v string) predicate.Contact {
+	return predicate.Contact(sql.FieldContainsFold(FieldV3, v))
+}
+
+// And groups predicates with the AND operator between them.
+func And(predicates ...predicate.Contact) predicate.Contact {
+	return predicate.Contact(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Contact) predicate.Contact {
+	return predicate.Contact(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Contact) predicate.Contact {
+	return predicate.Contact(sql.NotPredicates(p))
+}

+ 1812 - 0
ent/contact_create.go

@@ -0,0 +1,1812 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/contact"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// ContactCreate is the builder for creating a Contact entity.
+type ContactCreate struct {
+	config
+	mutation *ContactMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (cc *ContactCreate) SetCreatedAt(t time.Time) *ContactCreate {
+	cc.mutation.SetCreatedAt(t)
+	return cc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableCreatedAt(t *time.Time) *ContactCreate {
+	if t != nil {
+		cc.SetCreatedAt(*t)
+	}
+	return cc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (cc *ContactCreate) SetUpdatedAt(t time.Time) *ContactCreate {
+	cc.mutation.SetUpdatedAt(t)
+	return cc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableUpdatedAt(t *time.Time) *ContactCreate {
+	if t != nil {
+		cc.SetUpdatedAt(*t)
+	}
+	return cc
+}
+
+// SetStatus sets the "status" field.
+func (cc *ContactCreate) SetStatus(u uint8) *ContactCreate {
+	cc.mutation.SetStatus(u)
+	return cc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableStatus(u *uint8) *ContactCreate {
+	if u != nil {
+		cc.SetStatus(*u)
+	}
+	return cc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (cc *ContactCreate) SetDeletedAt(t time.Time) *ContactCreate {
+	cc.mutation.SetDeletedAt(t)
+	return cc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableDeletedAt(t *time.Time) *ContactCreate {
+	if t != nil {
+		cc.SetDeletedAt(*t)
+	}
+	return cc
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (cc *ContactCreate) SetWxWxid(s string) *ContactCreate {
+	cc.mutation.SetWxWxid(s)
+	return cc
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableWxWxid(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetWxWxid(*s)
+	}
+	return cc
+}
+
+// SetType sets the "type" field.
+func (cc *ContactCreate) SetType(i int) *ContactCreate {
+	cc.mutation.SetType(i)
+	return cc
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableType(i *int) *ContactCreate {
+	if i != nil {
+		cc.SetType(*i)
+	}
+	return cc
+}
+
+// SetWxid sets the "wxid" field.
+func (cc *ContactCreate) SetWxid(s string) *ContactCreate {
+	cc.mutation.SetWxid(s)
+	return cc
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableWxid(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetWxid(*s)
+	}
+	return cc
+}
+
+// SetAccount sets the "account" field.
+func (cc *ContactCreate) SetAccount(s string) *ContactCreate {
+	cc.mutation.SetAccount(s)
+	return cc
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableAccount(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetAccount(*s)
+	}
+	return cc
+}
+
+// SetNickname sets the "nickname" field.
+func (cc *ContactCreate) SetNickname(s string) *ContactCreate {
+	cc.mutation.SetNickname(s)
+	return cc
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableNickname(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetNickname(*s)
+	}
+	return cc
+}
+
+// SetMarkname sets the "markname" field.
+func (cc *ContactCreate) SetMarkname(s string) *ContactCreate {
+	cc.mutation.SetMarkname(s)
+	return cc
+}
+
+// SetNillableMarkname sets the "markname" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableMarkname(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetMarkname(*s)
+	}
+	return cc
+}
+
+// SetHeadimg sets the "headimg" field.
+func (cc *ContactCreate) SetHeadimg(s string) *ContactCreate {
+	cc.mutation.SetHeadimg(s)
+	return cc
+}
+
+// SetNillableHeadimg sets the "headimg" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableHeadimg(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetHeadimg(*s)
+	}
+	return cc
+}
+
+// SetSex sets the "sex" field.
+func (cc *ContactCreate) SetSex(i int) *ContactCreate {
+	cc.mutation.SetSex(i)
+	return cc
+}
+
+// SetNillableSex sets the "sex" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableSex(i *int) *ContactCreate {
+	if i != nil {
+		cc.SetSex(*i)
+	}
+	return cc
+}
+
+// SetStarrole sets the "starrole" field.
+func (cc *ContactCreate) SetStarrole(s string) *ContactCreate {
+	cc.mutation.SetStarrole(s)
+	return cc
+}
+
+// SetNillableStarrole sets the "starrole" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableStarrole(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetStarrole(*s)
+	}
+	return cc
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (cc *ContactCreate) SetDontseeit(i int) *ContactCreate {
+	cc.mutation.SetDontseeit(i)
+	return cc
+}
+
+// SetNillableDontseeit sets the "dontseeit" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableDontseeit(i *int) *ContactCreate {
+	if i != nil {
+		cc.SetDontseeit(*i)
+	}
+	return cc
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (cc *ContactCreate) SetDontseeme(i int) *ContactCreate {
+	cc.mutation.SetDontseeme(i)
+	return cc
+}
+
+// SetNillableDontseeme sets the "dontseeme" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableDontseeme(i *int) *ContactCreate {
+	if i != nil {
+		cc.SetDontseeme(*i)
+	}
+	return cc
+}
+
+// SetLag sets the "lag" field.
+func (cc *ContactCreate) SetLag(s string) *ContactCreate {
+	cc.mutation.SetLag(s)
+	return cc
+}
+
+// SetNillableLag sets the "lag" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableLag(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetLag(*s)
+	}
+	return cc
+}
+
+// SetGid sets the "gid" field.
+func (cc *ContactCreate) SetGid(s string) *ContactCreate {
+	cc.mutation.SetGid(s)
+	return cc
+}
+
+// SetNillableGid sets the "gid" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableGid(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetGid(*s)
+	}
+	return cc
+}
+
+// SetGname sets the "gname" field.
+func (cc *ContactCreate) SetGname(s string) *ContactCreate {
+	cc.mutation.SetGname(s)
+	return cc
+}
+
+// SetNillableGname sets the "gname" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableGname(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetGname(*s)
+	}
+	return cc
+}
+
+// SetV3 sets the "v3" field.
+func (cc *ContactCreate) SetV3(s string) *ContactCreate {
+	cc.mutation.SetV3(s)
+	return cc
+}
+
+// SetNillableV3 sets the "v3" field if the given value is not nil.
+func (cc *ContactCreate) SetNillableV3(s *string) *ContactCreate {
+	if s != nil {
+		cc.SetV3(*s)
+	}
+	return cc
+}
+
+// SetID sets the "id" field.
+func (cc *ContactCreate) SetID(u uint64) *ContactCreate {
+	cc.mutation.SetID(u)
+	return cc
+}
+
+// Mutation returns the ContactMutation object of the builder.
+func (cc *ContactCreate) Mutation() *ContactMutation {
+	return cc.mutation
+}
+
+// Save creates the Contact in the database.
+func (cc *ContactCreate) Save(ctx context.Context) (*Contact, error) {
+	if err := cc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, cc.sqlSave, cc.mutation, cc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (cc *ContactCreate) SaveX(ctx context.Context) *Contact {
+	v, err := cc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (cc *ContactCreate) Exec(ctx context.Context) error {
+	_, err := cc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (cc *ContactCreate) ExecX(ctx context.Context) {
+	if err := cc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (cc *ContactCreate) defaults() error {
+	if _, ok := cc.mutation.CreatedAt(); !ok {
+		if contact.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized contact.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := contact.DefaultCreatedAt()
+		cc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := cc.mutation.UpdatedAt(); !ok {
+		if contact.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized contact.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := contact.DefaultUpdatedAt()
+		cc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := cc.mutation.Status(); !ok {
+		v := contact.DefaultStatus
+		cc.mutation.SetStatus(v)
+	}
+	if _, ok := cc.mutation.WxWxid(); !ok {
+		v := contact.DefaultWxWxid
+		cc.mutation.SetWxWxid(v)
+	}
+	if _, ok := cc.mutation.GetType(); !ok {
+		v := contact.DefaultType
+		cc.mutation.SetType(v)
+	}
+	if _, ok := cc.mutation.Wxid(); !ok {
+		v := contact.DefaultWxid
+		cc.mutation.SetWxid(v)
+	}
+	if _, ok := cc.mutation.Account(); !ok {
+		v := contact.DefaultAccount
+		cc.mutation.SetAccount(v)
+	}
+	if _, ok := cc.mutation.Nickname(); !ok {
+		v := contact.DefaultNickname
+		cc.mutation.SetNickname(v)
+	}
+	if _, ok := cc.mutation.Markname(); !ok {
+		v := contact.DefaultMarkname
+		cc.mutation.SetMarkname(v)
+	}
+	if _, ok := cc.mutation.Headimg(); !ok {
+		v := contact.DefaultHeadimg
+		cc.mutation.SetHeadimg(v)
+	}
+	if _, ok := cc.mutation.Sex(); !ok {
+		v := contact.DefaultSex
+		cc.mutation.SetSex(v)
+	}
+	if _, ok := cc.mutation.Starrole(); !ok {
+		v := contact.DefaultStarrole
+		cc.mutation.SetStarrole(v)
+	}
+	if _, ok := cc.mutation.Dontseeit(); !ok {
+		v := contact.DefaultDontseeit
+		cc.mutation.SetDontseeit(v)
+	}
+	if _, ok := cc.mutation.Dontseeme(); !ok {
+		v := contact.DefaultDontseeme
+		cc.mutation.SetDontseeme(v)
+	}
+	if _, ok := cc.mutation.Lag(); !ok {
+		v := contact.DefaultLag
+		cc.mutation.SetLag(v)
+	}
+	if _, ok := cc.mutation.Gid(); !ok {
+		v := contact.DefaultGid
+		cc.mutation.SetGid(v)
+	}
+	if _, ok := cc.mutation.Gname(); !ok {
+		v := contact.DefaultGname
+		cc.mutation.SetGname(v)
+	}
+	if _, ok := cc.mutation.V3(); !ok {
+		v := contact.DefaultV3
+		cc.mutation.SetV3(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (cc *ContactCreate) check() error {
+	if _, ok := cc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Contact.created_at"`)}
+	}
+	if _, ok := cc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Contact.updated_at"`)}
+	}
+	if _, ok := cc.mutation.Wxid(); !ok {
+		return &ValidationError{Name: "wxid", err: errors.New(`ent: missing required field "Contact.wxid"`)}
+	}
+	if _, ok := cc.mutation.Account(); !ok {
+		return &ValidationError{Name: "account", err: errors.New(`ent: missing required field "Contact.account"`)}
+	}
+	if _, ok := cc.mutation.Nickname(); !ok {
+		return &ValidationError{Name: "nickname", err: errors.New(`ent: missing required field "Contact.nickname"`)}
+	}
+	if _, ok := cc.mutation.Markname(); !ok {
+		return &ValidationError{Name: "markname", err: errors.New(`ent: missing required field "Contact.markname"`)}
+	}
+	if _, ok := cc.mutation.Headimg(); !ok {
+		return &ValidationError{Name: "headimg", err: errors.New(`ent: missing required field "Contact.headimg"`)}
+	}
+	if _, ok := cc.mutation.Sex(); !ok {
+		return &ValidationError{Name: "sex", err: errors.New(`ent: missing required field "Contact.sex"`)}
+	}
+	if _, ok := cc.mutation.Starrole(); !ok {
+		return &ValidationError{Name: "starrole", err: errors.New(`ent: missing required field "Contact.starrole"`)}
+	}
+	if _, ok := cc.mutation.Dontseeit(); !ok {
+		return &ValidationError{Name: "dontseeit", err: errors.New(`ent: missing required field "Contact.dontseeit"`)}
+	}
+	if _, ok := cc.mutation.Dontseeme(); !ok {
+		return &ValidationError{Name: "dontseeme", err: errors.New(`ent: missing required field "Contact.dontseeme"`)}
+	}
+	if _, ok := cc.mutation.Lag(); !ok {
+		return &ValidationError{Name: "lag", err: errors.New(`ent: missing required field "Contact.lag"`)}
+	}
+	if _, ok := cc.mutation.Gid(); !ok {
+		return &ValidationError{Name: "gid", err: errors.New(`ent: missing required field "Contact.gid"`)}
+	}
+	if _, ok := cc.mutation.Gname(); !ok {
+		return &ValidationError{Name: "gname", err: errors.New(`ent: missing required field "Contact.gname"`)}
+	}
+	if _, ok := cc.mutation.V3(); !ok {
+		return &ValidationError{Name: "v3", err: errors.New(`ent: missing required field "Contact.v3"`)}
+	}
+	return nil
+}
+
+func (cc *ContactCreate) sqlSave(ctx context.Context) (*Contact, error) {
+	if err := cc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := cc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, cc.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)
+	}
+	cc.mutation.id = &_node.ID
+	cc.mutation.done = true
+	return _node, nil
+}
+
+func (cc *ContactCreate) createSpec() (*Contact, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Contact{config: cc.config}
+		_spec = sqlgraph.NewCreateSpec(contact.Table, sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = cc.conflict
+	if id, ok := cc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := cc.mutation.CreatedAt(); ok {
+		_spec.SetField(contact.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := cc.mutation.UpdatedAt(); ok {
+		_spec.SetField(contact.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := cc.mutation.Status(); ok {
+		_spec.SetField(contact.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := cc.mutation.DeletedAt(); ok {
+		_spec.SetField(contact.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if value, ok := cc.mutation.WxWxid(); ok {
+		_spec.SetField(contact.FieldWxWxid, field.TypeString, value)
+		_node.WxWxid = value
+	}
+	if value, ok := cc.mutation.GetType(); ok {
+		_spec.SetField(contact.FieldType, field.TypeInt, value)
+		_node.Type = value
+	}
+	if value, ok := cc.mutation.Wxid(); ok {
+		_spec.SetField(contact.FieldWxid, field.TypeString, value)
+		_node.Wxid = value
+	}
+	if value, ok := cc.mutation.Account(); ok {
+		_spec.SetField(contact.FieldAccount, field.TypeString, value)
+		_node.Account = value
+	}
+	if value, ok := cc.mutation.Nickname(); ok {
+		_spec.SetField(contact.FieldNickname, field.TypeString, value)
+		_node.Nickname = value
+	}
+	if value, ok := cc.mutation.Markname(); ok {
+		_spec.SetField(contact.FieldMarkname, field.TypeString, value)
+		_node.Markname = value
+	}
+	if value, ok := cc.mutation.Headimg(); ok {
+		_spec.SetField(contact.FieldHeadimg, field.TypeString, value)
+		_node.Headimg = value
+	}
+	if value, ok := cc.mutation.Sex(); ok {
+		_spec.SetField(contact.FieldSex, field.TypeInt, value)
+		_node.Sex = value
+	}
+	if value, ok := cc.mutation.Starrole(); ok {
+		_spec.SetField(contact.FieldStarrole, field.TypeString, value)
+		_node.Starrole = value
+	}
+	if value, ok := cc.mutation.Dontseeit(); ok {
+		_spec.SetField(contact.FieldDontseeit, field.TypeInt, value)
+		_node.Dontseeit = value
+	}
+	if value, ok := cc.mutation.Dontseeme(); ok {
+		_spec.SetField(contact.FieldDontseeme, field.TypeInt, value)
+		_node.Dontseeme = value
+	}
+	if value, ok := cc.mutation.Lag(); ok {
+		_spec.SetField(contact.FieldLag, field.TypeString, value)
+		_node.Lag = value
+	}
+	if value, ok := cc.mutation.Gid(); ok {
+		_spec.SetField(contact.FieldGid, field.TypeString, value)
+		_node.Gid = value
+	}
+	if value, ok := cc.mutation.Gname(); ok {
+		_spec.SetField(contact.FieldGname, field.TypeString, value)
+		_node.Gname = value
+	}
+	if value, ok := cc.mutation.V3(); ok {
+		_spec.SetField(contact.FieldV3, field.TypeString, value)
+		_node.V3 = value
+	}
+	return _node, _spec
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Contact.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.ContactUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (cc *ContactCreate) OnConflict(opts ...sql.ConflictOption) *ContactUpsertOne {
+	cc.conflict = opts
+	return &ContactUpsertOne{
+		create: cc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Contact.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (cc *ContactCreate) OnConflictColumns(columns ...string) *ContactUpsertOne {
+	cc.conflict = append(cc.conflict, sql.ConflictColumns(columns...))
+	return &ContactUpsertOne{
+		create: cc,
+	}
+}
+
+type (
+	// ContactUpsertOne is the builder for "upsert"-ing
+	//  one Contact node.
+	ContactUpsertOne struct {
+		create *ContactCreate
+	}
+
+	// ContactUpsert is the "OnConflict" setter.
+	ContactUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ContactUpsert) SetUpdatedAt(v time.Time) *ContactUpsert {
+	u.Set(contact.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateUpdatedAt() *ContactUpsert {
+	u.SetExcluded(contact.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *ContactUpsert) SetStatus(v uint8) *ContactUpsert {
+	u.Set(contact.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateStatus() *ContactUpsert {
+	u.SetExcluded(contact.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ContactUpsert) AddStatus(v uint8) *ContactUpsert {
+	u.Add(contact.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ContactUpsert) ClearStatus() *ContactUpsert {
+	u.SetNull(contact.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ContactUpsert) SetDeletedAt(v time.Time) *ContactUpsert {
+	u.Set(contact.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateDeletedAt() *ContactUpsert {
+	u.SetExcluded(contact.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ContactUpsert) ClearDeletedAt() *ContactUpsert {
+	u.SetNull(contact.FieldDeletedAt)
+	return u
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *ContactUpsert) SetWxWxid(v string) *ContactUpsert {
+	u.Set(contact.FieldWxWxid, v)
+	return u
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateWxWxid() *ContactUpsert {
+	u.SetExcluded(contact.FieldWxWxid)
+	return u
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *ContactUpsert) ClearWxWxid() *ContactUpsert {
+	u.SetNull(contact.FieldWxWxid)
+	return u
+}
+
+// SetType sets the "type" field.
+func (u *ContactUpsert) SetType(v int) *ContactUpsert {
+	u.Set(contact.FieldType, v)
+	return u
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateType() *ContactUpsert {
+	u.SetExcluded(contact.FieldType)
+	return u
+}
+
+// AddType adds v to the "type" field.
+func (u *ContactUpsert) AddType(v int) *ContactUpsert {
+	u.Add(contact.FieldType, v)
+	return u
+}
+
+// ClearType clears the value of the "type" field.
+func (u *ContactUpsert) ClearType() *ContactUpsert {
+	u.SetNull(contact.FieldType)
+	return u
+}
+
+// SetWxid sets the "wxid" field.
+func (u *ContactUpsert) SetWxid(v string) *ContactUpsert {
+	u.Set(contact.FieldWxid, v)
+	return u
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateWxid() *ContactUpsert {
+	u.SetExcluded(contact.FieldWxid)
+	return u
+}
+
+// SetAccount sets the "account" field.
+func (u *ContactUpsert) SetAccount(v string) *ContactUpsert {
+	u.Set(contact.FieldAccount, v)
+	return u
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateAccount() *ContactUpsert {
+	u.SetExcluded(contact.FieldAccount)
+	return u
+}
+
+// SetNickname sets the "nickname" field.
+func (u *ContactUpsert) SetNickname(v string) *ContactUpsert {
+	u.Set(contact.FieldNickname, v)
+	return u
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateNickname() *ContactUpsert {
+	u.SetExcluded(contact.FieldNickname)
+	return u
+}
+
+// SetMarkname sets the "markname" field.
+func (u *ContactUpsert) SetMarkname(v string) *ContactUpsert {
+	u.Set(contact.FieldMarkname, v)
+	return u
+}
+
+// UpdateMarkname sets the "markname" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateMarkname() *ContactUpsert {
+	u.SetExcluded(contact.FieldMarkname)
+	return u
+}
+
+// SetHeadimg sets the "headimg" field.
+func (u *ContactUpsert) SetHeadimg(v string) *ContactUpsert {
+	u.Set(contact.FieldHeadimg, v)
+	return u
+}
+
+// UpdateHeadimg sets the "headimg" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateHeadimg() *ContactUpsert {
+	u.SetExcluded(contact.FieldHeadimg)
+	return u
+}
+
+// SetSex sets the "sex" field.
+func (u *ContactUpsert) SetSex(v int) *ContactUpsert {
+	u.Set(contact.FieldSex, v)
+	return u
+}
+
+// UpdateSex sets the "sex" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateSex() *ContactUpsert {
+	u.SetExcluded(contact.FieldSex)
+	return u
+}
+
+// AddSex adds v to the "sex" field.
+func (u *ContactUpsert) AddSex(v int) *ContactUpsert {
+	u.Add(contact.FieldSex, v)
+	return u
+}
+
+// SetStarrole sets the "starrole" field.
+func (u *ContactUpsert) SetStarrole(v string) *ContactUpsert {
+	u.Set(contact.FieldStarrole, v)
+	return u
+}
+
+// UpdateStarrole sets the "starrole" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateStarrole() *ContactUpsert {
+	u.SetExcluded(contact.FieldStarrole)
+	return u
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (u *ContactUpsert) SetDontseeit(v int) *ContactUpsert {
+	u.Set(contact.FieldDontseeit, v)
+	return u
+}
+
+// UpdateDontseeit sets the "dontseeit" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateDontseeit() *ContactUpsert {
+	u.SetExcluded(contact.FieldDontseeit)
+	return u
+}
+
+// AddDontseeit adds v to the "dontseeit" field.
+func (u *ContactUpsert) AddDontseeit(v int) *ContactUpsert {
+	u.Add(contact.FieldDontseeit, v)
+	return u
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (u *ContactUpsert) SetDontseeme(v int) *ContactUpsert {
+	u.Set(contact.FieldDontseeme, v)
+	return u
+}
+
+// UpdateDontseeme sets the "dontseeme" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateDontseeme() *ContactUpsert {
+	u.SetExcluded(contact.FieldDontseeme)
+	return u
+}
+
+// AddDontseeme adds v to the "dontseeme" field.
+func (u *ContactUpsert) AddDontseeme(v int) *ContactUpsert {
+	u.Add(contact.FieldDontseeme, v)
+	return u
+}
+
+// SetLag sets the "lag" field.
+func (u *ContactUpsert) SetLag(v string) *ContactUpsert {
+	u.Set(contact.FieldLag, v)
+	return u
+}
+
+// UpdateLag sets the "lag" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateLag() *ContactUpsert {
+	u.SetExcluded(contact.FieldLag)
+	return u
+}
+
+// SetGid sets the "gid" field.
+func (u *ContactUpsert) SetGid(v string) *ContactUpsert {
+	u.Set(contact.FieldGid, v)
+	return u
+}
+
+// UpdateGid sets the "gid" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateGid() *ContactUpsert {
+	u.SetExcluded(contact.FieldGid)
+	return u
+}
+
+// SetGname sets the "gname" field.
+func (u *ContactUpsert) SetGname(v string) *ContactUpsert {
+	u.Set(contact.FieldGname, v)
+	return u
+}
+
+// UpdateGname sets the "gname" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateGname() *ContactUpsert {
+	u.SetExcluded(contact.FieldGname)
+	return u
+}
+
+// SetV3 sets the "v3" field.
+func (u *ContactUpsert) SetV3(v string) *ContactUpsert {
+	u.Set(contact.FieldV3, v)
+	return u
+}
+
+// UpdateV3 sets the "v3" field to the value that was provided on create.
+func (u *ContactUpsert) UpdateV3() *ContactUpsert {
+	u.SetExcluded(contact.FieldV3)
+	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.Contact.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(contact.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *ContactUpsertOne) UpdateNewValues() *ContactUpsertOne {
+	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(contact.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(contact.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Contact.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *ContactUpsertOne) Ignore() *ContactUpsertOne {
+	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 *ContactUpsertOne) DoNothing() *ContactUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the ContactCreate.OnConflict
+// documentation for more info.
+func (u *ContactUpsertOne) Update(set func(*ContactUpsert)) *ContactUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&ContactUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ContactUpsertOne) SetUpdatedAt(v time.Time) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateUpdatedAt() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *ContactUpsertOne) SetStatus(v uint8) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ContactUpsertOne) AddStatus(v uint8) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateStatus() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ContactUpsertOne) ClearStatus() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ContactUpsertOne) SetDeletedAt(v time.Time) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateDeletedAt() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ContactUpsertOne) ClearDeletedAt() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *ContactUpsertOne) SetWxWxid(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetWxWxid(v)
+	})
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateWxWxid() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateWxWxid()
+	})
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *ContactUpsertOne) ClearWxWxid() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearWxWxid()
+	})
+}
+
+// SetType sets the "type" field.
+func (u *ContactUpsertOne) SetType(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetType(v)
+	})
+}
+
+// AddType adds v to the "type" field.
+func (u *ContactUpsertOne) AddType(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddType(v)
+	})
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateType() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateType()
+	})
+}
+
+// ClearType clears the value of the "type" field.
+func (u *ContactUpsertOne) ClearType() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearType()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *ContactUpsertOne) SetWxid(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateWxid() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAccount sets the "account" field.
+func (u *ContactUpsertOne) SetAccount(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetAccount(v)
+	})
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateAccount() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateAccount()
+	})
+}
+
+// SetNickname sets the "nickname" field.
+func (u *ContactUpsertOne) SetNickname(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetNickname(v)
+	})
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateNickname() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateNickname()
+	})
+}
+
+// SetMarkname sets the "markname" field.
+func (u *ContactUpsertOne) SetMarkname(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetMarkname(v)
+	})
+}
+
+// UpdateMarkname sets the "markname" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateMarkname() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateMarkname()
+	})
+}
+
+// SetHeadimg sets the "headimg" field.
+func (u *ContactUpsertOne) SetHeadimg(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetHeadimg(v)
+	})
+}
+
+// UpdateHeadimg sets the "headimg" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateHeadimg() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateHeadimg()
+	})
+}
+
+// SetSex sets the "sex" field.
+func (u *ContactUpsertOne) SetSex(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetSex(v)
+	})
+}
+
+// AddSex adds v to the "sex" field.
+func (u *ContactUpsertOne) AddSex(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddSex(v)
+	})
+}
+
+// UpdateSex sets the "sex" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateSex() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateSex()
+	})
+}
+
+// SetStarrole sets the "starrole" field.
+func (u *ContactUpsertOne) SetStarrole(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetStarrole(v)
+	})
+}
+
+// UpdateStarrole sets the "starrole" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateStarrole() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateStarrole()
+	})
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (u *ContactUpsertOne) SetDontseeit(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDontseeit(v)
+	})
+}
+
+// AddDontseeit adds v to the "dontseeit" field.
+func (u *ContactUpsertOne) AddDontseeit(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddDontseeit(v)
+	})
+}
+
+// UpdateDontseeit sets the "dontseeit" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateDontseeit() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDontseeit()
+	})
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (u *ContactUpsertOne) SetDontseeme(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDontseeme(v)
+	})
+}
+
+// AddDontseeme adds v to the "dontseeme" field.
+func (u *ContactUpsertOne) AddDontseeme(v int) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddDontseeme(v)
+	})
+}
+
+// UpdateDontseeme sets the "dontseeme" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateDontseeme() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDontseeme()
+	})
+}
+
+// SetLag sets the "lag" field.
+func (u *ContactUpsertOne) SetLag(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetLag(v)
+	})
+}
+
+// UpdateLag sets the "lag" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateLag() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateLag()
+	})
+}
+
+// SetGid sets the "gid" field.
+func (u *ContactUpsertOne) SetGid(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetGid(v)
+	})
+}
+
+// UpdateGid sets the "gid" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateGid() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateGid()
+	})
+}
+
+// SetGname sets the "gname" field.
+func (u *ContactUpsertOne) SetGname(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetGname(v)
+	})
+}
+
+// UpdateGname sets the "gname" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateGname() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateGname()
+	})
+}
+
+// SetV3 sets the "v3" field.
+func (u *ContactUpsertOne) SetV3(v string) *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetV3(v)
+	})
+}
+
+// UpdateV3 sets the "v3" field to the value that was provided on create.
+func (u *ContactUpsertOne) UpdateV3() *ContactUpsertOne {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateV3()
+	})
+}
+
+// Exec executes the query.
+func (u *ContactUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for ContactCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *ContactUpsertOne) 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 *ContactUpsertOne) 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 *ContactUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// ContactCreateBulk is the builder for creating many Contact entities in bulk.
+type ContactCreateBulk struct {
+	config
+	err      error
+	builders []*ContactCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Contact entities in the database.
+func (ccb *ContactCreateBulk) Save(ctx context.Context) ([]*Contact, error) {
+	if ccb.err != nil {
+		return nil, ccb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(ccb.builders))
+	nodes := make([]*Contact, len(ccb.builders))
+	mutators := make([]Mutator, len(ccb.builders))
+	for i := range ccb.builders {
+		func(i int, root context.Context) {
+			builder := ccb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*ContactMutation)
+				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, ccb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = ccb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, ccb.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, ccb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (ccb *ContactCreateBulk) SaveX(ctx context.Context) []*Contact {
+	v, err := ccb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (ccb *ContactCreateBulk) Exec(ctx context.Context) error {
+	_, err := ccb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (ccb *ContactCreateBulk) ExecX(ctx context.Context) {
+	if err := ccb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Contact.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.ContactUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (ccb *ContactCreateBulk) OnConflict(opts ...sql.ConflictOption) *ContactUpsertBulk {
+	ccb.conflict = opts
+	return &ContactUpsertBulk{
+		create: ccb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Contact.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (ccb *ContactCreateBulk) OnConflictColumns(columns ...string) *ContactUpsertBulk {
+	ccb.conflict = append(ccb.conflict, sql.ConflictColumns(columns...))
+	return &ContactUpsertBulk{
+		create: ccb,
+	}
+}
+
+// ContactUpsertBulk is the builder for "upsert"-ing
+// a bulk of Contact nodes.
+type ContactUpsertBulk struct {
+	create *ContactCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Contact.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(contact.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *ContactUpsertBulk) UpdateNewValues() *ContactUpsertBulk {
+	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(contact.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(contact.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Contact.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *ContactUpsertBulk) Ignore() *ContactUpsertBulk {
+	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 *ContactUpsertBulk) DoNothing() *ContactUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the ContactCreateBulk.OnConflict
+// documentation for more info.
+func (u *ContactUpsertBulk) Update(set func(*ContactUpsert)) *ContactUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&ContactUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ContactUpsertBulk) SetUpdatedAt(v time.Time) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateUpdatedAt() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *ContactUpsertBulk) SetStatus(v uint8) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ContactUpsertBulk) AddStatus(v uint8) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateStatus() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ContactUpsertBulk) ClearStatus() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ContactUpsertBulk) SetDeletedAt(v time.Time) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateDeletedAt() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ContactUpsertBulk) ClearDeletedAt() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (u *ContactUpsertBulk) SetWxWxid(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetWxWxid(v)
+	})
+}
+
+// UpdateWxWxid sets the "wx_wxid" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateWxWxid() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateWxWxid()
+	})
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (u *ContactUpsertBulk) ClearWxWxid() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearWxWxid()
+	})
+}
+
+// SetType sets the "type" field.
+func (u *ContactUpsertBulk) SetType(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetType(v)
+	})
+}
+
+// AddType adds v to the "type" field.
+func (u *ContactUpsertBulk) AddType(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddType(v)
+	})
+}
+
+// UpdateType sets the "type" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateType() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateType()
+	})
+}
+
+// ClearType clears the value of the "type" field.
+func (u *ContactUpsertBulk) ClearType() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.ClearType()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *ContactUpsertBulk) SetWxid(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateWxid() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAccount sets the "account" field.
+func (u *ContactUpsertBulk) SetAccount(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetAccount(v)
+	})
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateAccount() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateAccount()
+	})
+}
+
+// SetNickname sets the "nickname" field.
+func (u *ContactUpsertBulk) SetNickname(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetNickname(v)
+	})
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateNickname() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateNickname()
+	})
+}
+
+// SetMarkname sets the "markname" field.
+func (u *ContactUpsertBulk) SetMarkname(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetMarkname(v)
+	})
+}
+
+// UpdateMarkname sets the "markname" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateMarkname() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateMarkname()
+	})
+}
+
+// SetHeadimg sets the "headimg" field.
+func (u *ContactUpsertBulk) SetHeadimg(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetHeadimg(v)
+	})
+}
+
+// UpdateHeadimg sets the "headimg" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateHeadimg() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateHeadimg()
+	})
+}
+
+// SetSex sets the "sex" field.
+func (u *ContactUpsertBulk) SetSex(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetSex(v)
+	})
+}
+
+// AddSex adds v to the "sex" field.
+func (u *ContactUpsertBulk) AddSex(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddSex(v)
+	})
+}
+
+// UpdateSex sets the "sex" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateSex() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateSex()
+	})
+}
+
+// SetStarrole sets the "starrole" field.
+func (u *ContactUpsertBulk) SetStarrole(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetStarrole(v)
+	})
+}
+
+// UpdateStarrole sets the "starrole" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateStarrole() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateStarrole()
+	})
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (u *ContactUpsertBulk) SetDontseeit(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDontseeit(v)
+	})
+}
+
+// AddDontseeit adds v to the "dontseeit" field.
+func (u *ContactUpsertBulk) AddDontseeit(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddDontseeit(v)
+	})
+}
+
+// UpdateDontseeit sets the "dontseeit" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateDontseeit() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDontseeit()
+	})
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (u *ContactUpsertBulk) SetDontseeme(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetDontseeme(v)
+	})
+}
+
+// AddDontseeme adds v to the "dontseeme" field.
+func (u *ContactUpsertBulk) AddDontseeme(v int) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.AddDontseeme(v)
+	})
+}
+
+// UpdateDontseeme sets the "dontseeme" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateDontseeme() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateDontseeme()
+	})
+}
+
+// SetLag sets the "lag" field.
+func (u *ContactUpsertBulk) SetLag(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetLag(v)
+	})
+}
+
+// UpdateLag sets the "lag" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateLag() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateLag()
+	})
+}
+
+// SetGid sets the "gid" field.
+func (u *ContactUpsertBulk) SetGid(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetGid(v)
+	})
+}
+
+// UpdateGid sets the "gid" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateGid() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateGid()
+	})
+}
+
+// SetGname sets the "gname" field.
+func (u *ContactUpsertBulk) SetGname(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetGname(v)
+	})
+}
+
+// UpdateGname sets the "gname" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateGname() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateGname()
+	})
+}
+
+// SetV3 sets the "v3" field.
+func (u *ContactUpsertBulk) SetV3(v string) *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.SetV3(v)
+	})
+}
+
+// UpdateV3 sets the "v3" field to the value that was provided on create.
+func (u *ContactUpsertBulk) UpdateV3() *ContactUpsertBulk {
+	return u.Update(func(s *ContactUpsert) {
+		s.UpdateV3()
+	})
+}
+
+// Exec executes the query.
+func (u *ContactUpsertBulk) 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 ContactCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for ContactCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *ContactUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/contact_delete.go

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

+ 526 - 0
ent/contact_query.go

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

+ 974 - 0
ent/contact_update.go

@@ -0,0 +1,974 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/predicate"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// ContactUpdate is the builder for updating Contact entities.
+type ContactUpdate struct {
+	config
+	hooks    []Hook
+	mutation *ContactMutation
+}
+
+// Where appends a list predicates to the ContactUpdate builder.
+func (cu *ContactUpdate) Where(ps ...predicate.Contact) *ContactUpdate {
+	cu.mutation.Where(ps...)
+	return cu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (cu *ContactUpdate) SetUpdatedAt(t time.Time) *ContactUpdate {
+	cu.mutation.SetUpdatedAt(t)
+	return cu
+}
+
+// SetStatus sets the "status" field.
+func (cu *ContactUpdate) SetStatus(u uint8) *ContactUpdate {
+	cu.mutation.ResetStatus()
+	cu.mutation.SetStatus(u)
+	return cu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableStatus(u *uint8) *ContactUpdate {
+	if u != nil {
+		cu.SetStatus(*u)
+	}
+	return cu
+}
+
+// AddStatus adds u to the "status" field.
+func (cu *ContactUpdate) AddStatus(u int8) *ContactUpdate {
+	cu.mutation.AddStatus(u)
+	return cu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (cu *ContactUpdate) ClearStatus() *ContactUpdate {
+	cu.mutation.ClearStatus()
+	return cu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (cu *ContactUpdate) SetDeletedAt(t time.Time) *ContactUpdate {
+	cu.mutation.SetDeletedAt(t)
+	return cu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableDeletedAt(t *time.Time) *ContactUpdate {
+	if t != nil {
+		cu.SetDeletedAt(*t)
+	}
+	return cu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (cu *ContactUpdate) ClearDeletedAt() *ContactUpdate {
+	cu.mutation.ClearDeletedAt()
+	return cu
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (cu *ContactUpdate) SetWxWxid(s string) *ContactUpdate {
+	cu.mutation.SetWxWxid(s)
+	return cu
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableWxWxid(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetWxWxid(*s)
+	}
+	return cu
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (cu *ContactUpdate) ClearWxWxid() *ContactUpdate {
+	cu.mutation.ClearWxWxid()
+	return cu
+}
+
+// SetType sets the "type" field.
+func (cu *ContactUpdate) SetType(i int) *ContactUpdate {
+	cu.mutation.ResetType()
+	cu.mutation.SetType(i)
+	return cu
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableType(i *int) *ContactUpdate {
+	if i != nil {
+		cu.SetType(*i)
+	}
+	return cu
+}
+
+// AddType adds i to the "type" field.
+func (cu *ContactUpdate) AddType(i int) *ContactUpdate {
+	cu.mutation.AddType(i)
+	return cu
+}
+
+// ClearType clears the value of the "type" field.
+func (cu *ContactUpdate) ClearType() *ContactUpdate {
+	cu.mutation.ClearType()
+	return cu
+}
+
+// SetWxid sets the "wxid" field.
+func (cu *ContactUpdate) SetWxid(s string) *ContactUpdate {
+	cu.mutation.SetWxid(s)
+	return cu
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableWxid(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetWxid(*s)
+	}
+	return cu
+}
+
+// SetAccount sets the "account" field.
+func (cu *ContactUpdate) SetAccount(s string) *ContactUpdate {
+	cu.mutation.SetAccount(s)
+	return cu
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableAccount(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetAccount(*s)
+	}
+	return cu
+}
+
+// SetNickname sets the "nickname" field.
+func (cu *ContactUpdate) SetNickname(s string) *ContactUpdate {
+	cu.mutation.SetNickname(s)
+	return cu
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableNickname(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetNickname(*s)
+	}
+	return cu
+}
+
+// SetMarkname sets the "markname" field.
+func (cu *ContactUpdate) SetMarkname(s string) *ContactUpdate {
+	cu.mutation.SetMarkname(s)
+	return cu
+}
+
+// SetNillableMarkname sets the "markname" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableMarkname(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetMarkname(*s)
+	}
+	return cu
+}
+
+// SetHeadimg sets the "headimg" field.
+func (cu *ContactUpdate) SetHeadimg(s string) *ContactUpdate {
+	cu.mutation.SetHeadimg(s)
+	return cu
+}
+
+// SetNillableHeadimg sets the "headimg" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableHeadimg(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetHeadimg(*s)
+	}
+	return cu
+}
+
+// SetSex sets the "sex" field.
+func (cu *ContactUpdate) SetSex(i int) *ContactUpdate {
+	cu.mutation.ResetSex()
+	cu.mutation.SetSex(i)
+	return cu
+}
+
+// SetNillableSex sets the "sex" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableSex(i *int) *ContactUpdate {
+	if i != nil {
+		cu.SetSex(*i)
+	}
+	return cu
+}
+
+// AddSex adds i to the "sex" field.
+func (cu *ContactUpdate) AddSex(i int) *ContactUpdate {
+	cu.mutation.AddSex(i)
+	return cu
+}
+
+// SetStarrole sets the "starrole" field.
+func (cu *ContactUpdate) SetStarrole(s string) *ContactUpdate {
+	cu.mutation.SetStarrole(s)
+	return cu
+}
+
+// SetNillableStarrole sets the "starrole" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableStarrole(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetStarrole(*s)
+	}
+	return cu
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (cu *ContactUpdate) SetDontseeit(i int) *ContactUpdate {
+	cu.mutation.ResetDontseeit()
+	cu.mutation.SetDontseeit(i)
+	return cu
+}
+
+// SetNillableDontseeit sets the "dontseeit" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableDontseeit(i *int) *ContactUpdate {
+	if i != nil {
+		cu.SetDontseeit(*i)
+	}
+	return cu
+}
+
+// AddDontseeit adds i to the "dontseeit" field.
+func (cu *ContactUpdate) AddDontseeit(i int) *ContactUpdate {
+	cu.mutation.AddDontseeit(i)
+	return cu
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (cu *ContactUpdate) SetDontseeme(i int) *ContactUpdate {
+	cu.mutation.ResetDontseeme()
+	cu.mutation.SetDontseeme(i)
+	return cu
+}
+
+// SetNillableDontseeme sets the "dontseeme" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableDontseeme(i *int) *ContactUpdate {
+	if i != nil {
+		cu.SetDontseeme(*i)
+	}
+	return cu
+}
+
+// AddDontseeme adds i to the "dontseeme" field.
+func (cu *ContactUpdate) AddDontseeme(i int) *ContactUpdate {
+	cu.mutation.AddDontseeme(i)
+	return cu
+}
+
+// SetLag sets the "lag" field.
+func (cu *ContactUpdate) SetLag(s string) *ContactUpdate {
+	cu.mutation.SetLag(s)
+	return cu
+}
+
+// SetNillableLag sets the "lag" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableLag(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetLag(*s)
+	}
+	return cu
+}
+
+// SetGid sets the "gid" field.
+func (cu *ContactUpdate) SetGid(s string) *ContactUpdate {
+	cu.mutation.SetGid(s)
+	return cu
+}
+
+// SetNillableGid sets the "gid" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableGid(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetGid(*s)
+	}
+	return cu
+}
+
+// SetGname sets the "gname" field.
+func (cu *ContactUpdate) SetGname(s string) *ContactUpdate {
+	cu.mutation.SetGname(s)
+	return cu
+}
+
+// SetNillableGname sets the "gname" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableGname(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetGname(*s)
+	}
+	return cu
+}
+
+// SetV3 sets the "v3" field.
+func (cu *ContactUpdate) SetV3(s string) *ContactUpdate {
+	cu.mutation.SetV3(s)
+	return cu
+}
+
+// SetNillableV3 sets the "v3" field if the given value is not nil.
+func (cu *ContactUpdate) SetNillableV3(s *string) *ContactUpdate {
+	if s != nil {
+		cu.SetV3(*s)
+	}
+	return cu
+}
+
+// Mutation returns the ContactMutation object of the builder.
+func (cu *ContactUpdate) Mutation() *ContactMutation {
+	return cu.mutation
+}
+
+// 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 {
+		return 0, err
+	}
+	return withHooks(ctx, cu.sqlSave, cu.mutation, cu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (cu *ContactUpdate) SaveX(ctx context.Context) int {
+	affected, err := cu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (cu *ContactUpdate) Exec(ctx context.Context) error {
+	_, err := cu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (cu *ContactUpdate) ExecX(ctx context.Context) {
+	if err := cu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (cu *ContactUpdate) defaults() error {
+	if _, ok := cu.mutation.UpdatedAt(); !ok {
+		if contact.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized contact.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := contact.UpdateDefaultUpdatedAt()
+		cu.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (cu *ContactUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	_spec := sqlgraph.NewUpdateSpec(contact.Table, contact.Columns, sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64))
+	if ps := cu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := cu.mutation.UpdatedAt(); ok {
+		_spec.SetField(contact.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := cu.mutation.Status(); ok {
+		_spec.SetField(contact.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := cu.mutation.AddedStatus(); ok {
+		_spec.AddField(contact.FieldStatus, field.TypeUint8, value)
+	}
+	if cu.mutation.StatusCleared() {
+		_spec.ClearField(contact.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := cu.mutation.DeletedAt(); ok {
+		_spec.SetField(contact.FieldDeletedAt, field.TypeTime, value)
+	}
+	if cu.mutation.DeletedAtCleared() {
+		_spec.ClearField(contact.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := cu.mutation.WxWxid(); ok {
+		_spec.SetField(contact.FieldWxWxid, field.TypeString, value)
+	}
+	if cu.mutation.WxWxidCleared() {
+		_spec.ClearField(contact.FieldWxWxid, field.TypeString)
+	}
+	if value, ok := cu.mutation.GetType(); ok {
+		_spec.SetField(contact.FieldType, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.AddedType(); ok {
+		_spec.AddField(contact.FieldType, field.TypeInt, value)
+	}
+	if cu.mutation.TypeCleared() {
+		_spec.ClearField(contact.FieldType, field.TypeInt)
+	}
+	if value, ok := cu.mutation.Wxid(); ok {
+		_spec.SetField(contact.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Account(); ok {
+		_spec.SetField(contact.FieldAccount, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Nickname(); ok {
+		_spec.SetField(contact.FieldNickname, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Markname(); ok {
+		_spec.SetField(contact.FieldMarkname, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Headimg(); ok {
+		_spec.SetField(contact.FieldHeadimg, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Sex(); ok {
+		_spec.SetField(contact.FieldSex, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.AddedSex(); ok {
+		_spec.AddField(contact.FieldSex, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.Starrole(); ok {
+		_spec.SetField(contact.FieldStarrole, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Dontseeit(); ok {
+		_spec.SetField(contact.FieldDontseeit, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.AddedDontseeit(); ok {
+		_spec.AddField(contact.FieldDontseeit, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.Dontseeme(); ok {
+		_spec.SetField(contact.FieldDontseeme, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.AddedDontseeme(); ok {
+		_spec.AddField(contact.FieldDontseeme, field.TypeInt, value)
+	}
+	if value, ok := cu.mutation.Lag(); ok {
+		_spec.SetField(contact.FieldLag, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Gid(); ok {
+		_spec.SetField(contact.FieldGid, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.Gname(); ok {
+		_spec.SetField(contact.FieldGname, field.TypeString, value)
+	}
+	if value, ok := cu.mutation.V3(); ok {
+		_spec.SetField(contact.FieldV3, field.TypeString, value)
+	}
+	if n, err = sqlgraph.UpdateNodes(ctx, cu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{contact.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	cu.mutation.done = true
+	return n, nil
+}
+
+// ContactUpdateOne is the builder for updating a single Contact entity.
+type ContactUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *ContactMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (cuo *ContactUpdateOne) SetUpdatedAt(t time.Time) *ContactUpdateOne {
+	cuo.mutation.SetUpdatedAt(t)
+	return cuo
+}
+
+// SetStatus sets the "status" field.
+func (cuo *ContactUpdateOne) SetStatus(u uint8) *ContactUpdateOne {
+	cuo.mutation.ResetStatus()
+	cuo.mutation.SetStatus(u)
+	return cuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableStatus(u *uint8) *ContactUpdateOne {
+	if u != nil {
+		cuo.SetStatus(*u)
+	}
+	return cuo
+}
+
+// AddStatus adds u to the "status" field.
+func (cuo *ContactUpdateOne) AddStatus(u int8) *ContactUpdateOne {
+	cuo.mutation.AddStatus(u)
+	return cuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (cuo *ContactUpdateOne) ClearStatus() *ContactUpdateOne {
+	cuo.mutation.ClearStatus()
+	return cuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (cuo *ContactUpdateOne) SetDeletedAt(t time.Time) *ContactUpdateOne {
+	cuo.mutation.SetDeletedAt(t)
+	return cuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableDeletedAt(t *time.Time) *ContactUpdateOne {
+	if t != nil {
+		cuo.SetDeletedAt(*t)
+	}
+	return cuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (cuo *ContactUpdateOne) ClearDeletedAt() *ContactUpdateOne {
+	cuo.mutation.ClearDeletedAt()
+	return cuo
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (cuo *ContactUpdateOne) SetWxWxid(s string) *ContactUpdateOne {
+	cuo.mutation.SetWxWxid(s)
+	return cuo
+}
+
+// SetNillableWxWxid sets the "wx_wxid" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableWxWxid(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetWxWxid(*s)
+	}
+	return cuo
+}
+
+// ClearWxWxid clears the value of the "wx_wxid" field.
+func (cuo *ContactUpdateOne) ClearWxWxid() *ContactUpdateOne {
+	cuo.mutation.ClearWxWxid()
+	return cuo
+}
+
+// SetType sets the "type" field.
+func (cuo *ContactUpdateOne) SetType(i int) *ContactUpdateOne {
+	cuo.mutation.ResetType()
+	cuo.mutation.SetType(i)
+	return cuo
+}
+
+// SetNillableType sets the "type" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableType(i *int) *ContactUpdateOne {
+	if i != nil {
+		cuo.SetType(*i)
+	}
+	return cuo
+}
+
+// AddType adds i to the "type" field.
+func (cuo *ContactUpdateOne) AddType(i int) *ContactUpdateOne {
+	cuo.mutation.AddType(i)
+	return cuo
+}
+
+// ClearType clears the value of the "type" field.
+func (cuo *ContactUpdateOne) ClearType() *ContactUpdateOne {
+	cuo.mutation.ClearType()
+	return cuo
+}
+
+// SetWxid sets the "wxid" field.
+func (cuo *ContactUpdateOne) SetWxid(s string) *ContactUpdateOne {
+	cuo.mutation.SetWxid(s)
+	return cuo
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableWxid(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetWxid(*s)
+	}
+	return cuo
+}
+
+// SetAccount sets the "account" field.
+func (cuo *ContactUpdateOne) SetAccount(s string) *ContactUpdateOne {
+	cuo.mutation.SetAccount(s)
+	return cuo
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableAccount(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetAccount(*s)
+	}
+	return cuo
+}
+
+// SetNickname sets the "nickname" field.
+func (cuo *ContactUpdateOne) SetNickname(s string) *ContactUpdateOne {
+	cuo.mutation.SetNickname(s)
+	return cuo
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableNickname(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetNickname(*s)
+	}
+	return cuo
+}
+
+// SetMarkname sets the "markname" field.
+func (cuo *ContactUpdateOne) SetMarkname(s string) *ContactUpdateOne {
+	cuo.mutation.SetMarkname(s)
+	return cuo
+}
+
+// SetNillableMarkname sets the "markname" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableMarkname(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetMarkname(*s)
+	}
+	return cuo
+}
+
+// SetHeadimg sets the "headimg" field.
+func (cuo *ContactUpdateOne) SetHeadimg(s string) *ContactUpdateOne {
+	cuo.mutation.SetHeadimg(s)
+	return cuo
+}
+
+// SetNillableHeadimg sets the "headimg" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableHeadimg(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetHeadimg(*s)
+	}
+	return cuo
+}
+
+// SetSex sets the "sex" field.
+func (cuo *ContactUpdateOne) SetSex(i int) *ContactUpdateOne {
+	cuo.mutation.ResetSex()
+	cuo.mutation.SetSex(i)
+	return cuo
+}
+
+// SetNillableSex sets the "sex" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableSex(i *int) *ContactUpdateOne {
+	if i != nil {
+		cuo.SetSex(*i)
+	}
+	return cuo
+}
+
+// AddSex adds i to the "sex" field.
+func (cuo *ContactUpdateOne) AddSex(i int) *ContactUpdateOne {
+	cuo.mutation.AddSex(i)
+	return cuo
+}
+
+// SetStarrole sets the "starrole" field.
+func (cuo *ContactUpdateOne) SetStarrole(s string) *ContactUpdateOne {
+	cuo.mutation.SetStarrole(s)
+	return cuo
+}
+
+// SetNillableStarrole sets the "starrole" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableStarrole(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetStarrole(*s)
+	}
+	return cuo
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (cuo *ContactUpdateOne) SetDontseeit(i int) *ContactUpdateOne {
+	cuo.mutation.ResetDontseeit()
+	cuo.mutation.SetDontseeit(i)
+	return cuo
+}
+
+// SetNillableDontseeit sets the "dontseeit" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableDontseeit(i *int) *ContactUpdateOne {
+	if i != nil {
+		cuo.SetDontseeit(*i)
+	}
+	return cuo
+}
+
+// AddDontseeit adds i to the "dontseeit" field.
+func (cuo *ContactUpdateOne) AddDontseeit(i int) *ContactUpdateOne {
+	cuo.mutation.AddDontseeit(i)
+	return cuo
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (cuo *ContactUpdateOne) SetDontseeme(i int) *ContactUpdateOne {
+	cuo.mutation.ResetDontseeme()
+	cuo.mutation.SetDontseeme(i)
+	return cuo
+}
+
+// SetNillableDontseeme sets the "dontseeme" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableDontseeme(i *int) *ContactUpdateOne {
+	if i != nil {
+		cuo.SetDontseeme(*i)
+	}
+	return cuo
+}
+
+// AddDontseeme adds i to the "dontseeme" field.
+func (cuo *ContactUpdateOne) AddDontseeme(i int) *ContactUpdateOne {
+	cuo.mutation.AddDontseeme(i)
+	return cuo
+}
+
+// SetLag sets the "lag" field.
+func (cuo *ContactUpdateOne) SetLag(s string) *ContactUpdateOne {
+	cuo.mutation.SetLag(s)
+	return cuo
+}
+
+// SetNillableLag sets the "lag" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableLag(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetLag(*s)
+	}
+	return cuo
+}
+
+// SetGid sets the "gid" field.
+func (cuo *ContactUpdateOne) SetGid(s string) *ContactUpdateOne {
+	cuo.mutation.SetGid(s)
+	return cuo
+}
+
+// SetNillableGid sets the "gid" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableGid(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetGid(*s)
+	}
+	return cuo
+}
+
+// SetGname sets the "gname" field.
+func (cuo *ContactUpdateOne) SetGname(s string) *ContactUpdateOne {
+	cuo.mutation.SetGname(s)
+	return cuo
+}
+
+// SetNillableGname sets the "gname" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableGname(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetGname(*s)
+	}
+	return cuo
+}
+
+// SetV3 sets the "v3" field.
+func (cuo *ContactUpdateOne) SetV3(s string) *ContactUpdateOne {
+	cuo.mutation.SetV3(s)
+	return cuo
+}
+
+// SetNillableV3 sets the "v3" field if the given value is not nil.
+func (cuo *ContactUpdateOne) SetNillableV3(s *string) *ContactUpdateOne {
+	if s != nil {
+		cuo.SetV3(*s)
+	}
+	return cuo
+}
+
+// Mutation returns the ContactMutation object of the builder.
+func (cuo *ContactUpdateOne) Mutation() *ContactMutation {
+	return cuo.mutation
+}
+
+// Where appends a list predicates to the ContactUpdate builder.
+func (cuo *ContactUpdateOne) Where(ps ...predicate.Contact) *ContactUpdateOne {
+	cuo.mutation.Where(ps...)
+	return cuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (cuo *ContactUpdateOne) Select(field string, fields ...string) *ContactUpdateOne {
+	cuo.fields = append([]string{field}, fields...)
+	return cuo
+}
+
+// Save executes the query and returns the updated Contact entity.
+func (cuo *ContactUpdateOne) Save(ctx context.Context) (*Contact, error) {
+	if err := cuo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, cuo.sqlSave, cuo.mutation, cuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (cuo *ContactUpdateOne) SaveX(ctx context.Context) *Contact {
+	node, err := cuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (cuo *ContactUpdateOne) Exec(ctx context.Context) error {
+	_, err := cuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (cuo *ContactUpdateOne) ExecX(ctx context.Context) {
+	if err := cuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (cuo *ContactUpdateOne) defaults() error {
+	if _, ok := cuo.mutation.UpdatedAt(); !ok {
+		if contact.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized contact.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := contact.UpdateDefaultUpdatedAt()
+		cuo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (cuo *ContactUpdateOne) sqlSave(ctx context.Context) (_node *Contact, err error) {
+	_spec := sqlgraph.NewUpdateSpec(contact.Table, contact.Columns, sqlgraph.NewFieldSpec(contact.FieldID, field.TypeUint64))
+	id, ok := cuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Contact.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := cuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, contact.FieldID)
+		for _, f := range fields {
+			if !contact.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != contact.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := cuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := cuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(contact.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := cuo.mutation.Status(); ok {
+		_spec.SetField(contact.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := cuo.mutation.AddedStatus(); ok {
+		_spec.AddField(contact.FieldStatus, field.TypeUint8, value)
+	}
+	if cuo.mutation.StatusCleared() {
+		_spec.ClearField(contact.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := cuo.mutation.DeletedAt(); ok {
+		_spec.SetField(contact.FieldDeletedAt, field.TypeTime, value)
+	}
+	if cuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(contact.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := cuo.mutation.WxWxid(); ok {
+		_spec.SetField(contact.FieldWxWxid, field.TypeString, value)
+	}
+	if cuo.mutation.WxWxidCleared() {
+		_spec.ClearField(contact.FieldWxWxid, field.TypeString)
+	}
+	if value, ok := cuo.mutation.GetType(); ok {
+		_spec.SetField(contact.FieldType, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.AddedType(); ok {
+		_spec.AddField(contact.FieldType, field.TypeInt, value)
+	}
+	if cuo.mutation.TypeCleared() {
+		_spec.ClearField(contact.FieldType, field.TypeInt)
+	}
+	if value, ok := cuo.mutation.Wxid(); ok {
+		_spec.SetField(contact.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Account(); ok {
+		_spec.SetField(contact.FieldAccount, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Nickname(); ok {
+		_spec.SetField(contact.FieldNickname, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Markname(); ok {
+		_spec.SetField(contact.FieldMarkname, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Headimg(); ok {
+		_spec.SetField(contact.FieldHeadimg, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Sex(); ok {
+		_spec.SetField(contact.FieldSex, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.AddedSex(); ok {
+		_spec.AddField(contact.FieldSex, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.Starrole(); ok {
+		_spec.SetField(contact.FieldStarrole, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Dontseeit(); ok {
+		_spec.SetField(contact.FieldDontseeit, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.AddedDontseeit(); ok {
+		_spec.AddField(contact.FieldDontseeit, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.Dontseeme(); ok {
+		_spec.SetField(contact.FieldDontseeme, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.AddedDontseeme(); ok {
+		_spec.AddField(contact.FieldDontseeme, field.TypeInt, value)
+	}
+	if value, ok := cuo.mutation.Lag(); ok {
+		_spec.SetField(contact.FieldLag, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Gid(); ok {
+		_spec.SetField(contact.FieldGid, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.Gname(); ok {
+		_spec.SetField(contact.FieldGname, field.TypeString, value)
+	}
+	if value, ok := cuo.mutation.V3(); ok {
+		_spec.SetField(contact.FieldV3, field.TypeString, value)
+	}
+	_node = &Contact{config: cuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, cuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{contact.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	cuo.mutation.done = true
+	return _node, nil
+}

+ 612 - 0
ent/ent.go

@@ -0,0 +1,612 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"sync"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+// ent aliases to avoid import conflicts in user's code.
+type (
+	Op            = ent.Op
+	Hook          = ent.Hook
+	Value         = ent.Value
+	Query         = ent.Query
+	QueryContext  = ent.QueryContext
+	Querier       = ent.Querier
+	QuerierFunc   = ent.QuerierFunc
+	Interceptor   = ent.Interceptor
+	InterceptFunc = ent.InterceptFunc
+	Traverser     = ent.Traverser
+	TraverseFunc  = ent.TraverseFunc
+	Policy        = ent.Policy
+	Mutator       = ent.Mutator
+	Mutation      = ent.Mutation
+	MutateFunc    = ent.MutateFunc
+)
+
+type clientCtxKey struct{}
+
+// FromContext returns a Client stored inside a context, or nil if there isn't one.
+func FromContext(ctx context.Context) *Client {
+	c, _ := ctx.Value(clientCtxKey{}).(*Client)
+	return c
+}
+
+// NewContext returns a new context with the given Client attached.
+func NewContext(parent context.Context, c *Client) context.Context {
+	return context.WithValue(parent, clientCtxKey{}, c)
+}
+
+type txCtxKey struct{}
+
+// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
+func TxFromContext(ctx context.Context) *Tx {
+	tx, _ := ctx.Value(txCtxKey{}).(*Tx)
+	return tx
+}
+
+// NewTxContext returns a new context with the given Tx attached.
+func NewTxContext(parent context.Context, tx *Tx) context.Context {
+	return context.WithValue(parent, txCtxKey{}, tx)
+}
+
+// OrderFunc applies an ordering on the sql selector.
+// Deprecated: Use Asc/Desc functions or the package builders instead.
+type OrderFunc func(*sql.Selector)
+
+var (
+	initCheck   sync.Once
+	columnCheck sql.ColumnCheck
+)
+
+// columnChecker checks if the column exists in the given table.
+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,
+		})
+	})
+	return columnCheck(table, column)
+}
+
+// Asc applies the given fields in ASC order.
+func Asc(fields ...string) func(*sql.Selector) {
+	return func(s *sql.Selector) {
+		for _, f := range fields {
+			if err := checkColumn(s.TableName(), f); err != nil {
+				s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
+			}
+			s.OrderBy(sql.Asc(s.C(f)))
+		}
+	}
+}
+
+// Desc applies the given fields in DESC order.
+func Desc(fields ...string) func(*sql.Selector) {
+	return func(s *sql.Selector) {
+		for _, f := range fields {
+			if err := checkColumn(s.TableName(), f); err != nil {
+				s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
+			}
+			s.OrderBy(sql.Desc(s.C(f)))
+		}
+	}
+}
+
+// AggregateFunc applies an aggregation step on the group-by traversal/selector.
+type AggregateFunc func(*sql.Selector) string
+
+// As is a pseudo aggregation function for renaming another other functions with custom names. For example:
+//
+//	GroupBy(field1, field2).
+//	Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")).
+//	Scan(ctx, &v)
+func As(fn AggregateFunc, end string) AggregateFunc {
+	return func(s *sql.Selector) string {
+		return sql.As(fn(s), end)
+	}
+}
+
+// Count applies the "count" aggregation function on each group.
+func Count() AggregateFunc {
+	return func(s *sql.Selector) string {
+		return sql.Count("*")
+	}
+}
+
+// Max applies the "max" aggregation function on the given field of each group.
+func Max(field string) AggregateFunc {
+	return func(s *sql.Selector) string {
+		if err := checkColumn(s.TableName(), field); err != nil {
+			s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
+			return ""
+		}
+		return sql.Max(s.C(field))
+	}
+}
+
+// Mean applies the "mean" aggregation function on the given field of each group.
+func Mean(field string) AggregateFunc {
+	return func(s *sql.Selector) string {
+		if err := checkColumn(s.TableName(), field); err != nil {
+			s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
+			return ""
+		}
+		return sql.Avg(s.C(field))
+	}
+}
+
+// Min applies the "min" aggregation function on the given field of each group.
+func Min(field string) AggregateFunc {
+	return func(s *sql.Selector) string {
+		if err := checkColumn(s.TableName(), field); err != nil {
+			s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
+			return ""
+		}
+		return sql.Min(s.C(field))
+	}
+}
+
+// Sum applies the "sum" aggregation function on the given field of each group.
+func Sum(field string) AggregateFunc {
+	return func(s *sql.Selector) string {
+		if err := checkColumn(s.TableName(), field); err != nil {
+			s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
+			return ""
+		}
+		return sql.Sum(s.C(field))
+	}
+}
+
+// ValidationError returns when validating a field or edge fails.
+type ValidationError struct {
+	Name string // Field or edge name.
+	err  error
+}
+
+// Error implements the error interface.
+func (e *ValidationError) Error() string {
+	return e.err.Error()
+}
+
+// Unwrap implements the errors.Wrapper interface.
+func (e *ValidationError) Unwrap() error {
+	return e.err
+}
+
+// IsValidationError returns a boolean indicating whether the error is a validation error.
+func IsValidationError(err error) bool {
+	if err == nil {
+		return false
+	}
+	var e *ValidationError
+	return errors.As(err, &e)
+}
+
+// NotFoundError returns when trying to fetch a specific entity and it was not found in the database.
+type NotFoundError struct {
+	label string
+}
+
+// Error implements the error interface.
+func (e *NotFoundError) Error() string {
+	return "ent: " + e.label + " not found"
+}
+
+// IsNotFound returns a boolean indicating whether the error is a not found error.
+func IsNotFound(err error) bool {
+	if err == nil {
+		return false
+	}
+	var e *NotFoundError
+	return errors.As(err, &e)
+}
+
+// MaskNotFound masks not found error.
+func MaskNotFound(err error) error {
+	if IsNotFound(err) {
+		return nil
+	}
+	return err
+}
+
+// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database.
+type NotSingularError struct {
+	label string
+}
+
+// Error implements the error interface.
+func (e *NotSingularError) Error() string {
+	return "ent: " + e.label + " not singular"
+}
+
+// IsNotSingular returns a boolean indicating whether the error is a not singular error.
+func IsNotSingular(err error) bool {
+	if err == nil {
+		return false
+	}
+	var e *NotSingularError
+	return errors.As(err, &e)
+}
+
+// NotLoadedError returns when trying to get a node that was not loaded by the query.
+type NotLoadedError struct {
+	edge string
+}
+
+// Error implements the error interface.
+func (e *NotLoadedError) Error() string {
+	return "ent: " + e.edge + " edge was not loaded"
+}
+
+// IsNotLoaded returns a boolean indicating whether the error is a not loaded error.
+func IsNotLoaded(err error) bool {
+	if err == nil {
+		return false
+	}
+	var e *NotLoadedError
+	return errors.As(err, &e)
+}
+
+// ConstraintError returns when trying to create/update one or more entities and
+// one or more of their constraints failed. For example, violation of edge or
+// field uniqueness.
+type ConstraintError struct {
+	msg  string
+	wrap error
+}
+
+// Error implements the error interface.
+func (e ConstraintError) Error() string {
+	return "ent: constraint failed: " + e.msg
+}
+
+// Unwrap implements the errors.Wrapper interface.
+func (e *ConstraintError) Unwrap() error {
+	return e.wrap
+}
+
+// IsConstraintError returns a boolean indicating whether the error is a constraint failure.
+func IsConstraintError(err error) bool {
+	if err == nil {
+		return false
+	}
+	var e *ConstraintError
+	return errors.As(err, &e)
+}
+
+// selector embedded by the different Select/GroupBy builders.
+type selector struct {
+	label string
+	flds  *[]string
+	fns   []AggregateFunc
+	scan  func(context.Context, any) error
+}
+
+// ScanX is like Scan, but panics if an error occurs.
+func (s *selector) ScanX(ctx context.Context, v any) {
+	if err := s.scan(ctx, v); err != nil {
+		panic(err)
+	}
+}
+
+// Strings returns list of strings from a selector. It is only allowed when selecting one field.
+func (s *selector) Strings(ctx context.Context) ([]string, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("ent: Strings is not achievable when selecting more than 1 field")
+	}
+	var v []string
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// StringsX is like Strings, but panics if an error occurs.
+func (s *selector) StringsX(ctx context.Context) []string {
+	v, err := s.Strings(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// String returns a single string from a selector. It is only allowed when selecting one field.
+func (s *selector) String(ctx context.Context) (_ string, err error) {
+	var v []string
+	if v, err = s.Strings(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("ent: Strings returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// StringX is like String, but panics if an error occurs.
+func (s *selector) StringX(ctx context.Context) string {
+	v, err := s.String(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Ints returns list of ints from a selector. It is only allowed when selecting one field.
+func (s *selector) Ints(ctx context.Context) ([]int, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("ent: Ints is not achievable when selecting more than 1 field")
+	}
+	var v []int
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// IntsX is like Ints, but panics if an error occurs.
+func (s *selector) IntsX(ctx context.Context) []int {
+	v, err := s.Ints(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Int returns a single int from a selector. It is only allowed when selecting one field.
+func (s *selector) Int(ctx context.Context) (_ int, err error) {
+	var v []int
+	if v, err = s.Ints(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("ent: Ints returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// IntX is like Int, but panics if an error occurs.
+func (s *selector) IntX(ctx context.Context) int {
+	v, err := s.Int(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
+func (s *selector) Float64s(ctx context.Context) ([]float64, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("ent: Float64s is not achievable when selecting more than 1 field")
+	}
+	var v []float64
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// Float64sX is like Float64s, but panics if an error occurs.
+func (s *selector) Float64sX(ctx context.Context) []float64 {
+	v, err := s.Float64s(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
+func (s *selector) Float64(ctx context.Context) (_ float64, err error) {
+	var v []float64
+	if v, err = s.Float64s(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("ent: Float64s returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// Float64X is like Float64, but panics if an error occurs.
+func (s *selector) Float64X(ctx context.Context) float64 {
+	v, err := s.Float64(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Bools returns list of bools from a selector. It is only allowed when selecting one field.
+func (s *selector) Bools(ctx context.Context) ([]bool, error) {
+	if len(*s.flds) > 1 {
+		return nil, errors.New("ent: Bools is not achievable when selecting more than 1 field")
+	}
+	var v []bool
+	if err := s.scan(ctx, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+// BoolsX is like Bools, but panics if an error occurs.
+func (s *selector) BoolsX(ctx context.Context) []bool {
+	v, err := s.Bools(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Bool returns a single bool from a selector. It is only allowed when selecting one field.
+func (s *selector) Bool(ctx context.Context) (_ bool, err error) {
+	var v []bool
+	if v, err = s.Bools(ctx); err != nil {
+		return
+	}
+	switch len(v) {
+	case 1:
+		return v[0], nil
+	case 0:
+		err = &NotFoundError{s.label}
+	default:
+		err = fmt.Errorf("ent: Bools returned %d results when one was expected", len(v))
+	}
+	return
+}
+
+// BoolX is like Bool, but panics if an error occurs.
+func (s *selector) BoolX(ctx context.Context) bool {
+	v, err := s.Bool(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// withHooks invokes the builder operation with the given hooks, if any.
+func withHooks[V Value, M any, PM interface {
+	*M
+	Mutation
+}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) {
+	if len(hooks) == 0 {
+		return exec(ctx)
+	}
+	var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+		mutationT, ok := any(m).(PM)
+		if !ok {
+			return nil, fmt.Errorf("unexpected mutation type %T", m)
+		}
+		// Set the mutation to the builder.
+		*mutation = *mutationT
+		return exec(ctx)
+	})
+	for i := len(hooks) - 1; i >= 0; i-- {
+		if hooks[i] == nil {
+			return value, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
+		}
+		mut = hooks[i](mut)
+	}
+	v, err := mut.Mutate(ctx, mutation)
+	if err != nil {
+		return value, err
+	}
+	nv, ok := v.(V)
+	if !ok {
+		return value, fmt.Errorf("unexpected node type %T returned from %T", v, mutation)
+	}
+	return nv, nil
+}
+
+// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist.
+func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context {
+	if ent.QueryFromContext(ctx) == nil {
+		qc.Op = op
+		ctx = ent.NewQueryContext(ctx, qc)
+	}
+	return ctx
+}
+
+func querierAll[V Value, Q interface {
+	sqlAll(context.Context, ...queryHook) (V, error)
+}]() Querier {
+	return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
+		query, ok := q.(Q)
+		if !ok {
+			return nil, fmt.Errorf("unexpected query type %T", q)
+		}
+		return query.sqlAll(ctx)
+	})
+}
+
+func querierCount[Q interface {
+	sqlCount(context.Context) (int, error)
+}]() Querier {
+	return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
+		query, ok := q.(Q)
+		if !ok {
+			return nil, fmt.Errorf("unexpected query type %T", q)
+		}
+		return query.sqlCount(ctx)
+	})
+}
+
+func withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) {
+	for i := len(inters) - 1; i >= 0; i-- {
+		qr = inters[i].Intercept(qr)
+	}
+	rv, err := qr.Query(ctx, q)
+	if err != nil {
+		return v, err
+	}
+	vt, ok := rv.(V)
+	if !ok {
+		return v, fmt.Errorf("unexpected type %T returned from %T. expected type: %T", vt, q, v)
+	}
+	return vt, nil
+}
+
+func scanWithInterceptors[Q1 ent.Query, Q2 interface {
+	sqlScan(context.Context, Q1, any) error
+}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error {
+	rv := reflect.ValueOf(v)
+	var qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
+		query, ok := q.(Q1)
+		if !ok {
+			return nil, fmt.Errorf("unexpected query type %T", q)
+		}
+		if err := selectOrGroup.sqlScan(ctx, query, v); err != nil {
+			return nil, err
+		}
+		if k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() {
+			return rv.Elem().Interface(), nil
+		}
+		return v, nil
+	})
+	for i := len(inters) - 1; i >= 0; i-- {
+		qr = inters[i].Intercept(qr)
+	}
+	vv, err := qr.Query(ctx, rootQuery)
+	if err != nil {
+		return err
+	}
+	switch rv2 := reflect.ValueOf(vv); {
+	case rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer:
+	case rv.Type() == rv2.Type():
+		rv.Elem().Set(rv2.Elem())
+	case rv.Elem().Type() == rv2.Type():
+		rv.Elem().Set(rv2)
+	}
+	return nil
+}
+
+// queryHook describes an internal hook for the different sqlAll methods.
+type queryHook func(context.Context, *sqlgraph.QuerySpec)

+ 84 - 0
ent/enttest/enttest.go

@@ -0,0 +1,84 @@
+// Code generated by ent, DO NOT EDIT.
+
+package enttest
+
+import (
+	"context"
+	"wechat-api/ent"
+	// required by schema hooks.
+	_ "wechat-api/ent/runtime"
+
+	"wechat-api/ent/migrate"
+
+	"entgo.io/ent/dialect/sql/schema"
+)
+
+type (
+	// TestingT is the interface that is shared between
+	// testing.T and testing.B and used by enttest.
+	TestingT interface {
+		FailNow()
+		Error(...any)
+	}
+
+	// Option configures client creation.
+	Option func(*options)
+
+	options struct {
+		opts        []ent.Option
+		migrateOpts []schema.MigrateOption
+	}
+)
+
+// WithOptions forwards options to client creation.
+func WithOptions(opts ...ent.Option) Option {
+	return func(o *options) {
+		o.opts = append(o.opts, opts...)
+	}
+}
+
+// WithMigrateOptions forwards options to auto migration.
+func WithMigrateOptions(opts ...schema.MigrateOption) Option {
+	return func(o *options) {
+		o.migrateOpts = append(o.migrateOpts, opts...)
+	}
+}
+
+func newOptions(opts []Option) *options {
+	o := &options{}
+	for _, opt := range opts {
+		opt(o)
+	}
+	return o
+}
+
+// Open calls ent.Open and auto-run migration.
+func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client {
+	o := newOptions(opts)
+	c, err := ent.Open(driverName, dataSourceName, o.opts...)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+	migrateSchema(t, c, o)
+	return c
+}
+
+// NewClient calls ent.NewClient and auto-run migration.
+func NewClient(t TestingT, opts ...Option) *ent.Client {
+	o := newOptions(opts)
+	c := ent.NewClient(o.opts...)
+	migrateSchema(t, c, o)
+	return c
+}
+func migrateSchema(t TestingT, c *ent.Client, o *options) {
+	tables, err := schema.CopyTables(migrate.Tables)
+	if err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+	if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil {
+		t.Error(err)
+		t.FailNow()
+	}
+}

+ 3 - 0
ent/generate.go

@@ -0,0 +1,3 @@
+package ent
+
+//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema

+ 222 - 0
ent/hook/hook.go

@@ -0,0 +1,222 @@
+// Code generated by ent, DO NOT EDIT.
+
+package hook
+
+import (
+	"context"
+	"fmt"
+	"wechat-api/ent"
+)
+
+// The ContactFunc type is an adapter to allow the use of ordinary
+// function as Contact mutator.
+type ContactFunc func(context.Context, *ent.ContactMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f ContactFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.ContactMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ContactMutation", 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)
+
+// Mutate calls f(ctx, m).
+func (f ServerFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.ServerMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ServerMutation", m)
+}
+
+// The WxFunc type is an adapter to allow the use of ordinary
+// function as Wx mutator.
+type WxFunc func(context.Context, *ent.WxMutation) (ent.Value, error)
+
+// Mutate calls f(ctx, m).
+func (f WxFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+	if mv, ok := m.(*ent.WxMutation); ok {
+		return f(ctx, mv)
+	}
+	return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.WxMutation", m)
+}
+
+// Condition is a hook condition function.
+type Condition func(context.Context, ent.Mutation) bool
+
+// And groups conditions with the AND operator.
+func And(first, second Condition, rest ...Condition) Condition {
+	return func(ctx context.Context, m ent.Mutation) bool {
+		if !first(ctx, m) || !second(ctx, m) {
+			return false
+		}
+		for _, cond := range rest {
+			if !cond(ctx, m) {
+				return false
+			}
+		}
+		return true
+	}
+}
+
+// Or groups conditions with the OR operator.
+func Or(first, second Condition, rest ...Condition) Condition {
+	return func(ctx context.Context, m ent.Mutation) bool {
+		if first(ctx, m) || second(ctx, m) {
+			return true
+		}
+		for _, cond := range rest {
+			if cond(ctx, m) {
+				return true
+			}
+		}
+		return false
+	}
+}
+
+// Not negates a given condition.
+func Not(cond Condition) Condition {
+	return func(ctx context.Context, m ent.Mutation) bool {
+		return !cond(ctx, m)
+	}
+}
+
+// HasOp is a condition testing mutation operation.
+func HasOp(op ent.Op) Condition {
+	return func(_ context.Context, m ent.Mutation) bool {
+		return m.Op().Is(op)
+	}
+}
+
+// HasAddedFields is a condition validating `.AddedField` on fields.
+func HasAddedFields(field string, fields ...string) Condition {
+	return func(_ context.Context, m ent.Mutation) bool {
+		if _, exists := m.AddedField(field); !exists {
+			return false
+		}
+		for _, field := range fields {
+			if _, exists := m.AddedField(field); !exists {
+				return false
+			}
+		}
+		return true
+	}
+}
+
+// HasClearedFields is a condition validating `.FieldCleared` on fields.
+func HasClearedFields(field string, fields ...string) Condition {
+	return func(_ context.Context, m ent.Mutation) bool {
+		if exists := m.FieldCleared(field); !exists {
+			return false
+		}
+		for _, field := range fields {
+			if exists := m.FieldCleared(field); !exists {
+				return false
+			}
+		}
+		return true
+	}
+}
+
+// HasFields is a condition validating `.Field` on fields.
+func HasFields(field string, fields ...string) Condition {
+	return func(_ context.Context, m ent.Mutation) bool {
+		if _, exists := m.Field(field); !exists {
+			return false
+		}
+		for _, field := range fields {
+			if _, exists := m.Field(field); !exists {
+				return false
+			}
+		}
+		return true
+	}
+}
+
+// If executes the given hook under condition.
+//
+//	hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))
+func If(hk ent.Hook, cond Condition) ent.Hook {
+	return func(next ent.Mutator) ent.Mutator {
+		return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
+			if cond(ctx, m) {
+				return hk(next).Mutate(ctx, m)
+			}
+			return next.Mutate(ctx, m)
+		})
+	}
+}
+
+// On executes the given hook only for the given operation.
+//
+//	hook.On(Log, ent.Delete|ent.Create)
+func On(hk ent.Hook, op ent.Op) ent.Hook {
+	return If(hk, HasOp(op))
+}
+
+// Unless skips the given hook only for the given operation.
+//
+//	hook.Unless(Log, ent.Update|ent.UpdateOne)
+func Unless(hk ent.Hook, op ent.Op) ent.Hook {
+	return If(hk, Not(HasOp(op)))
+}
+
+// FixedError is a hook returning a fixed error.
+func FixedError(err error) ent.Hook {
+	return func(ent.Mutator) ent.Mutator {
+		return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) {
+			return nil, err
+		})
+	}
+}
+
+// Reject returns a hook that rejects all operations that match op.
+//
+//	func (T) Hooks() []ent.Hook {
+//		return []ent.Hook{
+//			Reject(ent.Delete|ent.Update),
+//		}
+//	}
+func Reject(op ent.Op) ent.Hook {
+	hk := FixedError(fmt.Errorf("%s operation is not allowed", op))
+	return On(hk, op)
+}
+
+// Chain acts as a list of hooks and is effectively immutable.
+// Once created, it will always hold the same set of hooks in the same order.
+type Chain struct {
+	hooks []ent.Hook
+}
+
+// NewChain creates a new chain of hooks.
+func NewChain(hooks ...ent.Hook) Chain {
+	return Chain{append([]ent.Hook(nil), hooks...)}
+}
+
+// Hook chains the list of hooks and returns the final hook.
+func (c Chain) Hook() ent.Hook {
+	return func(mutator ent.Mutator) ent.Mutator {
+		for i := len(c.hooks) - 1; i >= 0; i-- {
+			mutator = c.hooks[i](mutator)
+		}
+		return mutator
+	}
+}
+
+// Append extends a chain, adding the specified hook
+// as the last ones in the mutation flow.
+func (c Chain) Append(hooks ...ent.Hook) Chain {
+	newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks))
+	newHooks = append(newHooks, c.hooks...)
+	newHooks = append(newHooks, hooks...)
+	return Chain{newHooks}
+}
+
+// Extend extends a chain, adding the specified chain
+// as the last ones in the mutation flow.
+func (c Chain) Extend(chain Chain) Chain {
+	return c.Append(chain.hooks...)
+}

+ 209 - 0
ent/intercept/intercept.go

@@ -0,0 +1,209 @@
+// Code generated by ent, DO NOT EDIT.
+
+package intercept
+
+import (
+	"context"
+	"fmt"
+	"wechat-api/ent"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent/dialect/sql"
+)
+
+// The Query interface represents an operation that queries a graph.
+// By using this interface, users can write generic code that manipulates
+// query builders of different types.
+type Query interface {
+	// Type returns the string representation of the query type.
+	Type() string
+	// Limit the number of records to be returned by this query.
+	Limit(int)
+	// Offset to start from.
+	Offset(int)
+	// Unique configures the query builder to filter duplicate records.
+	Unique(bool)
+	// Order specifies how the records should be ordered.
+	Order(...func(*sql.Selector))
+	// WhereP appends storage-level predicates to the query builder. Using this method, users
+	// can use type-assertion to append predicates that do not depend on any generated package.
+	WhereP(...func(*sql.Selector))
+}
+
+// The Func type is an adapter that allows ordinary functions to be used as interceptors.
+// Unlike traversal functions, interceptors are skipped during graph traversals. Note that the
+// implementation of Func is different from the one defined in entgo.io/ent.InterceptFunc.
+type Func func(context.Context, Query) error
+
+// Intercept calls f(ctx, q) and then applied the next Querier.
+func (f Func) Intercept(next ent.Querier) ent.Querier {
+	return ent.QuerierFunc(func(ctx context.Context, q ent.Query) (ent.Value, error) {
+		query, err := NewQuery(q)
+		if err != nil {
+			return nil, err
+		}
+		if err := f(ctx, query); err != nil {
+			return nil, err
+		}
+		return next.Query(ctx, q)
+	})
+}
+
+// The TraverseFunc type is an adapter to allow the use of ordinary function as Traverser.
+// If f is a function with the appropriate signature, TraverseFunc(f) is a Traverser that calls f.
+type TraverseFunc func(context.Context, Query) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseFunc) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseFunc) Traverse(ctx context.Context, q ent.Query) error {
+	query, err := NewQuery(q)
+	if err != nil {
+		return err
+	}
+	return f(ctx, query)
+}
+
+// The ContactFunc type is an adapter to allow the use of ordinary function as a Querier.
+type ContactFunc func(context.Context, *ent.ContactQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f ContactFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.ContactQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.ContactQuery", q)
+}
+
+// The TraverseContact type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseContact func(context.Context, *ent.ContactQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseContact) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseContact) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.ContactQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.ContactQuery", 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)
+
+// Query calls f(ctx, q).
+func (f ServerFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.ServerQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.ServerQuery", q)
+}
+
+// The TraverseServer type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseServer func(context.Context, *ent.ServerQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseServer) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseServer) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.ServerQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.ServerQuery", q)
+}
+
+// The WxFunc type is an adapter to allow the use of ordinary function as a Querier.
+type WxFunc func(context.Context, *ent.WxQuery) (ent.Value, error)
+
+// Query calls f(ctx, q).
+func (f WxFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
+	if q, ok := q.(*ent.WxQuery); ok {
+		return f(ctx, q)
+	}
+	return nil, fmt.Errorf("unexpected query type %T. expect *ent.WxQuery", q)
+}
+
+// The TraverseWx type is an adapter to allow the use of ordinary function as Traverser.
+type TraverseWx func(context.Context, *ent.WxQuery) error
+
+// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
+func (f TraverseWx) Intercept(next ent.Querier) ent.Querier {
+	return next
+}
+
+// Traverse calls f(ctx, q).
+func (f TraverseWx) Traverse(ctx context.Context, q ent.Query) error {
+	if q, ok := q.(*ent.WxQuery); ok {
+		return f(ctx, q)
+	}
+	return fmt.Errorf("unexpected query type %T. expect *ent.WxQuery", q)
+}
+
+// NewQuery returns the generic Query interface for the given typed query.
+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.ServerQuery:
+		return &query[*ent.ServerQuery, predicate.Server, server.OrderOption]{typ: ent.TypeServer, tq: q}, nil
+	case *ent.WxQuery:
+		return &query[*ent.WxQuery, predicate.Wx, wx.OrderOption]{typ: ent.TypeWx, tq: q}, nil
+	default:
+		return nil, fmt.Errorf("unknown query type %T", q)
+	}
+}
+
+type query[T any, P ~func(*sql.Selector), R ~func(*sql.Selector)] struct {
+	typ string
+	tq  interface {
+		Limit(int) T
+		Offset(int) T
+		Unique(bool) T
+		Order(...R) T
+		Where(...P) T
+	}
+}
+
+func (q query[T, P, R]) Type() string {
+	return q.typ
+}
+
+func (q query[T, P, R]) Limit(limit int) {
+	q.tq.Limit(limit)
+}
+
+func (q query[T, P, R]) Offset(offset int) {
+	q.tq.Offset(offset)
+}
+
+func (q query[T, P, R]) Unique(unique bool) {
+	q.tq.Unique(unique)
+}
+
+func (q query[T, P, R]) Order(orders ...func(*sql.Selector)) {
+	rs := make([]R, len(orders))
+	for i := range orders {
+		rs[i] = orders[i]
+	}
+	q.tq.Order(rs...)
+}
+
+func (q query[T, P, R]) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]P, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	q.tq.Where(p...)
+}

+ 64 - 0
ent/migrate/migrate.go

@@ -0,0 +1,64 @@
+// Code generated by ent, DO NOT EDIT.
+
+package migrate
+
+import (
+	"context"
+	"fmt"
+	"io"
+
+	"entgo.io/ent/dialect"
+	"entgo.io/ent/dialect/sql/schema"
+)
+
+var (
+	// WithGlobalUniqueID sets the universal ids options to the migration.
+	// If this option is enabled, ent migration will allocate a 1<<32 range
+	// for the ids of each entity (table).
+	// Note that this option cannot be applied on tables that already exist.
+	WithGlobalUniqueID = schema.WithGlobalUniqueID
+	// WithDropColumn sets the drop column option to the migration.
+	// If this option is enabled, ent migration will drop old columns
+	// that were used for both fields and edges. This defaults to false.
+	WithDropColumn = schema.WithDropColumn
+	// WithDropIndex sets the drop index option to the migration.
+	// If this option is enabled, ent migration will drop old indexes
+	// that were defined in the schema. This defaults to false.
+	// Note that unique constraints are defined using `UNIQUE INDEX`,
+	// and therefore, it's recommended to enable this option to get more
+	// flexibility in the schema changes.
+	WithDropIndex = schema.WithDropIndex
+	// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.
+	WithForeignKeys = schema.WithForeignKeys
+)
+
+// Schema is the API for creating, migrating and dropping a schema.
+type Schema struct {
+	drv dialect.Driver
+}
+
+// NewSchema creates a new schema client.
+func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} }
+
+// Create creates all schema resources.
+func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {
+	return Create(ctx, s, Tables, opts...)
+}
+
+// Create creates all table resources using the given schema driver.
+func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error {
+	migrate, err := schema.NewMigrate(s.drv, opts...)
+	if err != nil {
+		return fmt.Errorf("ent/migrate: %w", err)
+	}
+	return migrate.Create(ctx, tables...)
+}
+
+// WriteTo writes the schema changes to w instead of running them against the database.
+//
+//	if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil {
+//		log.Fatal(err)
+//	}
+func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {
+	return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...)
+}

+ 175 - 0
ent/migrate/schema.go

@@ -0,0 +1,175 @@
+// Code generated by ent, DO NOT EDIT.
+
+package migrate
+
+import (
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/dialect/sql/schema"
+	"entgo.io/ent/schema/field"
+)
+
+var (
+	// ContactColumns holds the columns for the "contact" table.
+	ContactColumns = []*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: "wx_wxid", Type: field.TypeString, Nullable: true, Comment: "属主微信id", Default: ""},
+		{Name: "type", Type: field.TypeInt, Nullable: true, Comment: "联系人类型:1好友,2群组,3公众号,4企业微信联系人", Default: 1},
+		{Name: "wxid", Type: field.TypeString, Comment: "微信id 公众号微信ID", Default: ""},
+		{Name: "account", Type: field.TypeString, Comment: "微信账号", Default: ""},
+		{Name: "nickname", Type: field.TypeString, Comment: "微信昵称 群备注名称", Default: ""},
+		{Name: "markname", Type: field.TypeString, Comment: "备注名", Default: ""},
+		{Name: "headimg", Type: field.TypeString, Comment: "头像", Default: ""},
+		{Name: "sex", Type: field.TypeInt, Comment: "性别 0未知 1男 2女", Default: 0},
+		{Name: "starrole", Type: field.TypeString, Comment: "星标 65/67=星标 1/3=未星标", Default: ""},
+		{Name: "dontseeit", Type: field.TypeInt, Comment: "不让他看我的朋友圈 0可以看 1不让看", Default: 0},
+		{Name: "dontseeme", Type: field.TypeInt, Comment: "不看他的朋友圈 0可以看 1不看 1=开启了不看他 128/129=仅聊天", Default: 0},
+		{Name: "lag", Type: field.TypeString, Comment: "所属标签id清单,多开会用逗号隔开", Default: ""},
+		{Name: "gid", Type: field.TypeString, Comment: "群组id", Default: ""},
+		{Name: "gname", Type: field.TypeString, Comment: "群组名称", Default: ""},
+		{Name: "v3", Type: field.TypeString, Comment: "v3数据", Default: ""},
+	}
+	// ContactTable holds the schema information for the "contact" table.
+	ContactTable = &schema.Table{
+		Name:       "contact",
+		Columns:    ContactColumns,
+		PrimaryKey: []*schema.Column{ContactColumns[0]},
+		Indexes: []*schema.Index{
+			{
+				Name:    "contact_wx_wxid_wxid",
+				Unique:  true,
+				Columns: []*schema.Column{ContactColumns[5], ContactColumns[7]},
+			},
+			{
+				Name:    "contact_wxid",
+				Unique:  false,
+				Columns: []*schema.Column{ContactColumns[7]},
+			},
+			{
+				Name:    "contact_type",
+				Unique:  false,
+				Columns: []*schema.Column{ContactColumns[6]},
+			},
+			{
+				Name:    "contact_gid",
+				Unique:  false,
+				Columns: []*schema.Column{ContactColumns[17]},
+			},
+		},
+	}
+	// ServerColumns holds the columns for the "server" table.
+	ServerColumns = []*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: "name", Type: field.TypeString, Comment: "名称"},
+		{Name: "public_ip", Type: field.TypeString, Comment: "公网ip"},
+		{Name: "private_ip", Type: field.TypeString, Comment: "内网ip"},
+		{Name: "admin_port", Type: field.TypeString, Comment: "管理端口"},
+	}
+	// ServerTable holds the schema information for the "server" table.
+	ServerTable = &schema.Table{
+		Name:       "server",
+		Columns:    ServerColumns,
+		PrimaryKey: []*schema.Column{ServerColumns[0]},
+		Indexes: []*schema.Index{
+			{
+				Name:    "server_name",
+				Unique:  false,
+				Columns: []*schema.Column{ServerColumns[5]},
+			},
+			{
+				Name:    "server_private_ip",
+				Unique:  false,
+				Columns: []*schema.Column{ServerColumns[7]},
+			},
+			{
+				Name:    "server_public_ip",
+				Unique:  true,
+				Columns: []*schema.Column{ServerColumns[6]},
+			},
+		},
+	}
+	// WxColumns holds the columns for the "wx" table.
+	WxColumns = []*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: "port", Type: field.TypeString, Comment: "端口号", Default: ""},
+		{Name: "process_id", Type: field.TypeString, Comment: "进程号", Default: ""},
+		{Name: "callback", Type: field.TypeString, Comment: "回调地址", Default: ""},
+		{Name: "wxid", Type: field.TypeString, Comment: "微信id", Default: ""},
+		{Name: "account", Type: field.TypeString, Comment: "微信账号", Default: ""},
+		{Name: "nickname", Type: field.TypeString, Comment: "微信昵称", Default: ""},
+		{Name: "tel", Type: field.TypeString, Comment: "手机号", Default: ""},
+		{Name: "head_big", Type: field.TypeString, Comment: "微信头像", Default: ""},
+		{Name: "server_id", Type: field.TypeUint64, Nullable: true, Comment: "服务器id", Default: 0},
+	}
+	// WxTable holds the schema information for the "wx" table.
+	WxTable = &schema.Table{
+		Name:       "wx",
+		Columns:    WxColumns,
+		PrimaryKey: []*schema.Column{WxColumns[0]},
+		ForeignKeys: []*schema.ForeignKey{
+			{
+				Symbol:     "wx_server_wxs",
+				Columns:    []*schema.Column{WxColumns[13]},
+				RefColumns: []*schema.Column{ServerColumns[0]},
+				OnDelete:   schema.SetNull,
+			},
+		},
+		Indexes: []*schema.Index{
+			{
+				Name:    "wx_server_id_port",
+				Unique:  true,
+				Columns: []*schema.Column{WxColumns[13], WxColumns[5]},
+			},
+			{
+				Name:    "wx_wxid",
+				Unique:  true,
+				Columns: []*schema.Column{WxColumns[8]},
+			},
+			{
+				Name:    "wx_account",
+				Unique:  false,
+				Columns: []*schema.Column{WxColumns[9]},
+			},
+			{
+				Name:    "wx_nickname",
+				Unique:  false,
+				Columns: []*schema.Column{WxColumns[10]},
+			},
+			{
+				Name:    "wx_tel",
+				Unique:  false,
+				Columns: []*schema.Column{WxColumns[11]},
+			},
+		},
+	}
+	// Tables holds all the tables in the schema.
+	Tables = []*schema.Table{
+		ContactTable,
+		ServerTable,
+		WxTable,
+	}
+)
+
+func init() {
+	ContactTable.Annotation = &entsql.Annotation{
+		Table: "contact",
+	}
+	ServerTable.Annotation = &entsql.Annotation{
+		Table: "server",
+	}
+	WxTable.ForeignKeys[0].RefTable = ServerTable
+	WxTable.Annotation = &entsql.Annotation{
+		Table: "wx",
+	}
+}

+ 3597 - 0
ent/mutation.go

@@ -0,0 +1,3597 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"sync"
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+const (
+	// Operation types.
+	OpCreate    = ent.OpCreate
+	OpDelete    = ent.OpDelete
+	OpDeleteOne = ent.OpDeleteOne
+	OpUpdate    = ent.OpUpdate
+	OpUpdateOne = ent.OpUpdateOne
+
+	// Node types.
+	TypeContact = "Contact"
+	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
+}
+
+var _ ent.Mutation = (*ContactMutation)(nil)
+
+// contactOption allows management of the mutation configuration using functional options.
+type contactOption func(*ContactMutation)
+
+// newContactMutation creates new mutation for the Contact entity.
+func newContactMutation(c config, op Op, opts ...contactOption) *ContactMutation {
+	m := &ContactMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeContact,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withContactID sets the ID field of the mutation.
+func withContactID(id uint64) contactOption {
+	return func(m *ContactMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Contact
+		)
+		m.oldValue = func(ctx context.Context) (*Contact, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Contact.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withContact sets the old Contact of the mutation.
+func withContact(node *Contact) contactOption {
+	return func(m *ContactMutation) {
+		m.oldValue = func(context.Context) (*Contact, 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 ContactMutation) 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 ContactMutation) 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 Contact entities.
+func (m *ContactMutation) 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 *ContactMutation) 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 *ContactMutation) 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().Contact.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 *ContactMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *ContactMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *ContactMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) 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 *ContactMutation) 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 *ContactMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[contact.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *ContactMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[contact.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *ContactMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, contact.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *ContactMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[contact.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *ContactMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[contact.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *ContactMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, contact.FieldDeletedAt)
+}
+
+// SetWxWxid sets the "wx_wxid" field.
+func (m *ContactMutation) SetWxWxid(s string) {
+	m.wx_wxid = &s
+}
+
+// WxWxid returns the value of the "wx_wxid" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) ClearWxWxid() {
+	m.wx_wxid = nil
+	m.clearedFields[contact.FieldWxWxid] = struct{}{}
+}
+
+// WxWxidCleared returns if the "wx_wxid" field was cleared in this mutation.
+func (m *ContactMutation) WxWxidCleared() bool {
+	_, ok := m.clearedFields[contact.FieldWxWxid]
+	return ok
+}
+
+// ResetWxWxid resets all changes to the "wx_wxid" field.
+func (m *ContactMutation) ResetWxWxid() {
+	m.wx_wxid = nil
+	delete(m.clearedFields, contact.FieldWxWxid)
+}
+
+// SetType sets the "type" field.
+func (m *ContactMutation) SetType(i int) {
+	m._type = &i
+	m.add_type = nil
+}
+
+// GetType returns the value of the "type" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) 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 *ContactMutation) AddedType() (r int, exists bool) {
+	v := m.add_type
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ClearType clears the value of the "type" field.
+func (m *ContactMutation) ClearType() {
+	m._type = nil
+	m.add_type = nil
+	m.clearedFields[contact.FieldType] = struct{}{}
+}
+
+// TypeCleared returns if the "type" field was cleared in this mutation.
+func (m *ContactMutation) TypeCleared() bool {
+	_, ok := m.clearedFields[contact.FieldType]
+	return ok
+}
+
+// ResetType resets all changes to the "type" field.
+func (m *ContactMutation) ResetType() {
+	m._type = nil
+	m.add_type = nil
+	delete(m.clearedFields, contact.FieldType)
+}
+
+// SetWxid sets the "wxid" field.
+func (m *ContactMutation) SetWxid(s string) {
+	m.wxid = &s
+}
+
+// Wxid returns the value of the "wxid" field in the mutation.
+func (m *ContactMutation) 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 Contact entity.
+// If the Contact 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 *ContactMutation) 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 *ContactMutation) ResetWxid() {
+	m.wxid = nil
+}
+
+// SetAccount sets the "account" field.
+func (m *ContactMutation) SetAccount(s string) {
+	m.account = &s
+}
+
+// Account returns the value of the "account" field in the mutation.
+func (m *ContactMutation) Account() (r string, exists bool) {
+	v := m.account
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAccount returns the old "account" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldAccount(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAccount is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAccount requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAccount: %w", err)
+	}
+	return oldValue.Account, nil
+}
+
+// ResetAccount resets all changes to the "account" field.
+func (m *ContactMutation) ResetAccount() {
+	m.account = nil
+}
+
+// SetNickname sets the "nickname" field.
+func (m *ContactMutation) SetNickname(s string) {
+	m.nickname = &s
+}
+
+// Nickname returns the value of the "nickname" field in the mutation.
+func (m *ContactMutation) Nickname() (r string, exists bool) {
+	v := m.nickname
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldNickname returns the old "nickname" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldNickname(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldNickname is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldNickname requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldNickname: %w", err)
+	}
+	return oldValue.Nickname, nil
+}
+
+// ResetNickname resets all changes to the "nickname" field.
+func (m *ContactMutation) ResetNickname() {
+	m.nickname = nil
+}
+
+// SetMarkname sets the "markname" field.
+func (m *ContactMutation) SetMarkname(s string) {
+	m.markname = &s
+}
+
+// Markname returns the value of the "markname" field in the mutation.
+func (m *ContactMutation) Markname() (r string, exists bool) {
+	v := m.markname
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldMarkname returns the old "markname" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldMarkname(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldMarkname is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldMarkname requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldMarkname: %w", err)
+	}
+	return oldValue.Markname, nil
+}
+
+// ResetMarkname resets all changes to the "markname" field.
+func (m *ContactMutation) ResetMarkname() {
+	m.markname = nil
+}
+
+// SetHeadimg sets the "headimg" field.
+func (m *ContactMutation) SetHeadimg(s string) {
+	m.headimg = &s
+}
+
+// Headimg returns the value of the "headimg" field in the mutation.
+func (m *ContactMutation) Headimg() (r string, exists bool) {
+	v := m.headimg
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldHeadimg returns the old "headimg" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldHeadimg(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldHeadimg is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldHeadimg requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldHeadimg: %w", err)
+	}
+	return oldValue.Headimg, nil
+}
+
+// ResetHeadimg resets all changes to the "headimg" field.
+func (m *ContactMutation) ResetHeadimg() {
+	m.headimg = nil
+}
+
+// SetSex sets the "sex" field.
+func (m *ContactMutation) SetSex(i int) {
+	m.sex = &i
+	m.addsex = nil
+}
+
+// Sex returns the value of the "sex" field in the mutation.
+func (m *ContactMutation) Sex() (r int, exists bool) {
+	v := m.sex
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldSex returns the old "sex" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldSex(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldSex is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldSex requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldSex: %w", err)
+	}
+	return oldValue.Sex, nil
+}
+
+// AddSex adds i to the "sex" field.
+func (m *ContactMutation) AddSex(i int) {
+	if m.addsex != nil {
+		*m.addsex += i
+	} else {
+		m.addsex = &i
+	}
+}
+
+// AddedSex returns the value that was added to the "sex" field in this mutation.
+func (m *ContactMutation) AddedSex() (r int, exists bool) {
+	v := m.addsex
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetSex resets all changes to the "sex" field.
+func (m *ContactMutation) ResetSex() {
+	m.sex = nil
+	m.addsex = nil
+}
+
+// SetStarrole sets the "starrole" field.
+func (m *ContactMutation) SetStarrole(s string) {
+	m.starrole = &s
+}
+
+// Starrole returns the value of the "starrole" field in the mutation.
+func (m *ContactMutation) Starrole() (r string, exists bool) {
+	v := m.starrole
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldStarrole returns the old "starrole" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldStarrole(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldStarrole is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldStarrole requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldStarrole: %w", err)
+	}
+	return oldValue.Starrole, nil
+}
+
+// ResetStarrole resets all changes to the "starrole" field.
+func (m *ContactMutation) ResetStarrole() {
+	m.starrole = nil
+}
+
+// SetDontseeit sets the "dontseeit" field.
+func (m *ContactMutation) SetDontseeit(i int) {
+	m.dontseeit = &i
+	m.adddontseeit = nil
+}
+
+// Dontseeit returns the value of the "dontseeit" field in the mutation.
+func (m *ContactMutation) Dontseeit() (r int, exists bool) {
+	v := m.dontseeit
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDontseeit returns the old "dontseeit" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldDontseeit(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDontseeit is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDontseeit requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDontseeit: %w", err)
+	}
+	return oldValue.Dontseeit, nil
+}
+
+// AddDontseeit adds i to the "dontseeit" field.
+func (m *ContactMutation) AddDontseeit(i int) {
+	if m.adddontseeit != nil {
+		*m.adddontseeit += i
+	} else {
+		m.adddontseeit = &i
+	}
+}
+
+// AddedDontseeit returns the value that was added to the "dontseeit" field in this mutation.
+func (m *ContactMutation) AddedDontseeit() (r int, exists bool) {
+	v := m.adddontseeit
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetDontseeit resets all changes to the "dontseeit" field.
+func (m *ContactMutation) ResetDontseeit() {
+	m.dontseeit = nil
+	m.adddontseeit = nil
+}
+
+// SetDontseeme sets the "dontseeme" field.
+func (m *ContactMutation) SetDontseeme(i int) {
+	m.dontseeme = &i
+	m.adddontseeme = nil
+}
+
+// Dontseeme returns the value of the "dontseeme" field in the mutation.
+func (m *ContactMutation) Dontseeme() (r int, exists bool) {
+	v := m.dontseeme
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldDontseeme returns the old "dontseeme" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldDontseeme(ctx context.Context) (v int, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldDontseeme is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldDontseeme requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldDontseeme: %w", err)
+	}
+	return oldValue.Dontseeme, nil
+}
+
+// AddDontseeme adds i to the "dontseeme" field.
+func (m *ContactMutation) AddDontseeme(i int) {
+	if m.adddontseeme != nil {
+		*m.adddontseeme += i
+	} else {
+		m.adddontseeme = &i
+	}
+}
+
+// AddedDontseeme returns the value that was added to the "dontseeme" field in this mutation.
+func (m *ContactMutation) AddedDontseeme() (r int, exists bool) {
+	v := m.adddontseeme
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// ResetDontseeme resets all changes to the "dontseeme" field.
+func (m *ContactMutation) ResetDontseeme() {
+	m.dontseeme = nil
+	m.adddontseeme = nil
+}
+
+// SetLag sets the "lag" field.
+func (m *ContactMutation) SetLag(s string) {
+	m.lag = &s
+}
+
+// Lag returns the value of the "lag" field in the mutation.
+func (m *ContactMutation) Lag() (r string, exists bool) {
+	v := m.lag
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldLag returns the old "lag" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldLag(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldLag is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldLag requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldLag: %w", err)
+	}
+	return oldValue.Lag, nil
+}
+
+// ResetLag resets all changes to the "lag" field.
+func (m *ContactMutation) ResetLag() {
+	m.lag = nil
+}
+
+// SetGid sets the "gid" field.
+func (m *ContactMutation) SetGid(s string) {
+	m.gid = &s
+}
+
+// Gid returns the value of the "gid" field in the mutation.
+func (m *ContactMutation) Gid() (r string, exists bool) {
+	v := m.gid
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldGid returns the old "gid" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldGid(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldGid is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldGid requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldGid: %w", err)
+	}
+	return oldValue.Gid, nil
+}
+
+// ResetGid resets all changes to the "gid" field.
+func (m *ContactMutation) ResetGid() {
+	m.gid = nil
+}
+
+// SetGname sets the "gname" field.
+func (m *ContactMutation) SetGname(s string) {
+	m.gname = &s
+}
+
+// Gname returns the value of the "gname" field in the mutation.
+func (m *ContactMutation) Gname() (r string, exists bool) {
+	v := m.gname
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldGname returns the old "gname" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldGname(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldGname is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldGname requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldGname: %w", err)
+	}
+	return oldValue.Gname, nil
+}
+
+// ResetGname resets all changes to the "gname" field.
+func (m *ContactMutation) ResetGname() {
+	m.gname = nil
+}
+
+// SetV3 sets the "v3" field.
+func (m *ContactMutation) SetV3(s string) {
+	m.v3 = &s
+}
+
+// V3 returns the value of the "v3" field in the mutation.
+func (m *ContactMutation) V3() (r string, exists bool) {
+	v := m.v3
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldV3 returns the old "v3" field's value of the Contact entity.
+// If the Contact 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 *ContactMutation) OldV3(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldV3 is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldV3 requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldV3: %w", err)
+	}
+	return oldValue.V3, nil
+}
+
+// ResetV3 resets all changes to the "v3" field.
+func (m *ContactMutation) ResetV3() {
+	m.v3 = nil
+}
+
+// Where appends a list predicates to the ContactMutation builder.
+func (m *ContactMutation) Where(ps ...predicate.Contact) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the ContactMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *ContactMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Contact, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *ContactMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *ContactMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Contact).
+func (m *ContactMutation) 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 *ContactMutation) Fields() []string {
+	fields := make([]string, 0, 19)
+	if m.created_at != nil {
+		fields = append(fields, contact.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, contact.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, contact.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, contact.FieldDeletedAt)
+	}
+	if m.wx_wxid != nil {
+		fields = append(fields, contact.FieldWxWxid)
+	}
+	if m._type != nil {
+		fields = append(fields, contact.FieldType)
+	}
+	if m.wxid != nil {
+		fields = append(fields, contact.FieldWxid)
+	}
+	if m.account != nil {
+		fields = append(fields, contact.FieldAccount)
+	}
+	if m.nickname != nil {
+		fields = append(fields, contact.FieldNickname)
+	}
+	if m.markname != nil {
+		fields = append(fields, contact.FieldMarkname)
+	}
+	if m.headimg != nil {
+		fields = append(fields, contact.FieldHeadimg)
+	}
+	if m.sex != nil {
+		fields = append(fields, contact.FieldSex)
+	}
+	if m.starrole != nil {
+		fields = append(fields, contact.FieldStarrole)
+	}
+	if m.dontseeit != nil {
+		fields = append(fields, contact.FieldDontseeit)
+	}
+	if m.dontseeme != nil {
+		fields = append(fields, contact.FieldDontseeme)
+	}
+	if m.lag != nil {
+		fields = append(fields, contact.FieldLag)
+	}
+	if m.gid != nil {
+		fields = append(fields, contact.FieldGid)
+	}
+	if m.gname != nil {
+		fields = append(fields, contact.FieldGname)
+	}
+	if m.v3 != nil {
+		fields = append(fields, contact.FieldV3)
+	}
+	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 *ContactMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case contact.FieldCreatedAt:
+		return m.CreatedAt()
+	case contact.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case contact.FieldStatus:
+		return m.Status()
+	case contact.FieldDeletedAt:
+		return m.DeletedAt()
+	case contact.FieldWxWxid:
+		return m.WxWxid()
+	case contact.FieldType:
+		return m.GetType()
+	case contact.FieldWxid:
+		return m.Wxid()
+	case contact.FieldAccount:
+		return m.Account()
+	case contact.FieldNickname:
+		return m.Nickname()
+	case contact.FieldMarkname:
+		return m.Markname()
+	case contact.FieldHeadimg:
+		return m.Headimg()
+	case contact.FieldSex:
+		return m.Sex()
+	case contact.FieldStarrole:
+		return m.Starrole()
+	case contact.FieldDontseeit:
+		return m.Dontseeit()
+	case contact.FieldDontseeme:
+		return m.Dontseeme()
+	case contact.FieldLag:
+		return m.Lag()
+	case contact.FieldGid:
+		return m.Gid()
+	case contact.FieldGname:
+		return m.Gname()
+	case contact.FieldV3:
+		return m.V3()
+	}
+	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 *ContactMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case contact.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case contact.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case contact.FieldStatus:
+		return m.OldStatus(ctx)
+	case contact.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case contact.FieldWxWxid:
+		return m.OldWxWxid(ctx)
+	case contact.FieldType:
+		return m.OldType(ctx)
+	case contact.FieldWxid:
+		return m.OldWxid(ctx)
+	case contact.FieldAccount:
+		return m.OldAccount(ctx)
+	case contact.FieldNickname:
+		return m.OldNickname(ctx)
+	case contact.FieldMarkname:
+		return m.OldMarkname(ctx)
+	case contact.FieldHeadimg:
+		return m.OldHeadimg(ctx)
+	case contact.FieldSex:
+		return m.OldSex(ctx)
+	case contact.FieldStarrole:
+		return m.OldStarrole(ctx)
+	case contact.FieldDontseeit:
+		return m.OldDontseeit(ctx)
+	case contact.FieldDontseeme:
+		return m.OldDontseeme(ctx)
+	case contact.FieldLag:
+		return m.OldLag(ctx)
+	case contact.FieldGid:
+		return m.OldGid(ctx)
+	case contact.FieldGname:
+		return m.OldGname(ctx)
+	case contact.FieldV3:
+		return m.OldV3(ctx)
+	}
+	return nil, fmt.Errorf("unknown Contact 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 *ContactMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case contact.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 contact.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 contact.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case contact.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 contact.FieldWxWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxWxid(v)
+		return nil
+	case contact.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetType(v)
+		return nil
+	case contact.FieldWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxid(v)
+		return nil
+	case contact.FieldAccount:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAccount(v)
+		return nil
+	case contact.FieldNickname:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetNickname(v)
+		return nil
+	case contact.FieldMarkname:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetMarkname(v)
+		return nil
+	case contact.FieldHeadimg:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetHeadimg(v)
+		return nil
+	case contact.FieldSex:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetSex(v)
+		return nil
+	case contact.FieldStarrole:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStarrole(v)
+		return nil
+	case contact.FieldDontseeit:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDontseeit(v)
+		return nil
+	case contact.FieldDontseeme:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetDontseeme(v)
+		return nil
+	case contact.FieldLag:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetLag(v)
+		return nil
+	case contact.FieldGid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetGid(v)
+		return nil
+	case contact.FieldGname:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetGname(v)
+		return nil
+	case contact.FieldV3:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetV3(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Contact field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *ContactMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, contact.FieldStatus)
+	}
+	if m.add_type != nil {
+		fields = append(fields, contact.FieldType)
+	}
+	if m.addsex != nil {
+		fields = append(fields, contact.FieldSex)
+	}
+	if m.adddontseeit != nil {
+		fields = append(fields, contact.FieldDontseeit)
+	}
+	if m.adddontseeme != nil {
+		fields = append(fields, contact.FieldDontseeme)
+	}
+	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 *ContactMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case contact.FieldStatus:
+		return m.AddedStatus()
+	case contact.FieldType:
+		return m.AddedType()
+	case contact.FieldSex:
+		return m.AddedSex()
+	case contact.FieldDontseeit:
+		return m.AddedDontseeit()
+	case contact.FieldDontseeme:
+		return m.AddedDontseeme()
+	}
+	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 *ContactMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case contact.FieldStatus:
+		v, ok := value.(int8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddStatus(v)
+		return nil
+	case contact.FieldType:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddType(v)
+		return nil
+	case contact.FieldSex:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddSex(v)
+		return nil
+	case contact.FieldDontseeit:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddDontseeit(v)
+		return nil
+	case contact.FieldDontseeme:
+		v, ok := value.(int)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.AddDontseeme(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Contact numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *ContactMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(contact.FieldStatus) {
+		fields = append(fields, contact.FieldStatus)
+	}
+	if m.FieldCleared(contact.FieldDeletedAt) {
+		fields = append(fields, contact.FieldDeletedAt)
+	}
+	if m.FieldCleared(contact.FieldWxWxid) {
+		fields = append(fields, contact.FieldWxWxid)
+	}
+	if m.FieldCleared(contact.FieldType) {
+		fields = append(fields, contact.FieldType)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *ContactMutation) 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 *ContactMutation) ClearField(name string) error {
+	switch name {
+	case contact.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case contact.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	case contact.FieldWxWxid:
+		m.ClearWxWxid()
+		return nil
+	case contact.FieldType:
+		m.ClearType()
+		return nil
+	}
+	return fmt.Errorf("unknown Contact 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 *ContactMutation) ResetField(name string) error {
+	switch name {
+	case contact.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case contact.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case contact.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case contact.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case contact.FieldWxWxid:
+		m.ResetWxWxid()
+		return nil
+	case contact.FieldType:
+		m.ResetType()
+		return nil
+	case contact.FieldWxid:
+		m.ResetWxid()
+		return nil
+	case contact.FieldAccount:
+		m.ResetAccount()
+		return nil
+	case contact.FieldNickname:
+		m.ResetNickname()
+		return nil
+	case contact.FieldMarkname:
+		m.ResetMarkname()
+		return nil
+	case contact.FieldHeadimg:
+		m.ResetHeadimg()
+		return nil
+	case contact.FieldSex:
+		m.ResetSex()
+		return nil
+	case contact.FieldStarrole:
+		m.ResetStarrole()
+		return nil
+	case contact.FieldDontseeit:
+		m.ResetDontseeit()
+		return nil
+	case contact.FieldDontseeme:
+		m.ResetDontseeme()
+		return nil
+	case contact.FieldLag:
+		m.ResetLag()
+		return nil
+	case contact.FieldGid:
+		m.ResetGid()
+		return nil
+	case contact.FieldGname:
+		m.ResetGname()
+		return nil
+	case contact.FieldV3:
+		m.ResetV3()
+		return nil
+	}
+	return fmt.Errorf("unknown Contact field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *ContactMutation) 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 *ContactMutation) AddedIDs(name string) []ent.Value {
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *ContactMutation) 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 *ContactMutation) RemovedIDs(name string) []ent.Value {
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *ContactMutation) 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 *ContactMutation) 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 *ContactMutation) ClearEdge(name string) error {
+	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 {
+	return fmt.Errorf("unknown Contact edge %s", name)
+}
+
+// ServerMutation represents an operation that mutates the Server nodes in the graph.
+type ServerMutation struct {
+	config
+	op            Op
+	typ           string
+	id            *uint64
+	created_at    *time.Time
+	updated_at    *time.Time
+	status        *uint8
+	addstatus     *int8
+	deleted_at    *time.Time
+	name          *string
+	public_ip     *string
+	private_ip    *string
+	admin_port    *string
+	clearedFields map[string]struct{}
+	wxs           map[uint64]struct{}
+	removedwxs    map[uint64]struct{}
+	clearedwxs    bool
+	done          bool
+	oldValue      func(context.Context) (*Server, error)
+	predicates    []predicate.Server
+}
+
+var _ ent.Mutation = (*ServerMutation)(nil)
+
+// serverOption allows management of the mutation configuration using functional options.
+type serverOption func(*ServerMutation)
+
+// newServerMutation creates new mutation for the Server entity.
+func newServerMutation(c config, op Op, opts ...serverOption) *ServerMutation {
+	m := &ServerMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeServer,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withServerID sets the ID field of the mutation.
+func withServerID(id uint64) serverOption {
+	return func(m *ServerMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Server
+		)
+		m.oldValue = func(ctx context.Context) (*Server, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Server.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withServer sets the old Server of the mutation.
+func withServer(node *Server) serverOption {
+	return func(m *ServerMutation) {
+		m.oldValue = func(context.Context) (*Server, 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 ServerMutation) 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 ServerMutation) 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 Server entities.
+func (m *ServerMutation) 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 *ServerMutation) 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 *ServerMutation) 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().Server.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 *ServerMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *ServerMutation) 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 Server entity.
+// If the Server 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 *ServerMutation) 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 *ServerMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *ServerMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *ServerMutation) 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 Server entity.
+// If the Server 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 *ServerMutation) 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 *ServerMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *ServerMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *ServerMutation) 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 Server entity.
+// If the Server 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 *ServerMutation) 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 *ServerMutation) 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 *ServerMutation) 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 *ServerMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[server.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *ServerMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[server.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *ServerMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, server.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *ServerMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *ServerMutation) 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 Server entity.
+// If the Server 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 *ServerMutation) 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 *ServerMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[server.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *ServerMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[server.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *ServerMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, server.FieldDeletedAt)
+}
+
+// SetName sets the "name" field.
+func (m *ServerMutation) SetName(s string) {
+	m.name = &s
+}
+
+// Name returns the value of the "name" field in the mutation.
+func (m *ServerMutation) 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 Server entity.
+// If the Server 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 *ServerMutation) 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 *ServerMutation) ResetName() {
+	m.name = nil
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (m *ServerMutation) SetPublicIP(s string) {
+	m.public_ip = &s
+}
+
+// PublicIP returns the value of the "public_ip" field in the mutation.
+func (m *ServerMutation) PublicIP() (r string, exists bool) {
+	v := m.public_ip
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldPublicIP returns the old "public_ip" field's value of the Server entity.
+// If the Server 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 *ServerMutation) OldPublicIP(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldPublicIP is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldPublicIP requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldPublicIP: %w", err)
+	}
+	return oldValue.PublicIP, nil
+}
+
+// ResetPublicIP resets all changes to the "public_ip" field.
+func (m *ServerMutation) ResetPublicIP() {
+	m.public_ip = nil
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (m *ServerMutation) SetPrivateIP(s string) {
+	m.private_ip = &s
+}
+
+// PrivateIP returns the value of the "private_ip" field in the mutation.
+func (m *ServerMutation) PrivateIP() (r string, exists bool) {
+	v := m.private_ip
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldPrivateIP returns the old "private_ip" field's value of the Server entity.
+// If the Server 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 *ServerMutation) OldPrivateIP(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldPrivateIP is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldPrivateIP requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldPrivateIP: %w", err)
+	}
+	return oldValue.PrivateIP, nil
+}
+
+// ResetPrivateIP resets all changes to the "private_ip" field.
+func (m *ServerMutation) ResetPrivateIP() {
+	m.private_ip = nil
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (m *ServerMutation) SetAdminPort(s string) {
+	m.admin_port = &s
+}
+
+// AdminPort returns the value of the "admin_port" field in the mutation.
+func (m *ServerMutation) AdminPort() (r string, exists bool) {
+	v := m.admin_port
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAdminPort returns the old "admin_port" field's value of the Server entity.
+// If the Server 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 *ServerMutation) OldAdminPort(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAdminPort is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAdminPort requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAdminPort: %w", err)
+	}
+	return oldValue.AdminPort, nil
+}
+
+// ResetAdminPort resets all changes to the "admin_port" field.
+func (m *ServerMutation) ResetAdminPort() {
+	m.admin_port = nil
+}
+
+// AddWxIDs adds the "wxs" edge to the Wx entity by ids.
+func (m *ServerMutation) AddWxIDs(ids ...uint64) {
+	if m.wxs == nil {
+		m.wxs = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		m.wxs[ids[i]] = struct{}{}
+	}
+}
+
+// ClearWxs clears the "wxs" edge to the Wx entity.
+func (m *ServerMutation) ClearWxs() {
+	m.clearedwxs = true
+}
+
+// WxsCleared reports if the "wxs" edge to the Wx entity was cleared.
+func (m *ServerMutation) WxsCleared() bool {
+	return m.clearedwxs
+}
+
+// RemoveWxIDs removes the "wxs" edge to the Wx entity by IDs.
+func (m *ServerMutation) RemoveWxIDs(ids ...uint64) {
+	if m.removedwxs == nil {
+		m.removedwxs = make(map[uint64]struct{})
+	}
+	for i := range ids {
+		delete(m.wxs, ids[i])
+		m.removedwxs[ids[i]] = struct{}{}
+	}
+}
+
+// RemovedWxs returns the removed IDs of the "wxs" edge to the Wx entity.
+func (m *ServerMutation) RemovedWxsIDs() (ids []uint64) {
+	for id := range m.removedwxs {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// WxsIDs returns the "wxs" edge IDs in the mutation.
+func (m *ServerMutation) WxsIDs() (ids []uint64) {
+	for id := range m.wxs {
+		ids = append(ids, id)
+	}
+	return
+}
+
+// ResetWxs resets all changes to the "wxs" edge.
+func (m *ServerMutation) ResetWxs() {
+	m.wxs = nil
+	m.clearedwxs = false
+	m.removedwxs = nil
+}
+
+// Where appends a list predicates to the ServerMutation builder.
+func (m *ServerMutation) Where(ps ...predicate.Server) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the ServerMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *ServerMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Server, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *ServerMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *ServerMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Server).
+func (m *ServerMutation) 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 *ServerMutation) Fields() []string {
+	fields := make([]string, 0, 8)
+	if m.created_at != nil {
+		fields = append(fields, server.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, server.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, server.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, server.FieldDeletedAt)
+	}
+	if m.name != nil {
+		fields = append(fields, server.FieldName)
+	}
+	if m.public_ip != nil {
+		fields = append(fields, server.FieldPublicIP)
+	}
+	if m.private_ip != nil {
+		fields = append(fields, server.FieldPrivateIP)
+	}
+	if m.admin_port != nil {
+		fields = append(fields, server.FieldAdminPort)
+	}
+	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 *ServerMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case server.FieldCreatedAt:
+		return m.CreatedAt()
+	case server.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case server.FieldStatus:
+		return m.Status()
+	case server.FieldDeletedAt:
+		return m.DeletedAt()
+	case server.FieldName:
+		return m.Name()
+	case server.FieldPublicIP:
+		return m.PublicIP()
+	case server.FieldPrivateIP:
+		return m.PrivateIP()
+	case server.FieldAdminPort:
+		return m.AdminPort()
+	}
+	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 *ServerMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case server.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case server.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case server.FieldStatus:
+		return m.OldStatus(ctx)
+	case server.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case server.FieldName:
+		return m.OldName(ctx)
+	case server.FieldPublicIP:
+		return m.OldPublicIP(ctx)
+	case server.FieldPrivateIP:
+		return m.OldPrivateIP(ctx)
+	case server.FieldAdminPort:
+		return m.OldAdminPort(ctx)
+	}
+	return nil, fmt.Errorf("unknown Server 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 *ServerMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case server.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 server.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 server.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case server.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 server.FieldName:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetName(v)
+		return nil
+	case server.FieldPublicIP:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetPublicIP(v)
+		return nil
+	case server.FieldPrivateIP:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetPrivateIP(v)
+		return nil
+	case server.FieldAdminPort:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAdminPort(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Server field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *ServerMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, server.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 *ServerMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case server.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 *ServerMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case server.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 Server numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *ServerMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(server.FieldStatus) {
+		fields = append(fields, server.FieldStatus)
+	}
+	if m.FieldCleared(server.FieldDeletedAt) {
+		fields = append(fields, server.FieldDeletedAt)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *ServerMutation) 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 *ServerMutation) ClearField(name string) error {
+	switch name {
+	case server.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case server.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	}
+	return fmt.Errorf("unknown Server 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 *ServerMutation) ResetField(name string) error {
+	switch name {
+	case server.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case server.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case server.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case server.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case server.FieldName:
+		m.ResetName()
+		return nil
+	case server.FieldPublicIP:
+		m.ResetPublicIP()
+		return nil
+	case server.FieldPrivateIP:
+		m.ResetPrivateIP()
+		return nil
+	case server.FieldAdminPort:
+		m.ResetAdminPort()
+		return nil
+	}
+	return fmt.Errorf("unknown Server field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *ServerMutation) AddedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.wxs != nil {
+		edges = append(edges, server.EdgeWxs)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *ServerMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case server.EdgeWxs:
+		ids := make([]ent.Value, 0, len(m.wxs))
+		for id := range m.wxs {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *ServerMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.removedwxs != nil {
+		edges = append(edges, server.EdgeWxs)
+	}
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *ServerMutation) RemovedIDs(name string) []ent.Value {
+	switch name {
+	case server.EdgeWxs:
+		ids := make([]ent.Value, 0, len(m.removedwxs))
+		for id := range m.removedwxs {
+			ids = append(ids, id)
+		}
+		return ids
+	}
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *ServerMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.clearedwxs {
+		edges = append(edges, server.EdgeWxs)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *ServerMutation) EdgeCleared(name string) bool {
+	switch name {
+	case server.EdgeWxs:
+		return m.clearedwxs
+	}
+	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 *ServerMutation) ClearEdge(name string) error {
+	switch name {
+	}
+	return fmt.Errorf("unknown Server 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 *ServerMutation) ResetEdge(name string) error {
+	switch name {
+	case server.EdgeWxs:
+		m.ResetWxs()
+		return nil
+	}
+	return fmt.Errorf("unknown Server edge %s", name)
+}
+
+// WxMutation represents an operation that mutates the Wx nodes in the graph.
+type WxMutation struct {
+	config
+	op            Op
+	typ           string
+	id            *uint64
+	created_at    *time.Time
+	updated_at    *time.Time
+	status        *uint8
+	addstatus     *int8
+	deleted_at    *time.Time
+	port          *string
+	process_id    *string
+	callback      *string
+	wxid          *string
+	account       *string
+	nickname      *string
+	tel           *string
+	head_big      *string
+	clearedFields map[string]struct{}
+	server        *uint64
+	clearedserver bool
+	done          bool
+	oldValue      func(context.Context) (*Wx, error)
+	predicates    []predicate.Wx
+}
+
+var _ ent.Mutation = (*WxMutation)(nil)
+
+// wxOption allows management of the mutation configuration using functional options.
+type wxOption func(*WxMutation)
+
+// newWxMutation creates new mutation for the Wx entity.
+func newWxMutation(c config, op Op, opts ...wxOption) *WxMutation {
+	m := &WxMutation{
+		config:        c,
+		op:            op,
+		typ:           TypeWx,
+		clearedFields: make(map[string]struct{}),
+	}
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+// withWxID sets the ID field of the mutation.
+func withWxID(id uint64) wxOption {
+	return func(m *WxMutation) {
+		var (
+			err   error
+			once  sync.Once
+			value *Wx
+		)
+		m.oldValue = func(ctx context.Context) (*Wx, error) {
+			once.Do(func() {
+				if m.done {
+					err = errors.New("querying old values post mutation is not allowed")
+				} else {
+					value, err = m.Client().Wx.Get(ctx, id)
+				}
+			})
+			return value, err
+		}
+		m.id = &id
+	}
+}
+
+// withWx sets the old Wx of the mutation.
+func withWx(node *Wx) wxOption {
+	return func(m *WxMutation) {
+		m.oldValue = func(context.Context) (*Wx, 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 WxMutation) 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 WxMutation) 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 Wx entities.
+func (m *WxMutation) 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 *WxMutation) 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 *WxMutation) 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().Wx.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 *WxMutation) SetCreatedAt(t time.Time) {
+	m.created_at = &t
+}
+
+// CreatedAt returns the value of the "created_at" field in the mutation.
+func (m *WxMutation) 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 Wx entity.
+// If the Wx 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 *WxMutation) 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 *WxMutation) ResetCreatedAt() {
+	m.created_at = nil
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (m *WxMutation) SetUpdatedAt(t time.Time) {
+	m.updated_at = &t
+}
+
+// UpdatedAt returns the value of the "updated_at" field in the mutation.
+func (m *WxMutation) 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 Wx entity.
+// If the Wx 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 *WxMutation) 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 *WxMutation) ResetUpdatedAt() {
+	m.updated_at = nil
+}
+
+// SetStatus sets the "status" field.
+func (m *WxMutation) SetStatus(u uint8) {
+	m.status = &u
+	m.addstatus = nil
+}
+
+// Status returns the value of the "status" field in the mutation.
+func (m *WxMutation) 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 Wx entity.
+// If the Wx 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 *WxMutation) 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 *WxMutation) 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 *WxMutation) 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 *WxMutation) ClearStatus() {
+	m.status = nil
+	m.addstatus = nil
+	m.clearedFields[wx.FieldStatus] = struct{}{}
+}
+
+// StatusCleared returns if the "status" field was cleared in this mutation.
+func (m *WxMutation) StatusCleared() bool {
+	_, ok := m.clearedFields[wx.FieldStatus]
+	return ok
+}
+
+// ResetStatus resets all changes to the "status" field.
+func (m *WxMutation) ResetStatus() {
+	m.status = nil
+	m.addstatus = nil
+	delete(m.clearedFields, wx.FieldStatus)
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (m *WxMutation) SetDeletedAt(t time.Time) {
+	m.deleted_at = &t
+}
+
+// DeletedAt returns the value of the "deleted_at" field in the mutation.
+func (m *WxMutation) 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 Wx entity.
+// If the Wx 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 *WxMutation) 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 *WxMutation) ClearDeletedAt() {
+	m.deleted_at = nil
+	m.clearedFields[wx.FieldDeletedAt] = struct{}{}
+}
+
+// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
+func (m *WxMutation) DeletedAtCleared() bool {
+	_, ok := m.clearedFields[wx.FieldDeletedAt]
+	return ok
+}
+
+// ResetDeletedAt resets all changes to the "deleted_at" field.
+func (m *WxMutation) ResetDeletedAt() {
+	m.deleted_at = nil
+	delete(m.clearedFields, wx.FieldDeletedAt)
+}
+
+// SetServerID sets the "server_id" field.
+func (m *WxMutation) SetServerID(u uint64) {
+	m.server = &u
+}
+
+// ServerID returns the value of the "server_id" field in the mutation.
+func (m *WxMutation) ServerID() (r uint64, exists bool) {
+	v := m.server
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldServerID returns the old "server_id" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldServerID(ctx context.Context) (v uint64, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldServerID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldServerID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldServerID: %w", err)
+	}
+	return oldValue.ServerID, nil
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (m *WxMutation) ClearServerID() {
+	m.server = nil
+	m.clearedFields[wx.FieldServerID] = struct{}{}
+}
+
+// ServerIDCleared returns if the "server_id" field was cleared in this mutation.
+func (m *WxMutation) ServerIDCleared() bool {
+	_, ok := m.clearedFields[wx.FieldServerID]
+	return ok
+}
+
+// ResetServerID resets all changes to the "server_id" field.
+func (m *WxMutation) ResetServerID() {
+	m.server = nil
+	delete(m.clearedFields, wx.FieldServerID)
+}
+
+// SetPort sets the "port" field.
+func (m *WxMutation) SetPort(s string) {
+	m.port = &s
+}
+
+// Port returns the value of the "port" field in the mutation.
+func (m *WxMutation) Port() (r string, exists bool) {
+	v := m.port
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldPort returns the old "port" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldPort(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldPort is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldPort requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldPort: %w", err)
+	}
+	return oldValue.Port, nil
+}
+
+// ResetPort resets all changes to the "port" field.
+func (m *WxMutation) ResetPort() {
+	m.port = nil
+}
+
+// SetProcessID sets the "process_id" field.
+func (m *WxMutation) SetProcessID(s string) {
+	m.process_id = &s
+}
+
+// ProcessID returns the value of the "process_id" field in the mutation.
+func (m *WxMutation) ProcessID() (r string, exists bool) {
+	v := m.process_id
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldProcessID returns the old "process_id" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldProcessID(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldProcessID is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldProcessID requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldProcessID: %w", err)
+	}
+	return oldValue.ProcessID, nil
+}
+
+// ResetProcessID resets all changes to the "process_id" field.
+func (m *WxMutation) ResetProcessID() {
+	m.process_id = nil
+}
+
+// SetCallback sets the "callback" field.
+func (m *WxMutation) SetCallback(s string) {
+	m.callback = &s
+}
+
+// Callback returns the value of the "callback" field in the mutation.
+func (m *WxMutation) Callback() (r string, exists bool) {
+	v := m.callback
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldCallback returns the old "callback" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldCallback(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldCallback is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldCallback requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldCallback: %w", err)
+	}
+	return oldValue.Callback, nil
+}
+
+// ResetCallback resets all changes to the "callback" field.
+func (m *WxMutation) ResetCallback() {
+	m.callback = nil
+}
+
+// SetWxid sets the "wxid" field.
+func (m *WxMutation) SetWxid(s string) {
+	m.wxid = &s
+}
+
+// Wxid returns the value of the "wxid" field in the mutation.
+func (m *WxMutation) 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 Wx entity.
+// If the Wx 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 *WxMutation) 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 *WxMutation) ResetWxid() {
+	m.wxid = nil
+}
+
+// SetAccount sets the "account" field.
+func (m *WxMutation) SetAccount(s string) {
+	m.account = &s
+}
+
+// Account returns the value of the "account" field in the mutation.
+func (m *WxMutation) Account() (r string, exists bool) {
+	v := m.account
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldAccount returns the old "account" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldAccount(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldAccount is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldAccount requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldAccount: %w", err)
+	}
+	return oldValue.Account, nil
+}
+
+// ResetAccount resets all changes to the "account" field.
+func (m *WxMutation) ResetAccount() {
+	m.account = nil
+}
+
+// SetNickname sets the "nickname" field.
+func (m *WxMutation) SetNickname(s string) {
+	m.nickname = &s
+}
+
+// Nickname returns the value of the "nickname" field in the mutation.
+func (m *WxMutation) Nickname() (r string, exists bool) {
+	v := m.nickname
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldNickname returns the old "nickname" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldNickname(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldNickname is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldNickname requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldNickname: %w", err)
+	}
+	return oldValue.Nickname, nil
+}
+
+// ResetNickname resets all changes to the "nickname" field.
+func (m *WxMutation) ResetNickname() {
+	m.nickname = nil
+}
+
+// SetTel sets the "tel" field.
+func (m *WxMutation) SetTel(s string) {
+	m.tel = &s
+}
+
+// Tel returns the value of the "tel" field in the mutation.
+func (m *WxMutation) Tel() (r string, exists bool) {
+	v := m.tel
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldTel returns the old "tel" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldTel(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldTel is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldTel requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldTel: %w", err)
+	}
+	return oldValue.Tel, nil
+}
+
+// ResetTel resets all changes to the "tel" field.
+func (m *WxMutation) ResetTel() {
+	m.tel = nil
+}
+
+// SetHeadBig sets the "head_big" field.
+func (m *WxMutation) SetHeadBig(s string) {
+	m.head_big = &s
+}
+
+// HeadBig returns the value of the "head_big" field in the mutation.
+func (m *WxMutation) HeadBig() (r string, exists bool) {
+	v := m.head_big
+	if v == nil {
+		return
+	}
+	return *v, true
+}
+
+// OldHeadBig returns the old "head_big" field's value of the Wx entity.
+// If the Wx 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 *WxMutation) OldHeadBig(ctx context.Context) (v string, err error) {
+	if !m.op.Is(OpUpdateOne) {
+		return v, errors.New("OldHeadBig is only allowed on UpdateOne operations")
+	}
+	if m.id == nil || m.oldValue == nil {
+		return v, errors.New("OldHeadBig requires an ID field in the mutation")
+	}
+	oldValue, err := m.oldValue(ctx)
+	if err != nil {
+		return v, fmt.Errorf("querying old value for OldHeadBig: %w", err)
+	}
+	return oldValue.HeadBig, nil
+}
+
+// ResetHeadBig resets all changes to the "head_big" field.
+func (m *WxMutation) ResetHeadBig() {
+	m.head_big = nil
+}
+
+// ClearServer clears the "server" edge to the Server entity.
+func (m *WxMutation) ClearServer() {
+	m.clearedserver = true
+	m.clearedFields[wx.FieldServerID] = struct{}{}
+}
+
+// ServerCleared reports if the "server" edge to the Server entity was cleared.
+func (m *WxMutation) ServerCleared() bool {
+	return m.ServerIDCleared() || m.clearedserver
+}
+
+// ServerIDs returns the "server" edge IDs in the mutation.
+// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
+// ServerID instead. It exists only for internal usage by the builders.
+func (m *WxMutation) ServerIDs() (ids []uint64) {
+	if id := m.server; id != nil {
+		ids = append(ids, *id)
+	}
+	return
+}
+
+// ResetServer resets all changes to the "server" edge.
+func (m *WxMutation) ResetServer() {
+	m.server = nil
+	m.clearedserver = false
+}
+
+// Where appends a list predicates to the WxMutation builder.
+func (m *WxMutation) Where(ps ...predicate.Wx) {
+	m.predicates = append(m.predicates, ps...)
+}
+
+// WhereP appends storage-level predicates to the WxMutation builder. Using this method,
+// users can use type-assertion to append predicates that do not depend on any generated package.
+func (m *WxMutation) WhereP(ps ...func(*sql.Selector)) {
+	p := make([]predicate.Wx, len(ps))
+	for i := range ps {
+		p[i] = ps[i]
+	}
+	m.Where(p...)
+}
+
+// Op returns the operation name.
+func (m *WxMutation) Op() Op {
+	return m.op
+}
+
+// SetOp allows setting the mutation operation.
+func (m *WxMutation) SetOp(op Op) {
+	m.op = op
+}
+
+// Type returns the node type of this mutation (Wx).
+func (m *WxMutation) 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 *WxMutation) Fields() []string {
+	fields := make([]string, 0, 13)
+	if m.created_at != nil {
+		fields = append(fields, wx.FieldCreatedAt)
+	}
+	if m.updated_at != nil {
+		fields = append(fields, wx.FieldUpdatedAt)
+	}
+	if m.status != nil {
+		fields = append(fields, wx.FieldStatus)
+	}
+	if m.deleted_at != nil {
+		fields = append(fields, wx.FieldDeletedAt)
+	}
+	if m.server != nil {
+		fields = append(fields, wx.FieldServerID)
+	}
+	if m.port != nil {
+		fields = append(fields, wx.FieldPort)
+	}
+	if m.process_id != nil {
+		fields = append(fields, wx.FieldProcessID)
+	}
+	if m.callback != nil {
+		fields = append(fields, wx.FieldCallback)
+	}
+	if m.wxid != nil {
+		fields = append(fields, wx.FieldWxid)
+	}
+	if m.account != nil {
+		fields = append(fields, wx.FieldAccount)
+	}
+	if m.nickname != nil {
+		fields = append(fields, wx.FieldNickname)
+	}
+	if m.tel != nil {
+		fields = append(fields, wx.FieldTel)
+	}
+	if m.head_big != nil {
+		fields = append(fields, wx.FieldHeadBig)
+	}
+	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 *WxMutation) Field(name string) (ent.Value, bool) {
+	switch name {
+	case wx.FieldCreatedAt:
+		return m.CreatedAt()
+	case wx.FieldUpdatedAt:
+		return m.UpdatedAt()
+	case wx.FieldStatus:
+		return m.Status()
+	case wx.FieldDeletedAt:
+		return m.DeletedAt()
+	case wx.FieldServerID:
+		return m.ServerID()
+	case wx.FieldPort:
+		return m.Port()
+	case wx.FieldProcessID:
+		return m.ProcessID()
+	case wx.FieldCallback:
+		return m.Callback()
+	case wx.FieldWxid:
+		return m.Wxid()
+	case wx.FieldAccount:
+		return m.Account()
+	case wx.FieldNickname:
+		return m.Nickname()
+	case wx.FieldTel:
+		return m.Tel()
+	case wx.FieldHeadBig:
+		return m.HeadBig()
+	}
+	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 *WxMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
+	switch name {
+	case wx.FieldCreatedAt:
+		return m.OldCreatedAt(ctx)
+	case wx.FieldUpdatedAt:
+		return m.OldUpdatedAt(ctx)
+	case wx.FieldStatus:
+		return m.OldStatus(ctx)
+	case wx.FieldDeletedAt:
+		return m.OldDeletedAt(ctx)
+	case wx.FieldServerID:
+		return m.OldServerID(ctx)
+	case wx.FieldPort:
+		return m.OldPort(ctx)
+	case wx.FieldProcessID:
+		return m.OldProcessID(ctx)
+	case wx.FieldCallback:
+		return m.OldCallback(ctx)
+	case wx.FieldWxid:
+		return m.OldWxid(ctx)
+	case wx.FieldAccount:
+		return m.OldAccount(ctx)
+	case wx.FieldNickname:
+		return m.OldNickname(ctx)
+	case wx.FieldTel:
+		return m.OldTel(ctx)
+	case wx.FieldHeadBig:
+		return m.OldHeadBig(ctx)
+	}
+	return nil, fmt.Errorf("unknown Wx 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 *WxMutation) SetField(name string, value ent.Value) error {
+	switch name {
+	case wx.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 wx.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 wx.FieldStatus:
+		v, ok := value.(uint8)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetStatus(v)
+		return nil
+	case wx.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 wx.FieldServerID:
+		v, ok := value.(uint64)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetServerID(v)
+		return nil
+	case wx.FieldPort:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetPort(v)
+		return nil
+	case wx.FieldProcessID:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetProcessID(v)
+		return nil
+	case wx.FieldCallback:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetCallback(v)
+		return nil
+	case wx.FieldWxid:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetWxid(v)
+		return nil
+	case wx.FieldAccount:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetAccount(v)
+		return nil
+	case wx.FieldNickname:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetNickname(v)
+		return nil
+	case wx.FieldTel:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetTel(v)
+		return nil
+	case wx.FieldHeadBig:
+		v, ok := value.(string)
+		if !ok {
+			return fmt.Errorf("unexpected type %T for field %s", value, name)
+		}
+		m.SetHeadBig(v)
+		return nil
+	}
+	return fmt.Errorf("unknown Wx field %s", name)
+}
+
+// AddedFields returns all numeric fields that were incremented/decremented during
+// this mutation.
+func (m *WxMutation) AddedFields() []string {
+	var fields []string
+	if m.addstatus != nil {
+		fields = append(fields, wx.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 *WxMutation) AddedField(name string) (ent.Value, bool) {
+	switch name {
+	case wx.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 *WxMutation) AddField(name string, value ent.Value) error {
+	switch name {
+	case wx.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 Wx numeric field %s", name)
+}
+
+// ClearedFields returns all nullable fields that were cleared during this
+// mutation.
+func (m *WxMutation) ClearedFields() []string {
+	var fields []string
+	if m.FieldCleared(wx.FieldStatus) {
+		fields = append(fields, wx.FieldStatus)
+	}
+	if m.FieldCleared(wx.FieldDeletedAt) {
+		fields = append(fields, wx.FieldDeletedAt)
+	}
+	if m.FieldCleared(wx.FieldServerID) {
+		fields = append(fields, wx.FieldServerID)
+	}
+	return fields
+}
+
+// FieldCleared returns a boolean indicating if a field with the given name was
+// cleared in this mutation.
+func (m *WxMutation) 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 *WxMutation) ClearField(name string) error {
+	switch name {
+	case wx.FieldStatus:
+		m.ClearStatus()
+		return nil
+	case wx.FieldDeletedAt:
+		m.ClearDeletedAt()
+		return nil
+	case wx.FieldServerID:
+		m.ClearServerID()
+		return nil
+	}
+	return fmt.Errorf("unknown Wx 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 *WxMutation) ResetField(name string) error {
+	switch name {
+	case wx.FieldCreatedAt:
+		m.ResetCreatedAt()
+		return nil
+	case wx.FieldUpdatedAt:
+		m.ResetUpdatedAt()
+		return nil
+	case wx.FieldStatus:
+		m.ResetStatus()
+		return nil
+	case wx.FieldDeletedAt:
+		m.ResetDeletedAt()
+		return nil
+	case wx.FieldServerID:
+		m.ResetServerID()
+		return nil
+	case wx.FieldPort:
+		m.ResetPort()
+		return nil
+	case wx.FieldProcessID:
+		m.ResetProcessID()
+		return nil
+	case wx.FieldCallback:
+		m.ResetCallback()
+		return nil
+	case wx.FieldWxid:
+		m.ResetWxid()
+		return nil
+	case wx.FieldAccount:
+		m.ResetAccount()
+		return nil
+	case wx.FieldNickname:
+		m.ResetNickname()
+		return nil
+	case wx.FieldTel:
+		m.ResetTel()
+		return nil
+	case wx.FieldHeadBig:
+		m.ResetHeadBig()
+		return nil
+	}
+	return fmt.Errorf("unknown Wx field %s", name)
+}
+
+// AddedEdges returns all edge names that were set/added in this mutation.
+func (m *WxMutation) AddedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.server != nil {
+		edges = append(edges, wx.EdgeServer)
+	}
+	return edges
+}
+
+// AddedIDs returns all IDs (to other nodes) that were added for the given edge
+// name in this mutation.
+func (m *WxMutation) AddedIDs(name string) []ent.Value {
+	switch name {
+	case wx.EdgeServer:
+		if id := m.server; id != nil {
+			return []ent.Value{*id}
+		}
+	}
+	return nil
+}
+
+// RemovedEdges returns all edge names that were removed in this mutation.
+func (m *WxMutation) RemovedEdges() []string {
+	edges := make([]string, 0, 1)
+	return edges
+}
+
+// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
+// the given name in this mutation.
+func (m *WxMutation) RemovedIDs(name string) []ent.Value {
+	return nil
+}
+
+// ClearedEdges returns all edge names that were cleared in this mutation.
+func (m *WxMutation) ClearedEdges() []string {
+	edges := make([]string, 0, 1)
+	if m.clearedserver {
+		edges = append(edges, wx.EdgeServer)
+	}
+	return edges
+}
+
+// EdgeCleared returns a boolean which indicates if the edge with the given name
+// was cleared in this mutation.
+func (m *WxMutation) EdgeCleared(name string) bool {
+	switch name {
+	case wx.EdgeServer:
+		return m.clearedserver
+	}
+	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 *WxMutation) ClearEdge(name string) error {
+	switch name {
+	case wx.EdgeServer:
+		m.ClearServer()
+		return nil
+	}
+	return fmt.Errorf("unknown Wx 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 *WxMutation) ResetEdge(name string) error {
+	switch name {
+	case wx.EdgeServer:
+		m.ResetServer()
+		return nil
+	}
+	return fmt.Errorf("unknown Wx edge %s", name)
+}

+ 294 - 0
ent/pagination.go

@@ -0,0 +1,294 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"fmt"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+)
+
+const errInvalidPage = "INVALID_PAGE"
+
+const (
+	listField     = "list"
+	pageNumField  = "pageNum"
+	pageSizeField = "pageSize"
+)
+
+type PageDetails struct {
+	Page  uint64 `json:"page"`
+	Size  uint64 `json:"size"`
+	Total uint64 `json:"total"`
+}
+
+// OrderDirection defines the directions in which to order a list of items.
+type OrderDirection string
+
+const (
+	// OrderDirectionAsc specifies an ascending order.
+	OrderDirectionAsc OrderDirection = "ASC"
+	// OrderDirectionDesc specifies a descending order.
+	OrderDirectionDesc OrderDirection = "DESC"
+)
+
+// Validate the order direction value.
+func (o OrderDirection) Validate() error {
+	if o != OrderDirectionAsc && o != OrderDirectionDesc {
+		return fmt.Errorf("%s is not a valid OrderDirection", o)
+	}
+	return nil
+}
+
+// String implements fmt.Stringer interface.
+func (o OrderDirection) String() string {
+	return string(o)
+}
+
+func (o OrderDirection) reverse() OrderDirection {
+	if o == OrderDirectionDesc {
+		return OrderDirectionAsc
+	}
+	return OrderDirectionDesc
+}
+
+const errInvalidPagination = "INVALID_PAGINATION"
+
+type ContactPager struct {
+	Order  contact.OrderOption
+	Filter func(*ContactQuery) (*ContactQuery, error)
+}
+
+// ContactPaginateOption enables pagination customization.
+type ContactPaginateOption func(*ContactPager)
+
+// DefaultContactOrder is the default ordering of Contact.
+var DefaultContactOrder = Desc(contact.FieldID)
+
+func newContactPager(opts []ContactPaginateOption) (*ContactPager, error) {
+	pager := &ContactPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultContactOrder
+	}
+	return pager, nil
+}
+
+func (p *ContactPager) ApplyFilter(query *ContactQuery) (*ContactQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// ContactPageList is Contact PageList result.
+type ContactPageList struct {
+	List        []*Contact   `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (c *ContactQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...ContactPaginateOption,
+) (*ContactPageList, error) {
+
+	pager, err := newContactPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if c, err = pager.ApplyFilter(c); err != nil {
+		return nil, err
+	}
+
+	ret := &ContactPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := c.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		c = c.Order(pager.Order)
+	} else {
+		c = c.Order(DefaultContactOrder)
+	}
+
+	c = c.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := c.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)
+}
+
+// ServerPaginateOption enables pagination customization.
+type ServerPaginateOption func(*ServerPager)
+
+// DefaultServerOrder is the default ordering of Server.
+var DefaultServerOrder = Desc(server.FieldID)
+
+func newServerPager(opts []ServerPaginateOption) (*ServerPager, error) {
+	pager := &ServerPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultServerOrder
+	}
+	return pager, nil
+}
+
+func (p *ServerPager) ApplyFilter(query *ServerQuery) (*ServerQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// ServerPageList is Server PageList result.
+type ServerPageList struct {
+	List        []*Server    `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (s *ServerQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...ServerPaginateOption,
+) (*ServerPageList, error) {
+
+	pager, err := newServerPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if s, err = pager.ApplyFilter(s); err != nil {
+		return nil, err
+	}
+
+	ret := &ServerPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := s.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		s = s.Order(pager.Order)
+	} else {
+		s = s.Order(DefaultServerOrder)
+	}
+
+	s = s.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := s.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}
+
+type WxPager struct {
+	Order  wx.OrderOption
+	Filter func(*WxQuery) (*WxQuery, error)
+}
+
+// WxPaginateOption enables pagination customization.
+type WxPaginateOption func(*WxPager)
+
+// DefaultWxOrder is the default ordering of Wx.
+var DefaultWxOrder = Desc(wx.FieldID)
+
+func newWxPager(opts []WxPaginateOption) (*WxPager, error) {
+	pager := &WxPager{}
+	for _, opt := range opts {
+		opt(pager)
+	}
+	if pager.Order == nil {
+		pager.Order = DefaultWxOrder
+	}
+	return pager, nil
+}
+
+func (p *WxPager) ApplyFilter(query *WxQuery) (*WxQuery, error) {
+	if p.Filter != nil {
+		return p.Filter(query)
+	}
+	return query, nil
+}
+
+// WxPageList is Wx PageList result.
+type WxPageList struct {
+	List        []*Wx        `json:"list"`
+	PageDetails *PageDetails `json:"pageDetails"`
+}
+
+func (w *WxQuery) Page(
+	ctx context.Context, pageNum uint64, pageSize uint64, opts ...WxPaginateOption,
+) (*WxPageList, error) {
+
+	pager, err := newWxPager(opts)
+	if err != nil {
+		return nil, err
+	}
+
+	if w, err = pager.ApplyFilter(w); err != nil {
+		return nil, err
+	}
+
+	ret := &WxPageList{}
+
+	ret.PageDetails = &PageDetails{
+		Page: pageNum,
+		Size: pageSize,
+	}
+
+	count, err := w.Clone().Count(ctx)
+
+	if err != nil {
+		return nil, err
+	}
+
+	ret.PageDetails.Total = uint64(count)
+
+	if pager.Order != nil {
+		w = w.Order(pager.Order)
+	} else {
+		w = w.Order(DefaultWxOrder)
+	}
+
+	w = w.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+	list, err := w.All(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret.List = list
+
+	return ret, nil
+}

+ 16 - 0
ent/predicate/predicate.go

@@ -0,0 +1,16 @@
+// Code generated by ent, DO NOT EDIT.
+
+package predicate
+
+import (
+	"entgo.io/ent/dialect/sql"
+)
+
+// Contact is the predicate function for contact builders.
+type Contact func(*sql.Selector)
+
+// Server is the predicate function for server builders.
+type Server func(*sql.Selector)
+
+// Wx is the predicate function for wx builders.
+type Wx func(*sql.Selector)

+ 5 - 0
ent/runtime.go

@@ -0,0 +1,5 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+// The schema-stitching logic is generated in wechat-api/ent/runtime/runtime.go

+ 193 - 0
ent/runtime/runtime.go

@@ -0,0 +1,193 @@
+// Code generated by ent, DO NOT EDIT.
+
+package runtime
+
+import (
+	"time"
+	"wechat-api/ent/contact"
+	"wechat-api/ent/schema"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+)
+
+// The init function reads all schema descriptors with runtime code
+// (default values, validators, hooks and policies) and stitches it
+// to their package variables.
+func init() {
+	contactMixin := schema.Contact{}.Mixin()
+	contactMixinHooks2 := contactMixin[2].Hooks()
+	contact.Hooks[0] = contactMixinHooks2[0]
+	contactMixinInters2 := contactMixin[2].Interceptors()
+	contact.Interceptors[0] = contactMixinInters2[0]
+	contactMixinFields0 := contactMixin[0].Fields()
+	_ = contactMixinFields0
+	contactMixinFields1 := contactMixin[1].Fields()
+	_ = contactMixinFields1
+	contactFields := schema.Contact{}.Fields()
+	_ = contactFields
+	// contactDescCreatedAt is the schema descriptor for created_at field.
+	contactDescCreatedAt := contactMixinFields0[1].Descriptor()
+	// contact.DefaultCreatedAt holds the default value on creation for the created_at field.
+	contact.DefaultCreatedAt = contactDescCreatedAt.Default.(func() time.Time)
+	// contactDescUpdatedAt is the schema descriptor for updated_at field.
+	contactDescUpdatedAt := contactMixinFields0[2].Descriptor()
+	// contact.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	contact.DefaultUpdatedAt = contactDescUpdatedAt.Default.(func() time.Time)
+	// contact.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	contact.UpdateDefaultUpdatedAt = contactDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// contactDescStatus is the schema descriptor for status field.
+	contactDescStatus := contactMixinFields1[0].Descriptor()
+	// contact.DefaultStatus holds the default value on creation for the status field.
+	contact.DefaultStatus = contactDescStatus.Default.(uint8)
+	// contactDescWxWxid is the schema descriptor for wx_wxid field.
+	contactDescWxWxid := contactFields[0].Descriptor()
+	// contact.DefaultWxWxid holds the default value on creation for the wx_wxid field.
+	contact.DefaultWxWxid = contactDescWxWxid.Default.(string)
+	// contactDescType is the schema descriptor for type field.
+	contactDescType := contactFields[1].Descriptor()
+	// contact.DefaultType holds the default value on creation for the type field.
+	contact.DefaultType = contactDescType.Default.(int)
+	// contactDescWxid is the schema descriptor for wxid field.
+	contactDescWxid := contactFields[2].Descriptor()
+	// contact.DefaultWxid holds the default value on creation for the wxid field.
+	contact.DefaultWxid = contactDescWxid.Default.(string)
+	// contactDescAccount is the schema descriptor for account field.
+	contactDescAccount := contactFields[3].Descriptor()
+	// contact.DefaultAccount holds the default value on creation for the account field.
+	contact.DefaultAccount = contactDescAccount.Default.(string)
+	// contactDescNickname is the schema descriptor for nickname field.
+	contactDescNickname := contactFields[4].Descriptor()
+	// contact.DefaultNickname holds the default value on creation for the nickname field.
+	contact.DefaultNickname = contactDescNickname.Default.(string)
+	// contactDescMarkname is the schema descriptor for markname field.
+	contactDescMarkname := contactFields[5].Descriptor()
+	// contact.DefaultMarkname holds the default value on creation for the markname field.
+	contact.DefaultMarkname = contactDescMarkname.Default.(string)
+	// contactDescHeadimg is the schema descriptor for headimg field.
+	contactDescHeadimg := contactFields[6].Descriptor()
+	// contact.DefaultHeadimg holds the default value on creation for the headimg field.
+	contact.DefaultHeadimg = contactDescHeadimg.Default.(string)
+	// contactDescSex is the schema descriptor for sex field.
+	contactDescSex := contactFields[7].Descriptor()
+	// contact.DefaultSex holds the default value on creation for the sex field.
+	contact.DefaultSex = contactDescSex.Default.(int)
+	// contactDescStarrole is the schema descriptor for starrole field.
+	contactDescStarrole := contactFields[8].Descriptor()
+	// contact.DefaultStarrole holds the default value on creation for the starrole field.
+	contact.DefaultStarrole = contactDescStarrole.Default.(string)
+	// contactDescDontseeit is the schema descriptor for dontseeit field.
+	contactDescDontseeit := contactFields[9].Descriptor()
+	// contact.DefaultDontseeit holds the default value on creation for the dontseeit field.
+	contact.DefaultDontseeit = contactDescDontseeit.Default.(int)
+	// contactDescDontseeme is the schema descriptor for dontseeme field.
+	contactDescDontseeme := contactFields[10].Descriptor()
+	// contact.DefaultDontseeme holds the default value on creation for the dontseeme field.
+	contact.DefaultDontseeme = contactDescDontseeme.Default.(int)
+	// contactDescLag is the schema descriptor for lag field.
+	contactDescLag := contactFields[11].Descriptor()
+	// contact.DefaultLag holds the default value on creation for the lag field.
+	contact.DefaultLag = contactDescLag.Default.(string)
+	// contactDescGid is the schema descriptor for gid field.
+	contactDescGid := contactFields[12].Descriptor()
+	// contact.DefaultGid holds the default value on creation for the gid field.
+	contact.DefaultGid = contactDescGid.Default.(string)
+	// contactDescGname is the schema descriptor for gname field.
+	contactDescGname := contactFields[13].Descriptor()
+	// contact.DefaultGname holds the default value on creation for the gname field.
+	contact.DefaultGname = contactDescGname.Default.(string)
+	// contactDescV3 is the schema descriptor for v3 field.
+	contactDescV3 := contactFields[14].Descriptor()
+	// contact.DefaultV3 holds the default value on creation for the v3 field.
+	contact.DefaultV3 = contactDescV3.Default.(string)
+	serverMixin := schema.Server{}.Mixin()
+	serverMixinHooks2 := serverMixin[2].Hooks()
+	server.Hooks[0] = serverMixinHooks2[0]
+	serverMixinInters2 := serverMixin[2].Interceptors()
+	server.Interceptors[0] = serverMixinInters2[0]
+	serverMixinFields0 := serverMixin[0].Fields()
+	_ = serverMixinFields0
+	serverMixinFields1 := serverMixin[1].Fields()
+	_ = serverMixinFields1
+	serverFields := schema.Server{}.Fields()
+	_ = serverFields
+	// serverDescCreatedAt is the schema descriptor for created_at field.
+	serverDescCreatedAt := serverMixinFields0[1].Descriptor()
+	// server.DefaultCreatedAt holds the default value on creation for the created_at field.
+	server.DefaultCreatedAt = serverDescCreatedAt.Default.(func() time.Time)
+	// serverDescUpdatedAt is the schema descriptor for updated_at field.
+	serverDescUpdatedAt := serverMixinFields0[2].Descriptor()
+	// server.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	server.DefaultUpdatedAt = serverDescUpdatedAt.Default.(func() time.Time)
+	// server.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	server.UpdateDefaultUpdatedAt = serverDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// serverDescStatus is the schema descriptor for status field.
+	serverDescStatus := serverMixinFields1[0].Descriptor()
+	// server.DefaultStatus holds the default value on creation for the status field.
+	server.DefaultStatus = serverDescStatus.Default.(uint8)
+	wxMixin := schema.Wx{}.Mixin()
+	wxMixinHooks2 := wxMixin[2].Hooks()
+	wx.Hooks[0] = wxMixinHooks2[0]
+	wxMixinInters2 := wxMixin[2].Interceptors()
+	wx.Interceptors[0] = wxMixinInters2[0]
+	wxMixinFields0 := wxMixin[0].Fields()
+	_ = wxMixinFields0
+	wxMixinFields1 := wxMixin[1].Fields()
+	_ = wxMixinFields1
+	wxFields := schema.Wx{}.Fields()
+	_ = wxFields
+	// wxDescCreatedAt is the schema descriptor for created_at field.
+	wxDescCreatedAt := wxMixinFields0[1].Descriptor()
+	// wx.DefaultCreatedAt holds the default value on creation for the created_at field.
+	wx.DefaultCreatedAt = wxDescCreatedAt.Default.(func() time.Time)
+	// wxDescUpdatedAt is the schema descriptor for updated_at field.
+	wxDescUpdatedAt := wxMixinFields0[2].Descriptor()
+	// wx.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+	wx.DefaultUpdatedAt = wxDescUpdatedAt.Default.(func() time.Time)
+	// wx.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+	wx.UpdateDefaultUpdatedAt = wxDescUpdatedAt.UpdateDefault.(func() time.Time)
+	// wxDescStatus is the schema descriptor for status field.
+	wxDescStatus := wxMixinFields1[0].Descriptor()
+	// wx.DefaultStatus holds the default value on creation for the status field.
+	wx.DefaultStatus = wxDescStatus.Default.(uint8)
+	// wxDescServerID is the schema descriptor for server_id field.
+	wxDescServerID := wxFields[0].Descriptor()
+	// wx.DefaultServerID holds the default value on creation for the server_id field.
+	wx.DefaultServerID = wxDescServerID.Default.(uint64)
+	// wxDescPort is the schema descriptor for port field.
+	wxDescPort := wxFields[1].Descriptor()
+	// wx.DefaultPort holds the default value on creation for the port field.
+	wx.DefaultPort = wxDescPort.Default.(string)
+	// wxDescProcessID is the schema descriptor for process_id field.
+	wxDescProcessID := wxFields[2].Descriptor()
+	// wx.DefaultProcessID holds the default value on creation for the process_id field.
+	wx.DefaultProcessID = wxDescProcessID.Default.(string)
+	// wxDescCallback is the schema descriptor for callback field.
+	wxDescCallback := wxFields[3].Descriptor()
+	// wx.DefaultCallback holds the default value on creation for the callback field.
+	wx.DefaultCallback = wxDescCallback.Default.(string)
+	// wxDescWxid is the schema descriptor for wxid field.
+	wxDescWxid := wxFields[4].Descriptor()
+	// wx.DefaultWxid holds the default value on creation for the wxid field.
+	wx.DefaultWxid = wxDescWxid.Default.(string)
+	// wxDescAccount is the schema descriptor for account field.
+	wxDescAccount := wxFields[5].Descriptor()
+	// wx.DefaultAccount holds the default value on creation for the account field.
+	wx.DefaultAccount = wxDescAccount.Default.(string)
+	// wxDescNickname is the schema descriptor for nickname field.
+	wxDescNickname := wxFields[6].Descriptor()
+	// wx.DefaultNickname holds the default value on creation for the nickname field.
+	wx.DefaultNickname = wxDescNickname.Default.(string)
+	// wxDescTel is the schema descriptor for tel field.
+	wxDescTel := wxFields[7].Descriptor()
+	// wx.DefaultTel holds the default value on creation for the tel field.
+	wx.DefaultTel = wxDescTel.Default.(string)
+	// wxDescHeadBig is the schema descriptor for head_big field.
+	wxDescHeadBig := wxFields[8].Descriptor()
+	// wx.DefaultHeadBig holds the default value on creation for the head_big field.
+	wx.DefaultHeadBig = wxDescHeadBig.Default.(string)
+}
+
+const (
+	Version = "v0.13.1"                                         // Version of ent codegen.
+	Sum     = "h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=" // Sum of ent codegen.
+)

+ 89 - 0
ent/schema/contact.go

@@ -0,0 +1,89 @@
+package schema
+
+import (
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"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 Contact struct {
+	ent.Schema
+}
+
+func (Contact) Fields() []ent.Field {
+	return []ent.Field{
+		field.String("wx_wxid").Optional().Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("属主微信id"),
+		field.Int("type").Optional().Default(1).
+			Annotations(entsql.WithComments(true)).
+			Comment("联系人类型:1好友,2群组,3公众号,4企业微信联系人"),
+		field.String("wxid").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信id 公众号微信ID"),
+		field.String("account").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信账号"),
+		field.String("nickname").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信昵称 群备注名称"),
+		field.String("markname").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("备注名"),
+		field.String("headimg").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("头像"),
+		field.Int("sex").Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("性别 0未知 1男 2女"),
+		field.String("starrole").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("星标 65/67=星标 1/3=未星标"),
+		field.Int("dontseeit").Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("不让他看我的朋友圈 0可以看 1不让看"),
+		field.Int("dontseeme").Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("不看他的朋友圈 0可以看 1不看 1=开启了不看他 128/129=仅聊天"),
+		field.String("lag").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("所属标签id清单,多开会用逗号隔开"),
+		field.String("gid").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("群组id"),
+		field.String("gname").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("群组名称"),
+		field.String("v3").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("v3数据"),
+	}
+}
+
+func (Contact) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (Contact) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("wx_wxid", "wxid").Unique(),
+		index.Fields("wxid"),
+		index.Fields("type"),
+		index.Fields("gid"),
+	}
+}
+
+func (Contact) Edges() []ent.Edge {
+	return nil
+}
+func (Contact) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "contact"}}
+}

+ 90 - 0
ent/schema/localmixin/soft_delete.go

@@ -0,0 +1,90 @@
+package localmixin
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/mixin"
+
+	gen "wechat-api/ent"
+	"wechat-api/ent/hook"
+	"wechat-api/ent/intercept"
+)
+
+// SoftDeleteMixin implements the soft delete pattern for schemas.
+type SoftDeleteMixin struct {
+	mixin.Schema
+}
+
+// Fields of the SoftDeleteMixin.
+func (SoftDeleteMixin) Fields() []ent.Field {
+	return []ent.Field{
+		field.Time("deleted_at").
+			Optional().
+			Comment("Delete Time | 删除日期").
+			Annotations(entsql.WithComments(true)),
+	}
+}
+
+type softDeleteKey struct{}
+
+// SkipSoftDelete returns a new context that skips the soft-delete interceptor/mutators.
+func SkipSoftDelete(parent context.Context) context.Context {
+	return context.WithValue(parent, softDeleteKey{}, true)
+}
+
+// Interceptors of the SoftDeleteMixin.
+func (d SoftDeleteMixin) Interceptors() []gen.Interceptor {
+	return []gen.Interceptor{
+		intercept.TraverseFunc(func(ctx context.Context, q intercept.Query) error {
+			// Skip soft-delete, means include soft-deleted entities.
+			if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
+				return nil
+			}
+			d.P(q)
+			return nil
+		}),
+	}
+}
+
+// Hooks of the SoftDeleteMixin.
+func (d SoftDeleteMixin) Hooks() []gen.Hook {
+	return []gen.Hook{
+		hook.On(
+			func(next gen.Mutator) gen.Mutator {
+				return gen.MutateFunc(func(ctx context.Context, m gen.Mutation) (gen.Value, error) {
+					// Skip soft-delete, means delete the entity permanently.
+					if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
+						return next.Mutate(ctx, m)
+					}
+					mx, ok := m.(interface {
+						SetOp(gen.Op)
+						Client() *gen.Client
+						SetDeletedAt(time.Time)
+						WhereP(...func(*sql.Selector))
+					})
+					if !ok {
+						return nil, fmt.Errorf("unexpected mutation type %T", m)
+					}
+					d.P(mx)
+					mx.SetOp(gen.OpUpdate)
+					mx.SetDeletedAt(time.Now())
+					return mx.Client().Mutate(ctx, m)
+				})
+			},
+			gen.OpDeleteOne|gen.OpDelete,
+		),
+	}
+}
+
+// P adds a storage-level predicate to the queries and mutations.
+func (d SoftDeleteMixin) P(w interface{ WhereP(...func(*sql.Selector)) }) {
+	w.WhereP(
+		sql.FieldIsNull(d.Fields()[0].Descriptor().Name),
+	)
+}

+ 58 - 0
ent/schema/server.go

@@ -0,0 +1,58 @@
+package schema
+
+import (
+	"wechat-api/ent/schema/localmixin"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+)
+
+type Server struct {
+	ent.Schema
+}
+
+func (Server) Fields() []ent.Field {
+	return []ent.Field{
+		field.String("name").
+			Annotations(entsql.WithComments(true)).
+			Comment("名称"),
+		field.String("public_ip").
+			Annotations(entsql.WithComments(true)).
+			Comment("公网ip"),
+		field.String("private_ip").
+			Annotations(entsql.WithComments(true)).
+			Comment("内网ip"),
+		field.String("admin_port").
+			Annotations(entsql.WithComments(true)).
+			Comment("管理端口")}
+}
+
+func (Server) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (Server) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("name"),
+		index.Fields("private_ip"),
+		index.Fields("public_ip").Unique(),
+	}
+}
+
+func (Server) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.To("wxs", Wx.Type),
+	}
+}
+func (Server) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "server"}}
+}

+ 77 - 0
ent/schema/wx.go

@@ -0,0 +1,77 @@
+package schema
+
+import (
+	"wechat-api/ent/schema/localmixin"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/entsql"
+	"entgo.io/ent/schema"
+	"entgo.io/ent/schema/edge"
+	"entgo.io/ent/schema/field"
+	"entgo.io/ent/schema/index"
+	"github.com/suyuan32/simple-admin-common/orm/ent/mixins"
+)
+
+type Wx struct {
+	ent.Schema
+}
+
+func (Wx) Fields() []ent.Field {
+	return []ent.Field{
+		field.Uint64("server_id").Optional().Default(0).
+			Annotations(entsql.WithComments(true)).
+			Comment("服务器id"),
+		field.String("port").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("端口号"),
+		field.String("process_id").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("进程号"),
+		field.String("callback").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("回调地址"),
+		field.String("wxid").Default("").
+			Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信id"),
+		field.String("account").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信账号"),
+		field.String("nickname").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信昵称"),
+		field.String("tel").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("手机号"),
+		field.String("head_big").Default("").
+			Annotations(entsql.WithComments(true)).
+			Comment("微信头像"),
+	}
+}
+
+func (Wx) Mixin() []ent.Mixin {
+	return []ent.Mixin{
+		mixins.IDMixin{},
+		mixins.StatusMixin{},
+		localmixin.SoftDeleteMixin{},
+	}
+}
+
+func (Wx) Indexes() []ent.Index {
+	return []ent.Index{
+		index.Fields("server_id", "port").Unique(),
+		index.Fields("wxid").Unique(),
+		index.Fields("account"),
+		index.Fields("nickname"),
+		index.Fields("tel"),
+	}
+}
+
+func (Wx) Edges() []ent.Edge {
+	return []ent.Edge{
+		edge.From("server", Server.Type).Ref("wxs").Unique().Field("server_id"),
+	}
+}
+func (Wx) Annotations() []schema.Annotation {
+	return []schema.Annotation{entsql.Annotation{Table: "wx"}}
+}

+ 209 - 0
ent/server.go

@@ -0,0 +1,209 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/server"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Server is the model entity for the Server schema.
+type Server 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"`
+	// 名称
+	Name string `json:"name,omitempty"`
+	// 公网ip
+	PublicIP string `json:"public_ip,omitempty"`
+	// 内网ip
+	PrivateIP string `json:"private_ip,omitempty"`
+	// 管理端口
+	AdminPort string `json:"admin_port,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the ServerQuery when eager-loading is set.
+	Edges        ServerEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// ServerEdges holds the relations/edges for other nodes in the graph.
+type ServerEdges struct {
+	// Wxs holds the value of the wxs edge.
+	Wxs []*Wx `json:"wxs,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [1]bool
+}
+
+// WxsOrErr returns the Wxs value or an error if the edge
+// was not loaded in eager-loading.
+func (e ServerEdges) WxsOrErr() ([]*Wx, error) {
+	if e.loadedTypes[0] {
+		return e.Wxs, nil
+	}
+	return nil, &NotLoadedError{edge: "wxs"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Server) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case server.FieldID, server.FieldStatus:
+			values[i] = new(sql.NullInt64)
+		case server.FieldName, server.FieldPublicIP, server.FieldPrivateIP, server.FieldAdminPort:
+			values[i] = new(sql.NullString)
+		case server.FieldCreatedAt, server.FieldUpdatedAt, server.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 Server fields.
+func (s *Server) 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 server.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			s.ID = uint64(value.Int64)
+		case server.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 {
+				s.CreatedAt = value.Time
+			}
+		case server.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 {
+				s.UpdatedAt = value.Time
+			}
+		case server.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				s.Status = uint8(value.Int64)
+			}
+		case server.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 {
+				s.DeletedAt = value.Time
+			}
+		case server.FieldName:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field name", values[i])
+			} else if value.Valid {
+				s.Name = value.String
+			}
+		case server.FieldPublicIP:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field public_ip", values[i])
+			} else if value.Valid {
+				s.PublicIP = value.String
+			}
+		case server.FieldPrivateIP:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field private_ip", values[i])
+			} else if value.Valid {
+				s.PrivateIP = value.String
+			}
+		case server.FieldAdminPort:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field admin_port", values[i])
+			} else if value.Valid {
+				s.AdminPort = value.String
+			}
+		default:
+			s.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Server.
+// This includes values selected through modifiers, order, etc.
+func (s *Server) Value(name string) (ent.Value, error) {
+	return s.selectValues.Get(name)
+}
+
+// QueryWxs queries the "wxs" edge of the Server entity.
+func (s *Server) QueryWxs() *WxQuery {
+	return NewServerClient(s.config).QueryWxs(s)
+}
+
+// Update returns a builder for updating this Server.
+// Note that you need to call Server.Unwrap() before calling this method if this Server
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (s *Server) Update() *ServerUpdateOne {
+	return NewServerClient(s.config).UpdateOne(s)
+}
+
+// Unwrap unwraps the Server 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 (s *Server) Unwrap() *Server {
+	_tx, ok := s.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Server is not a transactional entity")
+	}
+	s.config.driver = _tx.drv
+	return s
+}
+
+// String implements the fmt.Stringer.
+func (s *Server) String() string {
+	var builder strings.Builder
+	builder.WriteString("Server(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", s.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(s.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(s.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", s.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(s.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("name=")
+	builder.WriteString(s.Name)
+	builder.WriteString(", ")
+	builder.WriteString("public_ip=")
+	builder.WriteString(s.PublicIP)
+	builder.WriteString(", ")
+	builder.WriteString("private_ip=")
+	builder.WriteString(s.PrivateIP)
+	builder.WriteString(", ")
+	builder.WriteString("admin_port=")
+	builder.WriteString(s.AdminPort)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Servers is a parsable slice of Server.
+type Servers []*Server

+ 155 - 0
ent/server/server.go

@@ -0,0 +1,155 @@
+// Code generated by ent, DO NOT EDIT.
+
+package server
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the server type in the database.
+	Label = "server"
+	// 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"
+	// FieldName holds the string denoting the name field in the database.
+	FieldName = "name"
+	// FieldPublicIP holds the string denoting the public_ip field in the database.
+	FieldPublicIP = "public_ip"
+	// FieldPrivateIP holds the string denoting the private_ip field in the database.
+	FieldPrivateIP = "private_ip"
+	// FieldAdminPort holds the string denoting the admin_port field in the database.
+	FieldAdminPort = "admin_port"
+	// EdgeWxs holds the string denoting the wxs edge name in mutations.
+	EdgeWxs = "wxs"
+	// Table holds the table name of the server in the database.
+	Table = "server"
+	// WxsTable is the table that holds the wxs relation/edge.
+	WxsTable = "wx"
+	// WxsInverseTable is the table name for the Wx entity.
+	// It exists in this package in order to avoid circular dependency with the "wx" package.
+	WxsInverseTable = "wx"
+	// WxsColumn is the table column denoting the wxs relation/edge.
+	WxsColumn = "server_id"
+)
+
+// Columns holds all SQL columns for server fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldName,
+	FieldPublicIP,
+	FieldPrivateIP,
+	FieldAdminPort,
+}
+
+// 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
+)
+
+// OrderOption defines the ordering options for the Server 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()
+}
+
+// ByName orders the results by the name field.
+func ByName(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldName, opts...).ToFunc()
+}
+
+// ByPublicIP orders the results by the public_ip field.
+func ByPublicIP(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldPublicIP, opts...).ToFunc()
+}
+
+// ByPrivateIP orders the results by the private_ip field.
+func ByPrivateIP(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldPrivateIP, opts...).ToFunc()
+}
+
+// ByAdminPort orders the results by the admin_port field.
+func ByAdminPort(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAdminPort, opts...).ToFunc()
+}
+
+// ByWxsCount orders the results by wxs count.
+func ByWxsCount(opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborsCount(s, newWxsStep(), opts...)
+	}
+}
+
+// ByWxs orders the results by wxs terms.
+func ByWxs(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newWxsStep(), append([]sql.OrderTerm{term}, terms...)...)
+	}
+}
+func newWxsStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(WxsInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.O2M, false, WxsTable, WxsColumn),
+	)
+}

+ 574 - 0
ent/server/where.go

@@ -0,0 +1,574 @@
+// Code generated by ent, DO NOT EDIT.
+
+package server
+
+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.Server {
+	return predicate.Server(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.Server {
+	return predicate.Server(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.Server {
+	return predicate.Server(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.Server {
+	return predicate.Server(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.Server {
+	return predicate.Server(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.Server {
+	return predicate.Server(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
+func Name(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldName, v))
+}
+
+// PublicIP applies equality check predicate on the "public_ip" field. It's identical to PublicIPEQ.
+func PublicIP(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldPublicIP, v))
+}
+
+// PrivateIP applies equality check predicate on the "private_ip" field. It's identical to PrivateIPEQ.
+func PrivateIP(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldPrivateIP, v))
+}
+
+// AdminPort applies equality check predicate on the "admin_port" field. It's identical to AdminPortEQ.
+func AdminPort(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldAdminPort, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.Server {
+	return predicate.Server(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.Server {
+	return predicate.Server(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.Server {
+	return predicate.Server(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.Server {
+	return predicate.Server(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// NameEQ applies the EQ predicate on the "name" field.
+func NameEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldName, v))
+}
+
+// NameNEQ applies the NEQ predicate on the "name" field.
+func NameNEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldName, v))
+}
+
+// NameIn applies the In predicate on the "name" field.
+func NameIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldName, vs...))
+}
+
+// NameNotIn applies the NotIn predicate on the "name" field.
+func NameNotIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldName, vs...))
+}
+
+// NameGT applies the GT predicate on the "name" field.
+func NameGT(v string) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldName, v))
+}
+
+// NameGTE applies the GTE predicate on the "name" field.
+func NameGTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldName, v))
+}
+
+// NameLT applies the LT predicate on the "name" field.
+func NameLT(v string) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldName, v))
+}
+
+// NameLTE applies the LTE predicate on the "name" field.
+func NameLTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldName, v))
+}
+
+// NameContains applies the Contains predicate on the "name" field.
+func NameContains(v string) predicate.Server {
+	return predicate.Server(sql.FieldContains(FieldName, v))
+}
+
+// NameHasPrefix applies the HasPrefix predicate on the "name" field.
+func NameHasPrefix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasPrefix(FieldName, v))
+}
+
+// NameHasSuffix applies the HasSuffix predicate on the "name" field.
+func NameHasSuffix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasSuffix(FieldName, v))
+}
+
+// NameEqualFold applies the EqualFold predicate on the "name" field.
+func NameEqualFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldEqualFold(FieldName, v))
+}
+
+// NameContainsFold applies the ContainsFold predicate on the "name" field.
+func NameContainsFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldContainsFold(FieldName, v))
+}
+
+// PublicIPEQ applies the EQ predicate on the "public_ip" field.
+func PublicIPEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldPublicIP, v))
+}
+
+// PublicIPNEQ applies the NEQ predicate on the "public_ip" field.
+func PublicIPNEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldPublicIP, v))
+}
+
+// PublicIPIn applies the In predicate on the "public_ip" field.
+func PublicIPIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldPublicIP, vs...))
+}
+
+// PublicIPNotIn applies the NotIn predicate on the "public_ip" field.
+func PublicIPNotIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldPublicIP, vs...))
+}
+
+// PublicIPGT applies the GT predicate on the "public_ip" field.
+func PublicIPGT(v string) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldPublicIP, v))
+}
+
+// PublicIPGTE applies the GTE predicate on the "public_ip" field.
+func PublicIPGTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldPublicIP, v))
+}
+
+// PublicIPLT applies the LT predicate on the "public_ip" field.
+func PublicIPLT(v string) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldPublicIP, v))
+}
+
+// PublicIPLTE applies the LTE predicate on the "public_ip" field.
+func PublicIPLTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldPublicIP, v))
+}
+
+// PublicIPContains applies the Contains predicate on the "public_ip" field.
+func PublicIPContains(v string) predicate.Server {
+	return predicate.Server(sql.FieldContains(FieldPublicIP, v))
+}
+
+// PublicIPHasPrefix applies the HasPrefix predicate on the "public_ip" field.
+func PublicIPHasPrefix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasPrefix(FieldPublicIP, v))
+}
+
+// PublicIPHasSuffix applies the HasSuffix predicate on the "public_ip" field.
+func PublicIPHasSuffix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasSuffix(FieldPublicIP, v))
+}
+
+// PublicIPEqualFold applies the EqualFold predicate on the "public_ip" field.
+func PublicIPEqualFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldEqualFold(FieldPublicIP, v))
+}
+
+// PublicIPContainsFold applies the ContainsFold predicate on the "public_ip" field.
+func PublicIPContainsFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldContainsFold(FieldPublicIP, v))
+}
+
+// PrivateIPEQ applies the EQ predicate on the "private_ip" field.
+func PrivateIPEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldPrivateIP, v))
+}
+
+// PrivateIPNEQ applies the NEQ predicate on the "private_ip" field.
+func PrivateIPNEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldPrivateIP, v))
+}
+
+// PrivateIPIn applies the In predicate on the "private_ip" field.
+func PrivateIPIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldPrivateIP, vs...))
+}
+
+// PrivateIPNotIn applies the NotIn predicate on the "private_ip" field.
+func PrivateIPNotIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldPrivateIP, vs...))
+}
+
+// PrivateIPGT applies the GT predicate on the "private_ip" field.
+func PrivateIPGT(v string) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldPrivateIP, v))
+}
+
+// PrivateIPGTE applies the GTE predicate on the "private_ip" field.
+func PrivateIPGTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldPrivateIP, v))
+}
+
+// PrivateIPLT applies the LT predicate on the "private_ip" field.
+func PrivateIPLT(v string) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldPrivateIP, v))
+}
+
+// PrivateIPLTE applies the LTE predicate on the "private_ip" field.
+func PrivateIPLTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldPrivateIP, v))
+}
+
+// PrivateIPContains applies the Contains predicate on the "private_ip" field.
+func PrivateIPContains(v string) predicate.Server {
+	return predicate.Server(sql.FieldContains(FieldPrivateIP, v))
+}
+
+// PrivateIPHasPrefix applies the HasPrefix predicate on the "private_ip" field.
+func PrivateIPHasPrefix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasPrefix(FieldPrivateIP, v))
+}
+
+// PrivateIPHasSuffix applies the HasSuffix predicate on the "private_ip" field.
+func PrivateIPHasSuffix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasSuffix(FieldPrivateIP, v))
+}
+
+// PrivateIPEqualFold applies the EqualFold predicate on the "private_ip" field.
+func PrivateIPEqualFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldEqualFold(FieldPrivateIP, v))
+}
+
+// PrivateIPContainsFold applies the ContainsFold predicate on the "private_ip" field.
+func PrivateIPContainsFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldContainsFold(FieldPrivateIP, v))
+}
+
+// AdminPortEQ applies the EQ predicate on the "admin_port" field.
+func AdminPortEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldEQ(FieldAdminPort, v))
+}
+
+// AdminPortNEQ applies the NEQ predicate on the "admin_port" field.
+func AdminPortNEQ(v string) predicate.Server {
+	return predicate.Server(sql.FieldNEQ(FieldAdminPort, v))
+}
+
+// AdminPortIn applies the In predicate on the "admin_port" field.
+func AdminPortIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldIn(FieldAdminPort, vs...))
+}
+
+// AdminPortNotIn applies the NotIn predicate on the "admin_port" field.
+func AdminPortNotIn(vs ...string) predicate.Server {
+	return predicate.Server(sql.FieldNotIn(FieldAdminPort, vs...))
+}
+
+// AdminPortGT applies the GT predicate on the "admin_port" field.
+func AdminPortGT(v string) predicate.Server {
+	return predicate.Server(sql.FieldGT(FieldAdminPort, v))
+}
+
+// AdminPortGTE applies the GTE predicate on the "admin_port" field.
+func AdminPortGTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldGTE(FieldAdminPort, v))
+}
+
+// AdminPortLT applies the LT predicate on the "admin_port" field.
+func AdminPortLT(v string) predicate.Server {
+	return predicate.Server(sql.FieldLT(FieldAdminPort, v))
+}
+
+// AdminPortLTE applies the LTE predicate on the "admin_port" field.
+func AdminPortLTE(v string) predicate.Server {
+	return predicate.Server(sql.FieldLTE(FieldAdminPort, v))
+}
+
+// AdminPortContains applies the Contains predicate on the "admin_port" field.
+func AdminPortContains(v string) predicate.Server {
+	return predicate.Server(sql.FieldContains(FieldAdminPort, v))
+}
+
+// AdminPortHasPrefix applies the HasPrefix predicate on the "admin_port" field.
+func AdminPortHasPrefix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasPrefix(FieldAdminPort, v))
+}
+
+// AdminPortHasSuffix applies the HasSuffix predicate on the "admin_port" field.
+func AdminPortHasSuffix(v string) predicate.Server {
+	return predicate.Server(sql.FieldHasSuffix(FieldAdminPort, v))
+}
+
+// AdminPortEqualFold applies the EqualFold predicate on the "admin_port" field.
+func AdminPortEqualFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldEqualFold(FieldAdminPort, v))
+}
+
+// AdminPortContainsFold applies the ContainsFold predicate on the "admin_port" field.
+func AdminPortContainsFold(v string) predicate.Server {
+	return predicate.Server(sql.FieldContainsFold(FieldAdminPort, v))
+}
+
+// HasWxs applies the HasEdge predicate on the "wxs" edge.
+func HasWxs() predicate.Server {
+	return predicate.Server(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.O2M, false, WxsTable, WxsColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasWxsWith applies the HasEdge predicate on the "wxs" edge with a given conditions (other predicates).
+func HasWxsWith(preds ...predicate.Wx) predicate.Server {
+	return predicate.Server(func(s *sql.Selector) {
+		step := newWxsStep()
+		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.Server) predicate.Server {
+	return predicate.Server(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Server) predicate.Server {
+	return predicate.Server(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Server) predicate.Server {
+	return predicate.Server(sql.NotPredicates(p))
+}

+ 967 - 0
ent/server_create.go

@@ -0,0 +1,967 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// ServerCreate is the builder for creating a Server entity.
+type ServerCreate struct {
+	config
+	mutation *ServerMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (sc *ServerCreate) SetCreatedAt(t time.Time) *ServerCreate {
+	sc.mutation.SetCreatedAt(t)
+	return sc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (sc *ServerCreate) SetNillableCreatedAt(t *time.Time) *ServerCreate {
+	if t != nil {
+		sc.SetCreatedAt(*t)
+	}
+	return sc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (sc *ServerCreate) SetUpdatedAt(t time.Time) *ServerCreate {
+	sc.mutation.SetUpdatedAt(t)
+	return sc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (sc *ServerCreate) SetNillableUpdatedAt(t *time.Time) *ServerCreate {
+	if t != nil {
+		sc.SetUpdatedAt(*t)
+	}
+	return sc
+}
+
+// SetStatus sets the "status" field.
+func (sc *ServerCreate) SetStatus(u uint8) *ServerCreate {
+	sc.mutation.SetStatus(u)
+	return sc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (sc *ServerCreate) SetNillableStatus(u *uint8) *ServerCreate {
+	if u != nil {
+		sc.SetStatus(*u)
+	}
+	return sc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (sc *ServerCreate) SetDeletedAt(t time.Time) *ServerCreate {
+	sc.mutation.SetDeletedAt(t)
+	return sc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (sc *ServerCreate) SetNillableDeletedAt(t *time.Time) *ServerCreate {
+	if t != nil {
+		sc.SetDeletedAt(*t)
+	}
+	return sc
+}
+
+// SetName sets the "name" field.
+func (sc *ServerCreate) SetName(s string) *ServerCreate {
+	sc.mutation.SetName(s)
+	return sc
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (sc *ServerCreate) SetPublicIP(s string) *ServerCreate {
+	sc.mutation.SetPublicIP(s)
+	return sc
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (sc *ServerCreate) SetPrivateIP(s string) *ServerCreate {
+	sc.mutation.SetPrivateIP(s)
+	return sc
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (sc *ServerCreate) SetAdminPort(s string) *ServerCreate {
+	sc.mutation.SetAdminPort(s)
+	return sc
+}
+
+// SetID sets the "id" field.
+func (sc *ServerCreate) SetID(u uint64) *ServerCreate {
+	sc.mutation.SetID(u)
+	return sc
+}
+
+// AddWxIDs adds the "wxs" edge to the Wx entity by IDs.
+func (sc *ServerCreate) AddWxIDs(ids ...uint64) *ServerCreate {
+	sc.mutation.AddWxIDs(ids...)
+	return sc
+}
+
+// AddWxs adds the "wxs" edges to the Wx entity.
+func (sc *ServerCreate) AddWxs(w ...*Wx) *ServerCreate {
+	ids := make([]uint64, len(w))
+	for i := range w {
+		ids[i] = w[i].ID
+	}
+	return sc.AddWxIDs(ids...)
+}
+
+// Mutation returns the ServerMutation object of the builder.
+func (sc *ServerCreate) Mutation() *ServerMutation {
+	return sc.mutation
+}
+
+// Save creates the Server in the database.
+func (sc *ServerCreate) Save(ctx context.Context) (*Server, error) {
+	if err := sc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, sc.sqlSave, sc.mutation, sc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (sc *ServerCreate) SaveX(ctx context.Context) *Server {
+	v, err := sc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (sc *ServerCreate) Exec(ctx context.Context) error {
+	_, err := sc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (sc *ServerCreate) ExecX(ctx context.Context) {
+	if err := sc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (sc *ServerCreate) defaults() error {
+	if _, ok := sc.mutation.CreatedAt(); !ok {
+		if server.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized server.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := server.DefaultCreatedAt()
+		sc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := sc.mutation.UpdatedAt(); !ok {
+		if server.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized server.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := server.DefaultUpdatedAt()
+		sc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := sc.mutation.Status(); !ok {
+		v := server.DefaultStatus
+		sc.mutation.SetStatus(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (sc *ServerCreate) check() error {
+	if _, ok := sc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Server.created_at"`)}
+	}
+	if _, ok := sc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Server.updated_at"`)}
+	}
+	if _, ok := sc.mutation.Name(); !ok {
+		return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Server.name"`)}
+	}
+	if _, ok := sc.mutation.PublicIP(); !ok {
+		return &ValidationError{Name: "public_ip", err: errors.New(`ent: missing required field "Server.public_ip"`)}
+	}
+	if _, ok := sc.mutation.PrivateIP(); !ok {
+		return &ValidationError{Name: "private_ip", err: errors.New(`ent: missing required field "Server.private_ip"`)}
+	}
+	if _, ok := sc.mutation.AdminPort(); !ok {
+		return &ValidationError{Name: "admin_port", err: errors.New(`ent: missing required field "Server.admin_port"`)}
+	}
+	return nil
+}
+
+func (sc *ServerCreate) sqlSave(ctx context.Context) (*Server, error) {
+	if err := sc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := sc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, sc.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)
+	}
+	sc.mutation.id = &_node.ID
+	sc.mutation.done = true
+	return _node, nil
+}
+
+func (sc *ServerCreate) createSpec() (*Server, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Server{config: sc.config}
+		_spec = sqlgraph.NewCreateSpec(server.Table, sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = sc.conflict
+	if id, ok := sc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := sc.mutation.CreatedAt(); ok {
+		_spec.SetField(server.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := sc.mutation.UpdatedAt(); ok {
+		_spec.SetField(server.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := sc.mutation.Status(); ok {
+		_spec.SetField(server.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := sc.mutation.DeletedAt(); ok {
+		_spec.SetField(server.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if value, ok := sc.mutation.Name(); ok {
+		_spec.SetField(server.FieldName, field.TypeString, value)
+		_node.Name = value
+	}
+	if value, ok := sc.mutation.PublicIP(); ok {
+		_spec.SetField(server.FieldPublicIP, field.TypeString, value)
+		_node.PublicIP = value
+	}
+	if value, ok := sc.mutation.PrivateIP(); ok {
+		_spec.SetField(server.FieldPrivateIP, field.TypeString, value)
+		_node.PrivateIP = value
+	}
+	if value, ok := sc.mutation.AdminPort(); ok {
+		_spec.SetField(server.FieldAdminPort, field.TypeString, value)
+		_node.AdminPort = value
+	}
+	if nodes := sc.mutation.WxsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.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.Server.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.ServerUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (sc *ServerCreate) OnConflict(opts ...sql.ConflictOption) *ServerUpsertOne {
+	sc.conflict = opts
+	return &ServerUpsertOne{
+		create: sc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Server.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (sc *ServerCreate) OnConflictColumns(columns ...string) *ServerUpsertOne {
+	sc.conflict = append(sc.conflict, sql.ConflictColumns(columns...))
+	return &ServerUpsertOne{
+		create: sc,
+	}
+}
+
+type (
+	// ServerUpsertOne is the builder for "upsert"-ing
+	//  one Server node.
+	ServerUpsertOne struct {
+		create *ServerCreate
+	}
+
+	// ServerUpsert is the "OnConflict" setter.
+	ServerUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ServerUpsert) SetUpdatedAt(v time.Time) *ServerUpsert {
+	u.Set(server.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ServerUpsert) UpdateUpdatedAt() *ServerUpsert {
+	u.SetExcluded(server.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *ServerUpsert) SetStatus(v uint8) *ServerUpsert {
+	u.Set(server.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ServerUpsert) UpdateStatus() *ServerUpsert {
+	u.SetExcluded(server.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ServerUpsert) AddStatus(v uint8) *ServerUpsert {
+	u.Add(server.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ServerUpsert) ClearStatus() *ServerUpsert {
+	u.SetNull(server.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ServerUpsert) SetDeletedAt(v time.Time) *ServerUpsert {
+	u.Set(server.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ServerUpsert) UpdateDeletedAt() *ServerUpsert {
+	u.SetExcluded(server.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ServerUpsert) ClearDeletedAt() *ServerUpsert {
+	u.SetNull(server.FieldDeletedAt)
+	return u
+}
+
+// SetName sets the "name" field.
+func (u *ServerUpsert) SetName(v string) *ServerUpsert {
+	u.Set(server.FieldName, v)
+	return u
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *ServerUpsert) UpdateName() *ServerUpsert {
+	u.SetExcluded(server.FieldName)
+	return u
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (u *ServerUpsert) SetPublicIP(v string) *ServerUpsert {
+	u.Set(server.FieldPublicIP, v)
+	return u
+}
+
+// UpdatePublicIP sets the "public_ip" field to the value that was provided on create.
+func (u *ServerUpsert) UpdatePublicIP() *ServerUpsert {
+	u.SetExcluded(server.FieldPublicIP)
+	return u
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (u *ServerUpsert) SetPrivateIP(v string) *ServerUpsert {
+	u.Set(server.FieldPrivateIP, v)
+	return u
+}
+
+// UpdatePrivateIP sets the "private_ip" field to the value that was provided on create.
+func (u *ServerUpsert) UpdatePrivateIP() *ServerUpsert {
+	u.SetExcluded(server.FieldPrivateIP)
+	return u
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (u *ServerUpsert) SetAdminPort(v string) *ServerUpsert {
+	u.Set(server.FieldAdminPort, v)
+	return u
+}
+
+// UpdateAdminPort sets the "admin_port" field to the value that was provided on create.
+func (u *ServerUpsert) UpdateAdminPort() *ServerUpsert {
+	u.SetExcluded(server.FieldAdminPort)
+	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.Server.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(server.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *ServerUpsertOne) UpdateNewValues() *ServerUpsertOne {
+	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(server.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(server.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Server.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *ServerUpsertOne) Ignore() *ServerUpsertOne {
+	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 *ServerUpsertOne) DoNothing() *ServerUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the ServerCreate.OnConflict
+// documentation for more info.
+func (u *ServerUpsertOne) Update(set func(*ServerUpsert)) *ServerUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&ServerUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ServerUpsertOne) SetUpdatedAt(v time.Time) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdateUpdatedAt() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *ServerUpsertOne) SetStatus(v uint8) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ServerUpsertOne) AddStatus(v uint8) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdateStatus() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ServerUpsertOne) ClearStatus() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ServerUpsertOne) SetDeletedAt(v time.Time) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdateDeletedAt() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ServerUpsertOne) ClearDeletedAt() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetName sets the "name" field.
+func (u *ServerUpsertOne) SetName(v string) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetName(v)
+	})
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdateName() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateName()
+	})
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (u *ServerUpsertOne) SetPublicIP(v string) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetPublicIP(v)
+	})
+}
+
+// UpdatePublicIP sets the "public_ip" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdatePublicIP() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdatePublicIP()
+	})
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (u *ServerUpsertOne) SetPrivateIP(v string) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetPrivateIP(v)
+	})
+}
+
+// UpdatePrivateIP sets the "private_ip" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdatePrivateIP() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdatePrivateIP()
+	})
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (u *ServerUpsertOne) SetAdminPort(v string) *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetAdminPort(v)
+	})
+}
+
+// UpdateAdminPort sets the "admin_port" field to the value that was provided on create.
+func (u *ServerUpsertOne) UpdateAdminPort() *ServerUpsertOne {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateAdminPort()
+	})
+}
+
+// Exec executes the query.
+func (u *ServerUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for ServerCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *ServerUpsertOne) 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 *ServerUpsertOne) 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 *ServerUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// ServerCreateBulk is the builder for creating many Server entities in bulk.
+type ServerCreateBulk struct {
+	config
+	err      error
+	builders []*ServerCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Server entities in the database.
+func (scb *ServerCreateBulk) Save(ctx context.Context) ([]*Server, error) {
+	if scb.err != nil {
+		return nil, scb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(scb.builders))
+	nodes := make([]*Server, len(scb.builders))
+	mutators := make([]Mutator, len(scb.builders))
+	for i := range scb.builders {
+		func(i int, root context.Context) {
+			builder := scb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*ServerMutation)
+				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, scb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = scb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, scb.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, scb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (scb *ServerCreateBulk) SaveX(ctx context.Context) []*Server {
+	v, err := scb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (scb *ServerCreateBulk) Exec(ctx context.Context) error {
+	_, err := scb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (scb *ServerCreateBulk) ExecX(ctx context.Context) {
+	if err := scb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Server.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.ServerUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (scb *ServerCreateBulk) OnConflict(opts ...sql.ConflictOption) *ServerUpsertBulk {
+	scb.conflict = opts
+	return &ServerUpsertBulk{
+		create: scb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Server.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (scb *ServerCreateBulk) OnConflictColumns(columns ...string) *ServerUpsertBulk {
+	scb.conflict = append(scb.conflict, sql.ConflictColumns(columns...))
+	return &ServerUpsertBulk{
+		create: scb,
+	}
+}
+
+// ServerUpsertBulk is the builder for "upsert"-ing
+// a bulk of Server nodes.
+type ServerUpsertBulk struct {
+	create *ServerCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Server.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(server.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *ServerUpsertBulk) UpdateNewValues() *ServerUpsertBulk {
+	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(server.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(server.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Server.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *ServerUpsertBulk) Ignore() *ServerUpsertBulk {
+	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 *ServerUpsertBulk) DoNothing() *ServerUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the ServerCreateBulk.OnConflict
+// documentation for more info.
+func (u *ServerUpsertBulk) Update(set func(*ServerUpsert)) *ServerUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&ServerUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *ServerUpsertBulk) SetUpdatedAt(v time.Time) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdateUpdatedAt() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *ServerUpsertBulk) SetStatus(v uint8) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *ServerUpsertBulk) AddStatus(v uint8) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdateStatus() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *ServerUpsertBulk) ClearStatus() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *ServerUpsertBulk) SetDeletedAt(v time.Time) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdateDeletedAt() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *ServerUpsertBulk) ClearDeletedAt() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetName sets the "name" field.
+func (u *ServerUpsertBulk) SetName(v string) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetName(v)
+	})
+}
+
+// UpdateName sets the "name" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdateName() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateName()
+	})
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (u *ServerUpsertBulk) SetPublicIP(v string) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetPublicIP(v)
+	})
+}
+
+// UpdatePublicIP sets the "public_ip" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdatePublicIP() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdatePublicIP()
+	})
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (u *ServerUpsertBulk) SetPrivateIP(v string) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetPrivateIP(v)
+	})
+}
+
+// UpdatePrivateIP sets the "private_ip" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdatePrivateIP() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdatePrivateIP()
+	})
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (u *ServerUpsertBulk) SetAdminPort(v string) *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.SetAdminPort(v)
+	})
+}
+
+// UpdateAdminPort sets the "admin_port" field to the value that was provided on create.
+func (u *ServerUpsertBulk) UpdateAdminPort() *ServerUpsertBulk {
+	return u.Update(func(s *ServerUpsert) {
+		s.UpdateAdminPort()
+	})
+}
+
+// Exec executes the query.
+func (u *ServerUpsertBulk) 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 ServerCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for ServerCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *ServerUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/server_delete.go

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

+ 605 - 0
ent/server_query.go

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

+ 647 - 0
ent/server_update.go

@@ -0,0 +1,647 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// ServerUpdate is the builder for updating Server entities.
+type ServerUpdate struct {
+	config
+	hooks    []Hook
+	mutation *ServerMutation
+}
+
+// Where appends a list predicates to the ServerUpdate builder.
+func (su *ServerUpdate) Where(ps ...predicate.Server) *ServerUpdate {
+	su.mutation.Where(ps...)
+	return su
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (su *ServerUpdate) SetUpdatedAt(t time.Time) *ServerUpdate {
+	su.mutation.SetUpdatedAt(t)
+	return su
+}
+
+// SetStatus sets the "status" field.
+func (su *ServerUpdate) SetStatus(u uint8) *ServerUpdate {
+	su.mutation.ResetStatus()
+	su.mutation.SetStatus(u)
+	return su
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (su *ServerUpdate) SetNillableStatus(u *uint8) *ServerUpdate {
+	if u != nil {
+		su.SetStatus(*u)
+	}
+	return su
+}
+
+// AddStatus adds u to the "status" field.
+func (su *ServerUpdate) AddStatus(u int8) *ServerUpdate {
+	su.mutation.AddStatus(u)
+	return su
+}
+
+// ClearStatus clears the value of the "status" field.
+func (su *ServerUpdate) ClearStatus() *ServerUpdate {
+	su.mutation.ClearStatus()
+	return su
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (su *ServerUpdate) SetDeletedAt(t time.Time) *ServerUpdate {
+	su.mutation.SetDeletedAt(t)
+	return su
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (su *ServerUpdate) SetNillableDeletedAt(t *time.Time) *ServerUpdate {
+	if t != nil {
+		su.SetDeletedAt(*t)
+	}
+	return su
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (su *ServerUpdate) ClearDeletedAt() *ServerUpdate {
+	su.mutation.ClearDeletedAt()
+	return su
+}
+
+// SetName sets the "name" field.
+func (su *ServerUpdate) SetName(s string) *ServerUpdate {
+	su.mutation.SetName(s)
+	return su
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (su *ServerUpdate) SetNillableName(s *string) *ServerUpdate {
+	if s != nil {
+		su.SetName(*s)
+	}
+	return su
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (su *ServerUpdate) SetPublicIP(s string) *ServerUpdate {
+	su.mutation.SetPublicIP(s)
+	return su
+}
+
+// SetNillablePublicIP sets the "public_ip" field if the given value is not nil.
+func (su *ServerUpdate) SetNillablePublicIP(s *string) *ServerUpdate {
+	if s != nil {
+		su.SetPublicIP(*s)
+	}
+	return su
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (su *ServerUpdate) SetPrivateIP(s string) *ServerUpdate {
+	su.mutation.SetPrivateIP(s)
+	return su
+}
+
+// SetNillablePrivateIP sets the "private_ip" field if the given value is not nil.
+func (su *ServerUpdate) SetNillablePrivateIP(s *string) *ServerUpdate {
+	if s != nil {
+		su.SetPrivateIP(*s)
+	}
+	return su
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (su *ServerUpdate) SetAdminPort(s string) *ServerUpdate {
+	su.mutation.SetAdminPort(s)
+	return su
+}
+
+// SetNillableAdminPort sets the "admin_port" field if the given value is not nil.
+func (su *ServerUpdate) SetNillableAdminPort(s *string) *ServerUpdate {
+	if s != nil {
+		su.SetAdminPort(*s)
+	}
+	return su
+}
+
+// AddWxIDs adds the "wxs" edge to the Wx entity by IDs.
+func (su *ServerUpdate) AddWxIDs(ids ...uint64) *ServerUpdate {
+	su.mutation.AddWxIDs(ids...)
+	return su
+}
+
+// AddWxs adds the "wxs" edges to the Wx entity.
+func (su *ServerUpdate) AddWxs(w ...*Wx) *ServerUpdate {
+	ids := make([]uint64, len(w))
+	for i := range w {
+		ids[i] = w[i].ID
+	}
+	return su.AddWxIDs(ids...)
+}
+
+// Mutation returns the ServerMutation object of the builder.
+func (su *ServerUpdate) Mutation() *ServerMutation {
+	return su.mutation
+}
+
+// ClearWxs clears all "wxs" edges to the Wx entity.
+func (su *ServerUpdate) ClearWxs() *ServerUpdate {
+	su.mutation.ClearWxs()
+	return su
+}
+
+// RemoveWxIDs removes the "wxs" edge to Wx entities by IDs.
+func (su *ServerUpdate) RemoveWxIDs(ids ...uint64) *ServerUpdate {
+	su.mutation.RemoveWxIDs(ids...)
+	return su
+}
+
+// RemoveWxs removes "wxs" edges to Wx entities.
+func (su *ServerUpdate) RemoveWxs(w ...*Wx) *ServerUpdate {
+	ids := make([]uint64, len(w))
+	for i := range w {
+		ids[i] = w[i].ID
+	}
+	return su.RemoveWxIDs(ids...)
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (su *ServerUpdate) Save(ctx context.Context) (int, error) {
+	if err := su.defaults(); err != nil {
+		return 0, err
+	}
+	return withHooks(ctx, su.sqlSave, su.mutation, su.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (su *ServerUpdate) SaveX(ctx context.Context) int {
+	affected, err := su.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (su *ServerUpdate) Exec(ctx context.Context) error {
+	_, err := su.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (su *ServerUpdate) ExecX(ctx context.Context) {
+	if err := su.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (su *ServerUpdate) defaults() error {
+	if _, ok := su.mutation.UpdatedAt(); !ok {
+		if server.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized server.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := server.UpdateDefaultUpdatedAt()
+		su.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (su *ServerUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	_spec := sqlgraph.NewUpdateSpec(server.Table, server.Columns, sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64))
+	if ps := su.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := su.mutation.UpdatedAt(); ok {
+		_spec.SetField(server.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := su.mutation.Status(); ok {
+		_spec.SetField(server.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := su.mutation.AddedStatus(); ok {
+		_spec.AddField(server.FieldStatus, field.TypeUint8, value)
+	}
+	if su.mutation.StatusCleared() {
+		_spec.ClearField(server.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := su.mutation.DeletedAt(); ok {
+		_spec.SetField(server.FieldDeletedAt, field.TypeTime, value)
+	}
+	if su.mutation.DeletedAtCleared() {
+		_spec.ClearField(server.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := su.mutation.Name(); ok {
+		_spec.SetField(server.FieldName, field.TypeString, value)
+	}
+	if value, ok := su.mutation.PublicIP(); ok {
+		_spec.SetField(server.FieldPublicIP, field.TypeString, value)
+	}
+	if value, ok := su.mutation.PrivateIP(); ok {
+		_spec.SetField(server.FieldPrivateIP, field.TypeString, value)
+	}
+	if value, ok := su.mutation.AdminPort(); ok {
+		_spec.SetField(server.FieldAdminPort, field.TypeString, value)
+	}
+	if su.mutation.WxsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := su.mutation.RemovedWxsIDs(); len(nodes) > 0 && !su.mutation.WxsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.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 := su.mutation.WxsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.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, su.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{server.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	su.mutation.done = true
+	return n, nil
+}
+
+// ServerUpdateOne is the builder for updating a single Server entity.
+type ServerUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *ServerMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (suo *ServerUpdateOne) SetUpdatedAt(t time.Time) *ServerUpdateOne {
+	suo.mutation.SetUpdatedAt(t)
+	return suo
+}
+
+// SetStatus sets the "status" field.
+func (suo *ServerUpdateOne) SetStatus(u uint8) *ServerUpdateOne {
+	suo.mutation.ResetStatus()
+	suo.mutation.SetStatus(u)
+	return suo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillableStatus(u *uint8) *ServerUpdateOne {
+	if u != nil {
+		suo.SetStatus(*u)
+	}
+	return suo
+}
+
+// AddStatus adds u to the "status" field.
+func (suo *ServerUpdateOne) AddStatus(u int8) *ServerUpdateOne {
+	suo.mutation.AddStatus(u)
+	return suo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (suo *ServerUpdateOne) ClearStatus() *ServerUpdateOne {
+	suo.mutation.ClearStatus()
+	return suo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (suo *ServerUpdateOne) SetDeletedAt(t time.Time) *ServerUpdateOne {
+	suo.mutation.SetDeletedAt(t)
+	return suo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillableDeletedAt(t *time.Time) *ServerUpdateOne {
+	if t != nil {
+		suo.SetDeletedAt(*t)
+	}
+	return suo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (suo *ServerUpdateOne) ClearDeletedAt() *ServerUpdateOne {
+	suo.mutation.ClearDeletedAt()
+	return suo
+}
+
+// SetName sets the "name" field.
+func (suo *ServerUpdateOne) SetName(s string) *ServerUpdateOne {
+	suo.mutation.SetName(s)
+	return suo
+}
+
+// SetNillableName sets the "name" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillableName(s *string) *ServerUpdateOne {
+	if s != nil {
+		suo.SetName(*s)
+	}
+	return suo
+}
+
+// SetPublicIP sets the "public_ip" field.
+func (suo *ServerUpdateOne) SetPublicIP(s string) *ServerUpdateOne {
+	suo.mutation.SetPublicIP(s)
+	return suo
+}
+
+// SetNillablePublicIP sets the "public_ip" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillablePublicIP(s *string) *ServerUpdateOne {
+	if s != nil {
+		suo.SetPublicIP(*s)
+	}
+	return suo
+}
+
+// SetPrivateIP sets the "private_ip" field.
+func (suo *ServerUpdateOne) SetPrivateIP(s string) *ServerUpdateOne {
+	suo.mutation.SetPrivateIP(s)
+	return suo
+}
+
+// SetNillablePrivateIP sets the "private_ip" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillablePrivateIP(s *string) *ServerUpdateOne {
+	if s != nil {
+		suo.SetPrivateIP(*s)
+	}
+	return suo
+}
+
+// SetAdminPort sets the "admin_port" field.
+func (suo *ServerUpdateOne) SetAdminPort(s string) *ServerUpdateOne {
+	suo.mutation.SetAdminPort(s)
+	return suo
+}
+
+// SetNillableAdminPort sets the "admin_port" field if the given value is not nil.
+func (suo *ServerUpdateOne) SetNillableAdminPort(s *string) *ServerUpdateOne {
+	if s != nil {
+		suo.SetAdminPort(*s)
+	}
+	return suo
+}
+
+// AddWxIDs adds the "wxs" edge to the Wx entity by IDs.
+func (suo *ServerUpdateOne) AddWxIDs(ids ...uint64) *ServerUpdateOne {
+	suo.mutation.AddWxIDs(ids...)
+	return suo
+}
+
+// AddWxs adds the "wxs" edges to the Wx entity.
+func (suo *ServerUpdateOne) AddWxs(w ...*Wx) *ServerUpdateOne {
+	ids := make([]uint64, len(w))
+	for i := range w {
+		ids[i] = w[i].ID
+	}
+	return suo.AddWxIDs(ids...)
+}
+
+// Mutation returns the ServerMutation object of the builder.
+func (suo *ServerUpdateOne) Mutation() *ServerMutation {
+	return suo.mutation
+}
+
+// ClearWxs clears all "wxs" edges to the Wx entity.
+func (suo *ServerUpdateOne) ClearWxs() *ServerUpdateOne {
+	suo.mutation.ClearWxs()
+	return suo
+}
+
+// RemoveWxIDs removes the "wxs" edge to Wx entities by IDs.
+func (suo *ServerUpdateOne) RemoveWxIDs(ids ...uint64) *ServerUpdateOne {
+	suo.mutation.RemoveWxIDs(ids...)
+	return suo
+}
+
+// RemoveWxs removes "wxs" edges to Wx entities.
+func (suo *ServerUpdateOne) RemoveWxs(w ...*Wx) *ServerUpdateOne {
+	ids := make([]uint64, len(w))
+	for i := range w {
+		ids[i] = w[i].ID
+	}
+	return suo.RemoveWxIDs(ids...)
+}
+
+// Where appends a list predicates to the ServerUpdate builder.
+func (suo *ServerUpdateOne) Where(ps ...predicate.Server) *ServerUpdateOne {
+	suo.mutation.Where(ps...)
+	return suo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (suo *ServerUpdateOne) Select(field string, fields ...string) *ServerUpdateOne {
+	suo.fields = append([]string{field}, fields...)
+	return suo
+}
+
+// Save executes the query and returns the updated Server entity.
+func (suo *ServerUpdateOne) Save(ctx context.Context) (*Server, error) {
+	if err := suo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, suo.sqlSave, suo.mutation, suo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (suo *ServerUpdateOne) SaveX(ctx context.Context) *Server {
+	node, err := suo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (suo *ServerUpdateOne) Exec(ctx context.Context) error {
+	_, err := suo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (suo *ServerUpdateOne) ExecX(ctx context.Context) {
+	if err := suo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (suo *ServerUpdateOne) defaults() error {
+	if _, ok := suo.mutation.UpdatedAt(); !ok {
+		if server.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized server.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := server.UpdateDefaultUpdatedAt()
+		suo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (suo *ServerUpdateOne) sqlSave(ctx context.Context) (_node *Server, err error) {
+	_spec := sqlgraph.NewUpdateSpec(server.Table, server.Columns, sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64))
+	id, ok := suo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Server.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := suo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, server.FieldID)
+		for _, f := range fields {
+			if !server.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != server.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := suo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := suo.mutation.UpdatedAt(); ok {
+		_spec.SetField(server.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := suo.mutation.Status(); ok {
+		_spec.SetField(server.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := suo.mutation.AddedStatus(); ok {
+		_spec.AddField(server.FieldStatus, field.TypeUint8, value)
+	}
+	if suo.mutation.StatusCleared() {
+		_spec.ClearField(server.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := suo.mutation.DeletedAt(); ok {
+		_spec.SetField(server.FieldDeletedAt, field.TypeTime, value)
+	}
+	if suo.mutation.DeletedAtCleared() {
+		_spec.ClearField(server.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := suo.mutation.Name(); ok {
+		_spec.SetField(server.FieldName, field.TypeString, value)
+	}
+	if value, ok := suo.mutation.PublicIP(); ok {
+		_spec.SetField(server.FieldPublicIP, field.TypeString, value)
+	}
+	if value, ok := suo.mutation.PrivateIP(); ok {
+		_spec.SetField(server.FieldPrivateIP, field.TypeString, value)
+	}
+	if value, ok := suo.mutation.AdminPort(); ok {
+		_spec.SetField(server.FieldAdminPort, field.TypeString, value)
+	}
+	if suo.mutation.WxsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := suo.mutation.RemovedWxsIDs(); len(nodes) > 0 && !suo.mutation.WxsCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.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 := suo.mutation.WxsIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.O2M,
+			Inverse: false,
+			Table:   server.WxsTable,
+			Columns: []string{server.WxsColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &Server{config: suo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, suo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{server.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	suo.mutation.done = true
+	return _node, nil
+}

+ 893 - 0
ent/set_not_nil.go

@@ -0,0 +1,893 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import "time"
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilUpdatedAt(value *time.Time) *ContactUpdate {
+	if value != nil {
+		return c.SetUpdatedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilUpdatedAt(value *time.Time) *ContactUpdateOne {
+	if value != nil {
+		return c.SetUpdatedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilUpdatedAt(value *time.Time) *ContactCreate {
+	if value != nil {
+		return c.SetUpdatedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilStatus(value *uint8) *ContactUpdate {
+	if value != nil {
+		return c.SetStatus(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilStatus(value *uint8) *ContactUpdateOne {
+	if value != nil {
+		return c.SetStatus(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilStatus(value *uint8) *ContactCreate {
+	if value != nil {
+		return c.SetStatus(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilDeletedAt(value *time.Time) *ContactUpdate {
+	if value != nil {
+		return c.SetDeletedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilDeletedAt(value *time.Time) *ContactUpdateOne {
+	if value != nil {
+		return c.SetDeletedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilDeletedAt(value *time.Time) *ContactCreate {
+	if value != nil {
+		return c.SetDeletedAt(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilWxWxid(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetWxWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilWxWxid(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetWxWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilWxWxid(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetWxWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilType(value *int) *ContactUpdate {
+	if value != nil {
+		return c.SetType(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilType(value *int) *ContactUpdateOne {
+	if value != nil {
+		return c.SetType(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilType(value *int) *ContactCreate {
+	if value != nil {
+		return c.SetType(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilWxid(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilWxid(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilWxid(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetWxid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilAccount(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetAccount(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilAccount(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetAccount(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilAccount(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetAccount(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilNickname(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetNickname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilNickname(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetNickname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilNickname(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetNickname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilMarkname(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetMarkname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilMarkname(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetMarkname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilMarkname(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetMarkname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilHeadimg(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetHeadimg(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilHeadimg(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetHeadimg(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilHeadimg(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetHeadimg(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilSex(value *int) *ContactUpdate {
+	if value != nil {
+		return c.SetSex(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilSex(value *int) *ContactUpdateOne {
+	if value != nil {
+		return c.SetSex(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilSex(value *int) *ContactCreate {
+	if value != nil {
+		return c.SetSex(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilStarrole(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetStarrole(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilStarrole(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetStarrole(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilStarrole(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetStarrole(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilDontseeit(value *int) *ContactUpdate {
+	if value != nil {
+		return c.SetDontseeit(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilDontseeit(value *int) *ContactUpdateOne {
+	if value != nil {
+		return c.SetDontseeit(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilDontseeit(value *int) *ContactCreate {
+	if value != nil {
+		return c.SetDontseeit(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilDontseeme(value *int) *ContactUpdate {
+	if value != nil {
+		return c.SetDontseeme(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilDontseeme(value *int) *ContactUpdateOne {
+	if value != nil {
+		return c.SetDontseeme(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilDontseeme(value *int) *ContactCreate {
+	if value != nil {
+		return c.SetDontseeme(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilLag(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetLag(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilLag(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetLag(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilLag(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetLag(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilGid(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetGid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilGid(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetGid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilGid(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetGid(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilGname(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetGname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilGname(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetGname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilGname(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetGname(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdate) SetNotNilV3(value *string) *ContactUpdate {
+	if value != nil {
+		return c.SetV3(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactUpdateOne) SetNotNilV3(value *string) *ContactUpdateOne {
+	if value != nil {
+		return c.SetV3(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (c *ContactCreate) SetNotNilV3(value *string) *ContactCreate {
+	if value != nil {
+		return c.SetV3(*value)
+	}
+	return c
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilUpdatedAt(value *time.Time) *ServerUpdate {
+	if value != nil {
+		return s.SetUpdatedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilUpdatedAt(value *time.Time) *ServerUpdateOne {
+	if value != nil {
+		return s.SetUpdatedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilUpdatedAt(value *time.Time) *ServerCreate {
+	if value != nil {
+		return s.SetUpdatedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilStatus(value *uint8) *ServerUpdate {
+	if value != nil {
+		return s.SetStatus(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilStatus(value *uint8) *ServerUpdateOne {
+	if value != nil {
+		return s.SetStatus(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilStatus(value *uint8) *ServerCreate {
+	if value != nil {
+		return s.SetStatus(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilDeletedAt(value *time.Time) *ServerUpdate {
+	if value != nil {
+		return s.SetDeletedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilDeletedAt(value *time.Time) *ServerUpdateOne {
+	if value != nil {
+		return s.SetDeletedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilDeletedAt(value *time.Time) *ServerCreate {
+	if value != nil {
+		return s.SetDeletedAt(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilName(value *string) *ServerUpdate {
+	if value != nil {
+		return s.SetName(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilName(value *string) *ServerUpdateOne {
+	if value != nil {
+		return s.SetName(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilName(value *string) *ServerCreate {
+	if value != nil {
+		return s.SetName(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilPublicIP(value *string) *ServerUpdate {
+	if value != nil {
+		return s.SetPublicIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilPublicIP(value *string) *ServerUpdateOne {
+	if value != nil {
+		return s.SetPublicIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilPublicIP(value *string) *ServerCreate {
+	if value != nil {
+		return s.SetPublicIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilPrivateIP(value *string) *ServerUpdate {
+	if value != nil {
+		return s.SetPrivateIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilPrivateIP(value *string) *ServerUpdateOne {
+	if value != nil {
+		return s.SetPrivateIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilPrivateIP(value *string) *ServerCreate {
+	if value != nil {
+		return s.SetPrivateIP(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdate) SetNotNilAdminPort(value *string) *ServerUpdate {
+	if value != nil {
+		return s.SetAdminPort(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerUpdateOne) SetNotNilAdminPort(value *string) *ServerUpdateOne {
+	if value != nil {
+		return s.SetAdminPort(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (s *ServerCreate) SetNotNilAdminPort(value *string) *ServerCreate {
+	if value != nil {
+		return s.SetAdminPort(*value)
+	}
+	return s
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilUpdatedAt(value *time.Time) *WxUpdate {
+	if value != nil {
+		return w.SetUpdatedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilUpdatedAt(value *time.Time) *WxUpdateOne {
+	if value != nil {
+		return w.SetUpdatedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilUpdatedAt(value *time.Time) *WxCreate {
+	if value != nil {
+		return w.SetUpdatedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilStatus(value *uint8) *WxUpdate {
+	if value != nil {
+		return w.SetStatus(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilStatus(value *uint8) *WxUpdateOne {
+	if value != nil {
+		return w.SetStatus(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilStatus(value *uint8) *WxCreate {
+	if value != nil {
+		return w.SetStatus(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilDeletedAt(value *time.Time) *WxUpdate {
+	if value != nil {
+		return w.SetDeletedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilDeletedAt(value *time.Time) *WxUpdateOne {
+	if value != nil {
+		return w.SetDeletedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilDeletedAt(value *time.Time) *WxCreate {
+	if value != nil {
+		return w.SetDeletedAt(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilServerID(value *uint64) *WxUpdate {
+	if value != nil {
+		return w.SetServerID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilServerID(value *uint64) *WxUpdateOne {
+	if value != nil {
+		return w.SetServerID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilServerID(value *uint64) *WxCreate {
+	if value != nil {
+		return w.SetServerID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilPort(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetPort(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilPort(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetPort(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilPort(value *string) *WxCreate {
+	if value != nil {
+		return w.SetPort(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilProcessID(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetProcessID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilProcessID(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetProcessID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilProcessID(value *string) *WxCreate {
+	if value != nil {
+		return w.SetProcessID(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilCallback(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetCallback(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilCallback(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetCallback(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilCallback(value *string) *WxCreate {
+	if value != nil {
+		return w.SetCallback(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilWxid(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetWxid(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilWxid(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetWxid(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilWxid(value *string) *WxCreate {
+	if value != nil {
+		return w.SetWxid(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilAccount(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetAccount(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilAccount(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetAccount(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilAccount(value *string) *WxCreate {
+	if value != nil {
+		return w.SetAccount(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilNickname(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetNickname(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilNickname(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetNickname(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilNickname(value *string) *WxCreate {
+	if value != nil {
+		return w.SetNickname(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilTel(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetTel(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilTel(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetTel(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilTel(value *string) *WxCreate {
+	if value != nil {
+		return w.SetTel(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdate) SetNotNilHeadBig(value *string) *WxUpdate {
+	if value != nil {
+		return w.SetHeadBig(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxUpdateOne) SetNotNilHeadBig(value *string) *WxUpdateOne {
+	if value != nil {
+		return w.SetHeadBig(*value)
+	}
+	return w
+}
+
+// set field if value's pointer is not nil.
+func (w *WxCreate) SetNotNilHeadBig(value *string) *WxCreate {
+	if value != nil {
+		return w.SetHeadBig(*value)
+	}
+	return w
+}

+ 168 - 0
ent/template/pagination.tmpl

@@ -0,0 +1,168 @@
+{{/*
+Copyright 2022-present Ryan SU (github.com/suyuan32). All rights reserved.
+This source code is licensed under the Apache 2.0 license found
+in the LICENSE file in the root directory of this source tree.
+*/}}
+
+{{ define "pagination" }}
+    {{- /*gotype: entgo.io/ent/entc/gen.Graph*/ -}}
+
+    {{ template "header" $ }}
+    {{ $pkg := base $.Config.Package }}
+    {{ template "import" $ }}
+
+    const errInvalidPage = "INVALID_PAGE"
+
+    const (
+        listField = "list"
+        pageNumField = "pageNum"
+        pageSizeField = "pageSize"
+    )
+
+    type PageDetails struct {
+        Page  uint64 `json:"page"`
+        Size  uint64 `json:"size"`
+        Total uint64 `json:"total"`
+    }
+
+    // OrderDirection defines the directions in which to order a list of items.
+    type OrderDirection string
+
+    const (
+        // OrderDirectionAsc specifies an ascending order.
+        OrderDirectionAsc OrderDirection  = "ASC"
+        // OrderDirectionDesc specifies a descending order.
+        OrderDirectionDesc OrderDirection = "DESC"
+    )
+
+    // Validate the order direction value.
+    func (o OrderDirection) Validate() error {
+        if o != OrderDirectionAsc && o != OrderDirectionDesc {
+            return fmt.Errorf("%s is not a valid OrderDirection", o)
+        }
+        return nil
+    }
+
+    // String implements fmt.Stringer interface.
+    func (o OrderDirection) String() string {
+        return string(o)
+    }
+
+    func (o OrderDirection) reverse() OrderDirection {
+        if o == OrderDirectionDesc {
+            return OrderDirectionAsc
+        }
+	    return OrderDirectionDesc
+    }
+
+    const errInvalidPagination = "INVALID_PAGINATION"
+
+    {{ range $node := $.Nodes -}}
+        {{- if ne $node.Name "CasbinRule" }}
+        {{ $pager := print $node.Name "Pager" }}
+        {{ $order := print $node.Name "Order"}}
+        {{ $query := print $node.Name "Query"}}
+        {{ $orderField := print $node.Name "OrderField"}}
+        type {{ $pager }} struct {
+            Order {{ lower $node.Name }}.OrderOption
+            Filter func(*{{ $query }}) (*{{ $query }}, error)
+        }
+
+        {{ $opt := print $node.Name "PaginateOption" }}
+        // {{ $opt }} enables pagination customization.
+        type {{ $opt }} func(*{{ $pager }})
+
+
+        {{ $newPager := print "new" $node.Name "Pager" -}}
+        {{- $defaultOrder := print "Default" $node.Name "Order" }}
+
+		{{ range $f :=  $node.Fields -}}
+		   {{- if eq $node.HasOneFieldID true}}
+        // {{ $defaultOrder }} is the default ordering of {{ $node.Name }}.
+        var {{ $defaultOrder }} = Desc({{ lower $node.Name }}.FieldID)
+		    {{- break}}
+		    {{- else}}
+        // {{ $defaultOrder }} is the default ordering of {{ $node.Name }}.
+        var {{ $defaultOrder }} = Desc({{ lower $node.Name }}.Field{{ $f.StructField }})
+		    {{- break}}
+		    {{- end}}
+		{{end}}
+
+        func {{ $newPager }}(opts []{{ $opt }}) (*{{ $pager }}, error) {
+            pager := &{{ $pager }}{}
+            for _, opt := range opts {
+                opt(pager)
+            }
+            if pager.Order == nil {
+                pager.Order = {{ $defaultOrder }}
+            }
+            return pager, nil
+        }
+
+
+        func (p *{{ $pager }}) ApplyFilter(query *{{ $query }}) (*{{ $query }}, error) {
+            if p.Filter != nil {
+                return p.Filter(query)
+            }
+            return query, nil
+        }
+
+           {{ $pageList := print $node.Name "PageList" -}}
+        {{ $name := $node.Name }}
+
+        // {{ $pageList }} is {{ $name }} PageList result.
+        type {{ $pageList }} struct {
+            List []*{{ $name }}      `json:"list"`
+            PageDetails *PageDetails  `json:"pageDetails"`
+        }
+
+
+        {{ $r := $node.Receiver -}}
+        {{ $queryName := print $node.QueryName -}}
+
+        func ({{ $r }} *{{ $queryName }}) Page(
+            ctx context.Context, pageNum uint64, pageSize uint64, opts ...{{ $opt }},
+            ) (*{{ $pageList }}, error) {
+
+            pager, err := {{ $newPager }}(opts)
+            if err != nil {
+                return nil, err
+            }
+
+            if {{ $r }}, err = pager.ApplyFilter({{ $r }}); err != nil {
+                return nil, err
+            }
+
+            ret := &{{ $pageList }}{}
+
+            ret.PageDetails = &PageDetails{
+                Page: pageNum,
+                Size: pageSize,
+            }
+
+            count, err := {{ $r }}.Clone().Count(ctx)
+
+            if err != nil {
+                return nil, err
+            }
+
+            ret.PageDetails.Total = uint64(count)
+
+            if pager.Order != nil {
+           		{{ $r }} = {{ $r }}.Order(pager.Order)
+           	} else {
+           		{{ $r }} = {{ $r }}.Order({{ $defaultOrder }})
+           	}
+
+            {{ $r }} = {{ $r }}.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
+            list, err := {{ $r }}.All(ctx)
+            if err != nil {
+                return nil, err
+            }
+            ret.List = list
+
+            return ret, nil
+        }
+    {{- end}}
+    {{- end}}
+{{- end}}

+ 32 - 0
ent/template/set_not_nil.tmpl

@@ -0,0 +1,32 @@
+{{/*
+Copyright 2022-present Ryan SU (github.com/suyuan32). All rights reserved.
+This source code is licensed under the Apache 2.0 license found
+in the LICENSE file in the root directory of this source tree.
+*/}}
+
+{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
+
+
+{{ define "set_not_nil" }}
+
+    {{/* Add the base header for the generated file */}}
+    {{ $pkg := base $.Config.Package }}
+    {{ template "header" $ }}
+
+    {{/* Loop over all updaters and implement the "SetNotNil" method for all optional fields */}}
+    {{ range $n := $.Nodes }}
+        {{ range $f := $n.MutableFields }}
+            {{ $set := print "Set" $f.StructField }}
+
+            {{ range $updater := list $n.UpdateName $n.UpdateOneName $n.CreateName}}
+                // set field if value's pointer is not nil.
+                func ({{ $n.Receiver }} *{{ $updater }}) SetNotNil{{ $f.StructField }}(value {{if not (hasPrefix $f.Type.String "[]") }}*{{end}}{{ $f.Type }}) *{{ $updater }} {
+                if value != nil  {
+                return {{ $n.Receiver }}.{{ $set }}({{if not (hasPrefix $f.Type.String "[]") }}*{{end}}value)
+                }
+                return {{ $n.Receiver }}
+                }
+            {{ end }}
+        {{ end }}
+    {{ end }}
+{{ end }}

+ 242 - 0
ent/tx.go

@@ -0,0 +1,242 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	stdsql "database/sql"
+	"fmt"
+	"sync"
+
+	"entgo.io/ent/dialect"
+)
+
+// Tx is a transactional client that is created by calling Client.Tx().
+type Tx struct {
+	config
+	// Contact is the client for interacting with the Contact builders.
+	Contact *ContactClient
+	// Server is the client for interacting with the Server builders.
+	Server *ServerClient
+	// Wx is the client for interacting with the Wx builders.
+	Wx *WxClient
+
+	// lazily loaded.
+	client     *Client
+	clientOnce sync.Once
+	// ctx lives for the life of the transaction. It is
+	// the same context used by the underlying connection.
+	ctx context.Context
+}
+
+type (
+	// Committer is the interface that wraps the Commit method.
+	Committer interface {
+		Commit(context.Context, *Tx) error
+	}
+
+	// The CommitFunc type is an adapter to allow the use of ordinary
+	// function as a Committer. If f is a function with the appropriate
+	// signature, CommitFunc(f) is a Committer that calls f.
+	CommitFunc func(context.Context, *Tx) error
+
+	// CommitHook defines the "commit middleware". A function that gets a Committer
+	// and returns a Committer. For example:
+	//
+	//	hook := func(next ent.Committer) ent.Committer {
+	//		return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error {
+	//			// Do some stuff before.
+	//			if err := next.Commit(ctx, tx); err != nil {
+	//				return err
+	//			}
+	//			// Do some stuff after.
+	//			return nil
+	//		})
+	//	}
+	//
+	CommitHook func(Committer) Committer
+)
+
+// Commit calls f(ctx, m).
+func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error {
+	return f(ctx, tx)
+}
+
+// Commit commits the transaction.
+func (tx *Tx) Commit() error {
+	txDriver := tx.config.driver.(*txDriver)
+	var fn Committer = CommitFunc(func(context.Context, *Tx) error {
+		return txDriver.tx.Commit()
+	})
+	txDriver.mu.Lock()
+	hooks := append([]CommitHook(nil), txDriver.onCommit...)
+	txDriver.mu.Unlock()
+	for i := len(hooks) - 1; i >= 0; i-- {
+		fn = hooks[i](fn)
+	}
+	return fn.Commit(tx.ctx, tx)
+}
+
+// OnCommit adds a hook to call on commit.
+func (tx *Tx) OnCommit(f CommitHook) {
+	txDriver := tx.config.driver.(*txDriver)
+	txDriver.mu.Lock()
+	txDriver.onCommit = append(txDriver.onCommit, f)
+	txDriver.mu.Unlock()
+}
+
+type (
+	// Rollbacker is the interface that wraps the Rollback method.
+	Rollbacker interface {
+		Rollback(context.Context, *Tx) error
+	}
+
+	// The RollbackFunc type is an adapter to allow the use of ordinary
+	// function as a Rollbacker. If f is a function with the appropriate
+	// signature, RollbackFunc(f) is a Rollbacker that calls f.
+	RollbackFunc func(context.Context, *Tx) error
+
+	// RollbackHook defines the "rollback middleware". A function that gets a Rollbacker
+	// and returns a Rollbacker. For example:
+	//
+	//	hook := func(next ent.Rollbacker) ent.Rollbacker {
+	//		return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error {
+	//			// Do some stuff before.
+	//			if err := next.Rollback(ctx, tx); err != nil {
+	//				return err
+	//			}
+	//			// Do some stuff after.
+	//			return nil
+	//		})
+	//	}
+	//
+	RollbackHook func(Rollbacker) Rollbacker
+)
+
+// Rollback calls f(ctx, m).
+func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error {
+	return f(ctx, tx)
+}
+
+// Rollback rollbacks the transaction.
+func (tx *Tx) Rollback() error {
+	txDriver := tx.config.driver.(*txDriver)
+	var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error {
+		return txDriver.tx.Rollback()
+	})
+	txDriver.mu.Lock()
+	hooks := append([]RollbackHook(nil), txDriver.onRollback...)
+	txDriver.mu.Unlock()
+	for i := len(hooks) - 1; i >= 0; i-- {
+		fn = hooks[i](fn)
+	}
+	return fn.Rollback(tx.ctx, tx)
+}
+
+// OnRollback adds a hook to call on rollback.
+func (tx *Tx) OnRollback(f RollbackHook) {
+	txDriver := tx.config.driver.(*txDriver)
+	txDriver.mu.Lock()
+	txDriver.onRollback = append(txDriver.onRollback, f)
+	txDriver.mu.Unlock()
+}
+
+// Client returns a Client that binds to current transaction.
+func (tx *Tx) Client() *Client {
+	tx.clientOnce.Do(func() {
+		tx.client = &Client{config: tx.config}
+		tx.client.init()
+	})
+	return tx.client
+}
+
+func (tx *Tx) init() {
+	tx.Contact = NewContactClient(tx.config)
+	tx.Server = NewServerClient(tx.config)
+	tx.Wx = NewWxClient(tx.config)
+}
+
+// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation.
+// The idea is to support transactions without adding any extra code to the builders.
+// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance.
+// Commit and Rollback are nop for the internal builders and the user must call one
+// of them in order to commit or rollback the transaction.
+//
+// If a closed transaction is embedded in one of the generated entities, and the entity
+// applies a query, for example: Contact.QueryXXX(), the query will be executed
+// through the driver which created this transaction.
+//
+// Note that txDriver is not goroutine safe.
+type txDriver struct {
+	// the driver we started the transaction from.
+	drv dialect.Driver
+	// tx is the underlying transaction.
+	tx dialect.Tx
+	// completion hooks.
+	mu         sync.Mutex
+	onCommit   []CommitHook
+	onRollback []RollbackHook
+}
+
+// newTx creates a new transactional driver.
+func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) {
+	tx, err := drv.Tx(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return &txDriver{tx: tx, drv: drv}, nil
+}
+
+// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls
+// from the internal builders. Should be called only by the internal builders.
+func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil }
+
+// Dialect returns the dialect of the driver we started the transaction from.
+func (tx *txDriver) Dialect() string { return tx.drv.Dialect() }
+
+// Close is a nop close.
+func (*txDriver) Close() error { return nil }
+
+// Commit is a nop commit for the internal builders.
+// User must call `Tx.Commit` in order to commit the transaction.
+func (*txDriver) Commit() error { return nil }
+
+// Rollback is a nop rollback for the internal builders.
+// User must call `Tx.Rollback` in order to rollback the transaction.
+func (*txDriver) Rollback() error { return nil }
+
+// Exec calls tx.Exec.
+func (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error {
+	return tx.tx.Exec(ctx, query, args, v)
+}
+
+// Query calls tx.Query.
+func (tx *txDriver) Query(ctx context.Context, query string, args, v any) error {
+	return tx.tx.Query(ctx, query, args, v)
+}
+
+var _ dialect.Driver = (*txDriver)(nil)
+
+// ExecContext allows calling the underlying ExecContext method of the transaction if it is supported by it.
+// See, database/sql#Tx.ExecContext for more information.
+func (tx *txDriver) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
+	ex, ok := tx.tx.(interface {
+		ExecContext(context.Context, string, ...any) (stdsql.Result, error)
+	})
+	if !ok {
+		return nil, fmt.Errorf("Tx.ExecContext is not supported")
+	}
+	return ex.ExecContext(ctx, query, args...)
+}
+
+// QueryContext allows calling the underlying QueryContext method of the transaction if it is supported by it.
+// See, database/sql#Tx.QueryContext for more information.
+func (tx *txDriver) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
+	q, ok := tx.tx.(interface {
+		QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
+	})
+	if !ok {
+		return nil, fmt.Errorf("Tx.QueryContext is not supported")
+	}
+	return q.QueryContext(ctx, query, args...)
+}

+ 267 - 0
ent/wx.go

@@ -0,0 +1,267 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"fmt"
+	"strings"
+	"time"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+)
+
+// Wx is the model entity for the Wx schema.
+type Wx 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
+	ServerID uint64 `json:"server_id,omitempty"`
+	// 端口号
+	Port string `json:"port,omitempty"`
+	// 进程号
+	ProcessID string `json:"process_id,omitempty"`
+	// 回调地址
+	Callback string `json:"callback,omitempty"`
+	// 微信id
+	Wxid string `json:"wxid,omitempty"`
+	// 微信账号
+	Account string `json:"account,omitempty"`
+	// 微信昵称
+	Nickname string `json:"nickname,omitempty"`
+	// 手机号
+	Tel string `json:"tel,omitempty"`
+	// 微信头像
+	HeadBig string `json:"head_big,omitempty"`
+	// Edges holds the relations/edges for other nodes in the graph.
+	// The values are being populated by the WxQuery when eager-loading is set.
+	Edges        WxEdges `json:"edges"`
+	selectValues sql.SelectValues
+}
+
+// WxEdges holds the relations/edges for other nodes in the graph.
+type WxEdges struct {
+	// Server holds the value of the server edge.
+	Server *Server `json:"server,omitempty"`
+	// loadedTypes holds the information for reporting if a
+	// type was loaded (or requested) in eager-loading or not.
+	loadedTypes [1]bool
+}
+
+// ServerOrErr returns the Server value or an error if the edge
+// was not loaded in eager-loading, or loaded but was not found.
+func (e WxEdges) ServerOrErr() (*Server, error) {
+	if e.Server != nil {
+		return e.Server, nil
+	} else if e.loadedTypes[0] {
+		return nil, &NotFoundError{label: server.Label}
+	}
+	return nil, &NotLoadedError{edge: "server"}
+}
+
+// scanValues returns the types for scanning values from sql.Rows.
+func (*Wx) scanValues(columns []string) ([]any, error) {
+	values := make([]any, len(columns))
+	for i := range columns {
+		switch columns[i] {
+		case wx.FieldID, wx.FieldStatus, wx.FieldServerID:
+			values[i] = new(sql.NullInt64)
+		case wx.FieldPort, wx.FieldProcessID, wx.FieldCallback, wx.FieldWxid, wx.FieldAccount, wx.FieldNickname, wx.FieldTel, wx.FieldHeadBig:
+			values[i] = new(sql.NullString)
+		case wx.FieldCreatedAt, wx.FieldUpdatedAt, wx.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 Wx fields.
+func (w *Wx) 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 wx.FieldID:
+			value, ok := values[i].(*sql.NullInt64)
+			if !ok {
+				return fmt.Errorf("unexpected type %T for field id", value)
+			}
+			w.ID = uint64(value.Int64)
+		case wx.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 {
+				w.CreatedAt = value.Time
+			}
+		case wx.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 {
+				w.UpdatedAt = value.Time
+			}
+		case wx.FieldStatus:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field status", values[i])
+			} else if value.Valid {
+				w.Status = uint8(value.Int64)
+			}
+		case wx.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 {
+				w.DeletedAt = value.Time
+			}
+		case wx.FieldServerID:
+			if value, ok := values[i].(*sql.NullInt64); !ok {
+				return fmt.Errorf("unexpected type %T for field server_id", values[i])
+			} else if value.Valid {
+				w.ServerID = uint64(value.Int64)
+			}
+		case wx.FieldPort:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field port", values[i])
+			} else if value.Valid {
+				w.Port = value.String
+			}
+		case wx.FieldProcessID:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field process_id", values[i])
+			} else if value.Valid {
+				w.ProcessID = value.String
+			}
+		case wx.FieldCallback:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field callback", values[i])
+			} else if value.Valid {
+				w.Callback = value.String
+			}
+		case wx.FieldWxid:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field wxid", values[i])
+			} else if value.Valid {
+				w.Wxid = value.String
+			}
+		case wx.FieldAccount:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field account", values[i])
+			} else if value.Valid {
+				w.Account = value.String
+			}
+		case wx.FieldNickname:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field nickname", values[i])
+			} else if value.Valid {
+				w.Nickname = value.String
+			}
+		case wx.FieldTel:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field tel", values[i])
+			} else if value.Valid {
+				w.Tel = value.String
+			}
+		case wx.FieldHeadBig:
+			if value, ok := values[i].(*sql.NullString); !ok {
+				return fmt.Errorf("unexpected type %T for field head_big", values[i])
+			} else if value.Valid {
+				w.HeadBig = value.String
+			}
+		default:
+			w.selectValues.Set(columns[i], values[i])
+		}
+	}
+	return nil
+}
+
+// Value returns the ent.Value that was dynamically selected and assigned to the Wx.
+// This includes values selected through modifiers, order, etc.
+func (w *Wx) Value(name string) (ent.Value, error) {
+	return w.selectValues.Get(name)
+}
+
+// QueryServer queries the "server" edge of the Wx entity.
+func (w *Wx) QueryServer() *ServerQuery {
+	return NewWxClient(w.config).QueryServer(w)
+}
+
+// Update returns a builder for updating this Wx.
+// Note that you need to call Wx.Unwrap() before calling this method if this Wx
+// was returned from a transaction, and the transaction was committed or rolled back.
+func (w *Wx) Update() *WxUpdateOne {
+	return NewWxClient(w.config).UpdateOne(w)
+}
+
+// Unwrap unwraps the Wx 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 (w *Wx) Unwrap() *Wx {
+	_tx, ok := w.config.driver.(*txDriver)
+	if !ok {
+		panic("ent: Wx is not a transactional entity")
+	}
+	w.config.driver = _tx.drv
+	return w
+}
+
+// String implements the fmt.Stringer.
+func (w *Wx) String() string {
+	var builder strings.Builder
+	builder.WriteString("Wx(")
+	builder.WriteString(fmt.Sprintf("id=%v, ", w.ID))
+	builder.WriteString("created_at=")
+	builder.WriteString(w.CreatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("updated_at=")
+	builder.WriteString(w.UpdatedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("status=")
+	builder.WriteString(fmt.Sprintf("%v", w.Status))
+	builder.WriteString(", ")
+	builder.WriteString("deleted_at=")
+	builder.WriteString(w.DeletedAt.Format(time.ANSIC))
+	builder.WriteString(", ")
+	builder.WriteString("server_id=")
+	builder.WriteString(fmt.Sprintf("%v", w.ServerID))
+	builder.WriteString(", ")
+	builder.WriteString("port=")
+	builder.WriteString(w.Port)
+	builder.WriteString(", ")
+	builder.WriteString("process_id=")
+	builder.WriteString(w.ProcessID)
+	builder.WriteString(", ")
+	builder.WriteString("callback=")
+	builder.WriteString(w.Callback)
+	builder.WriteString(", ")
+	builder.WriteString("wxid=")
+	builder.WriteString(w.Wxid)
+	builder.WriteString(", ")
+	builder.WriteString("account=")
+	builder.WriteString(w.Account)
+	builder.WriteString(", ")
+	builder.WriteString("nickname=")
+	builder.WriteString(w.Nickname)
+	builder.WriteString(", ")
+	builder.WriteString("tel=")
+	builder.WriteString(w.Tel)
+	builder.WriteString(", ")
+	builder.WriteString("head_big=")
+	builder.WriteString(w.HeadBig)
+	builder.WriteByte(')')
+	return builder.String()
+}
+
+// Wxes is a parsable slice of Wx.
+type Wxes []*Wx

+ 889 - 0
ent/wx/where.go

@@ -0,0 +1,889 @@
+// Code generated by ent, DO NOT EDIT.
+
+package wx
+
+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.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldID, id))
+}
+
+// IDEQ applies the EQ predicate on the ID field.
+func IDEQ(id uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldID, id))
+}
+
+// IDNEQ applies the NEQ predicate on the ID field.
+func IDNEQ(id uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldID, id))
+}
+
+// IDIn applies the In predicate on the ID field.
+func IDIn(ids ...uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldID, ids...))
+}
+
+// IDNotIn applies the NotIn predicate on the ID field.
+func IDNotIn(ids ...uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldID, ids...))
+}
+
+// IDGT applies the GT predicate on the ID field.
+func IDGT(id uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldID, id))
+}
+
+// IDGTE applies the GTE predicate on the ID field.
+func IDGTE(id uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldID, id))
+}
+
+// IDLT applies the LT predicate on the ID field.
+func IDLT(id uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldID, id))
+}
+
+// IDLTE applies the LTE predicate on the ID field.
+func IDLTE(id uint64) predicate.Wx {
+	return predicate.Wx(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.Wx {
+	return predicate.Wx(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.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// Status applies equality check predicate on the "status" field. It's identical to StatusEQ.
+func Status(v uint8) predicate.Wx {
+	return predicate.Wx(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.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// ServerID applies equality check predicate on the "server_id" field. It's identical to ServerIDEQ.
+func ServerID(v uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldServerID, v))
+}
+
+// Port applies equality check predicate on the "port" field. It's identical to PortEQ.
+func Port(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldPort, v))
+}
+
+// ProcessID applies equality check predicate on the "process_id" field. It's identical to ProcessIDEQ.
+func ProcessID(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldProcessID, v))
+}
+
+// Callback applies equality check predicate on the "callback" field. It's identical to CallbackEQ.
+func Callback(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldCallback, v))
+}
+
+// Wxid applies equality check predicate on the "wxid" field. It's identical to WxidEQ.
+func Wxid(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldWxid, v))
+}
+
+// Account applies equality check predicate on the "account" field. It's identical to AccountEQ.
+func Account(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldAccount, v))
+}
+
+// Nickname applies equality check predicate on the "nickname" field. It's identical to NicknameEQ.
+func Nickname(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldNickname, v))
+}
+
+// Tel applies equality check predicate on the "tel" field. It's identical to TelEQ.
+func Tel(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldTel, v))
+}
+
+// HeadBig applies equality check predicate on the "head_big" field. It's identical to HeadBigEQ.
+func HeadBig(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldHeadBig, v))
+}
+
+// CreatedAtEQ applies the EQ predicate on the "created_at" field.
+func CreatedAtEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
+func CreatedAtNEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldCreatedAt, v))
+}
+
+// CreatedAtIn applies the In predicate on the "created_at" field.
+func CreatedAtIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
+func CreatedAtNotIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldCreatedAt, vs...))
+}
+
+// CreatedAtGT applies the GT predicate on the "created_at" field.
+func CreatedAtGT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldCreatedAt, v))
+}
+
+// CreatedAtGTE applies the GTE predicate on the "created_at" field.
+func CreatedAtGTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldCreatedAt, v))
+}
+
+// CreatedAtLT applies the LT predicate on the "created_at" field.
+func CreatedAtLT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldCreatedAt, v))
+}
+
+// CreatedAtLTE applies the LTE predicate on the "created_at" field.
+func CreatedAtLTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldCreatedAt, v))
+}
+
+// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
+func UpdatedAtEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
+func UpdatedAtNEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldUpdatedAt, v))
+}
+
+// UpdatedAtIn applies the In predicate on the "updated_at" field.
+func UpdatedAtIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
+func UpdatedAtNotIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldUpdatedAt, vs...))
+}
+
+// UpdatedAtGT applies the GT predicate on the "updated_at" field.
+func UpdatedAtGT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
+func UpdatedAtGTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLT applies the LT predicate on the "updated_at" field.
+func UpdatedAtLT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldUpdatedAt, v))
+}
+
+// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
+func UpdatedAtLTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldUpdatedAt, v))
+}
+
+// StatusEQ applies the EQ predicate on the "status" field.
+func StatusEQ(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldStatus, v))
+}
+
+// StatusNEQ applies the NEQ predicate on the "status" field.
+func StatusNEQ(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldStatus, v))
+}
+
+// StatusIn applies the In predicate on the "status" field.
+func StatusIn(vs ...uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldStatus, vs...))
+}
+
+// StatusNotIn applies the NotIn predicate on the "status" field.
+func StatusNotIn(vs ...uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldStatus, vs...))
+}
+
+// StatusGT applies the GT predicate on the "status" field.
+func StatusGT(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldStatus, v))
+}
+
+// StatusGTE applies the GTE predicate on the "status" field.
+func StatusGTE(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldStatus, v))
+}
+
+// StatusLT applies the LT predicate on the "status" field.
+func StatusLT(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldStatus, v))
+}
+
+// StatusLTE applies the LTE predicate on the "status" field.
+func StatusLTE(v uint8) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldStatus, v))
+}
+
+// StatusIsNil applies the IsNil predicate on the "status" field.
+func StatusIsNil() predicate.Wx {
+	return predicate.Wx(sql.FieldIsNull(FieldStatus))
+}
+
+// StatusNotNil applies the NotNil predicate on the "status" field.
+func StatusNotNil() predicate.Wx {
+	return predicate.Wx(sql.FieldNotNull(FieldStatus))
+}
+
+// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
+func DeletedAtEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
+func DeletedAtNEQ(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldDeletedAt, v))
+}
+
+// DeletedAtIn applies the In predicate on the "deleted_at" field.
+func DeletedAtIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
+func DeletedAtNotIn(vs ...time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldDeletedAt, vs...))
+}
+
+// DeletedAtGT applies the GT predicate on the "deleted_at" field.
+func DeletedAtGT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldDeletedAt, v))
+}
+
+// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
+func DeletedAtGTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldDeletedAt, v))
+}
+
+// DeletedAtLT applies the LT predicate on the "deleted_at" field.
+func DeletedAtLT(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldDeletedAt, v))
+}
+
+// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
+func DeletedAtLTE(v time.Time) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldDeletedAt, v))
+}
+
+// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
+func DeletedAtIsNil() predicate.Wx {
+	return predicate.Wx(sql.FieldIsNull(FieldDeletedAt))
+}
+
+// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
+func DeletedAtNotNil() predicate.Wx {
+	return predicate.Wx(sql.FieldNotNull(FieldDeletedAt))
+}
+
+// ServerIDEQ applies the EQ predicate on the "server_id" field.
+func ServerIDEQ(v uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldServerID, v))
+}
+
+// ServerIDNEQ applies the NEQ predicate on the "server_id" field.
+func ServerIDNEQ(v uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldServerID, v))
+}
+
+// ServerIDIn applies the In predicate on the "server_id" field.
+func ServerIDIn(vs ...uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldServerID, vs...))
+}
+
+// ServerIDNotIn applies the NotIn predicate on the "server_id" field.
+func ServerIDNotIn(vs ...uint64) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldServerID, vs...))
+}
+
+// ServerIDIsNil applies the IsNil predicate on the "server_id" field.
+func ServerIDIsNil() predicate.Wx {
+	return predicate.Wx(sql.FieldIsNull(FieldServerID))
+}
+
+// ServerIDNotNil applies the NotNil predicate on the "server_id" field.
+func ServerIDNotNil() predicate.Wx {
+	return predicate.Wx(sql.FieldNotNull(FieldServerID))
+}
+
+// PortEQ applies the EQ predicate on the "port" field.
+func PortEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldPort, v))
+}
+
+// PortNEQ applies the NEQ predicate on the "port" field.
+func PortNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldPort, v))
+}
+
+// PortIn applies the In predicate on the "port" field.
+func PortIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldPort, vs...))
+}
+
+// PortNotIn applies the NotIn predicate on the "port" field.
+func PortNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldPort, vs...))
+}
+
+// PortGT applies the GT predicate on the "port" field.
+func PortGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldPort, v))
+}
+
+// PortGTE applies the GTE predicate on the "port" field.
+func PortGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldPort, v))
+}
+
+// PortLT applies the LT predicate on the "port" field.
+func PortLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldPort, v))
+}
+
+// PortLTE applies the LTE predicate on the "port" field.
+func PortLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldPort, v))
+}
+
+// PortContains applies the Contains predicate on the "port" field.
+func PortContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldPort, v))
+}
+
+// PortHasPrefix applies the HasPrefix predicate on the "port" field.
+func PortHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldPort, v))
+}
+
+// PortHasSuffix applies the HasSuffix predicate on the "port" field.
+func PortHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldPort, v))
+}
+
+// PortEqualFold applies the EqualFold predicate on the "port" field.
+func PortEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldPort, v))
+}
+
+// PortContainsFold applies the ContainsFold predicate on the "port" field.
+func PortContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldPort, v))
+}
+
+// ProcessIDEQ applies the EQ predicate on the "process_id" field.
+func ProcessIDEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldProcessID, v))
+}
+
+// ProcessIDNEQ applies the NEQ predicate on the "process_id" field.
+func ProcessIDNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldProcessID, v))
+}
+
+// ProcessIDIn applies the In predicate on the "process_id" field.
+func ProcessIDIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldProcessID, vs...))
+}
+
+// ProcessIDNotIn applies the NotIn predicate on the "process_id" field.
+func ProcessIDNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldProcessID, vs...))
+}
+
+// ProcessIDGT applies the GT predicate on the "process_id" field.
+func ProcessIDGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldProcessID, v))
+}
+
+// ProcessIDGTE applies the GTE predicate on the "process_id" field.
+func ProcessIDGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldProcessID, v))
+}
+
+// ProcessIDLT applies the LT predicate on the "process_id" field.
+func ProcessIDLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldProcessID, v))
+}
+
+// ProcessIDLTE applies the LTE predicate on the "process_id" field.
+func ProcessIDLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldProcessID, v))
+}
+
+// ProcessIDContains applies the Contains predicate on the "process_id" field.
+func ProcessIDContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldProcessID, v))
+}
+
+// ProcessIDHasPrefix applies the HasPrefix predicate on the "process_id" field.
+func ProcessIDHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldProcessID, v))
+}
+
+// ProcessIDHasSuffix applies the HasSuffix predicate on the "process_id" field.
+func ProcessIDHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldProcessID, v))
+}
+
+// ProcessIDEqualFold applies the EqualFold predicate on the "process_id" field.
+func ProcessIDEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldProcessID, v))
+}
+
+// ProcessIDContainsFold applies the ContainsFold predicate on the "process_id" field.
+func ProcessIDContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldProcessID, v))
+}
+
+// CallbackEQ applies the EQ predicate on the "callback" field.
+func CallbackEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldCallback, v))
+}
+
+// CallbackNEQ applies the NEQ predicate on the "callback" field.
+func CallbackNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldCallback, v))
+}
+
+// CallbackIn applies the In predicate on the "callback" field.
+func CallbackIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldCallback, vs...))
+}
+
+// CallbackNotIn applies the NotIn predicate on the "callback" field.
+func CallbackNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldCallback, vs...))
+}
+
+// CallbackGT applies the GT predicate on the "callback" field.
+func CallbackGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldCallback, v))
+}
+
+// CallbackGTE applies the GTE predicate on the "callback" field.
+func CallbackGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldCallback, v))
+}
+
+// CallbackLT applies the LT predicate on the "callback" field.
+func CallbackLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldCallback, v))
+}
+
+// CallbackLTE applies the LTE predicate on the "callback" field.
+func CallbackLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldCallback, v))
+}
+
+// CallbackContains applies the Contains predicate on the "callback" field.
+func CallbackContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldCallback, v))
+}
+
+// CallbackHasPrefix applies the HasPrefix predicate on the "callback" field.
+func CallbackHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldCallback, v))
+}
+
+// CallbackHasSuffix applies the HasSuffix predicate on the "callback" field.
+func CallbackHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldCallback, v))
+}
+
+// CallbackEqualFold applies the EqualFold predicate on the "callback" field.
+func CallbackEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldCallback, v))
+}
+
+// CallbackContainsFold applies the ContainsFold predicate on the "callback" field.
+func CallbackContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldCallback, v))
+}
+
+// WxidEQ applies the EQ predicate on the "wxid" field.
+func WxidEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldWxid, v))
+}
+
+// WxidNEQ applies the NEQ predicate on the "wxid" field.
+func WxidNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldWxid, v))
+}
+
+// WxidIn applies the In predicate on the "wxid" field.
+func WxidIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldWxid, vs...))
+}
+
+// WxidNotIn applies the NotIn predicate on the "wxid" field.
+func WxidNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldWxid, vs...))
+}
+
+// WxidGT applies the GT predicate on the "wxid" field.
+func WxidGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldWxid, v))
+}
+
+// WxidGTE applies the GTE predicate on the "wxid" field.
+func WxidGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldWxid, v))
+}
+
+// WxidLT applies the LT predicate on the "wxid" field.
+func WxidLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldWxid, v))
+}
+
+// WxidLTE applies the LTE predicate on the "wxid" field.
+func WxidLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldWxid, v))
+}
+
+// WxidContains applies the Contains predicate on the "wxid" field.
+func WxidContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldWxid, v))
+}
+
+// WxidHasPrefix applies the HasPrefix predicate on the "wxid" field.
+func WxidHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldWxid, v))
+}
+
+// WxidHasSuffix applies the HasSuffix predicate on the "wxid" field.
+func WxidHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldWxid, v))
+}
+
+// WxidEqualFold applies the EqualFold predicate on the "wxid" field.
+func WxidEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldWxid, v))
+}
+
+// WxidContainsFold applies the ContainsFold predicate on the "wxid" field.
+func WxidContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldWxid, v))
+}
+
+// AccountEQ applies the EQ predicate on the "account" field.
+func AccountEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldAccount, v))
+}
+
+// AccountNEQ applies the NEQ predicate on the "account" field.
+func AccountNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldAccount, v))
+}
+
+// AccountIn applies the In predicate on the "account" field.
+func AccountIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldAccount, vs...))
+}
+
+// AccountNotIn applies the NotIn predicate on the "account" field.
+func AccountNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldAccount, vs...))
+}
+
+// AccountGT applies the GT predicate on the "account" field.
+func AccountGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldAccount, v))
+}
+
+// AccountGTE applies the GTE predicate on the "account" field.
+func AccountGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldAccount, v))
+}
+
+// AccountLT applies the LT predicate on the "account" field.
+func AccountLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldAccount, v))
+}
+
+// AccountLTE applies the LTE predicate on the "account" field.
+func AccountLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldAccount, v))
+}
+
+// AccountContains applies the Contains predicate on the "account" field.
+func AccountContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldAccount, v))
+}
+
+// AccountHasPrefix applies the HasPrefix predicate on the "account" field.
+func AccountHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldAccount, v))
+}
+
+// AccountHasSuffix applies the HasSuffix predicate on the "account" field.
+func AccountHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldAccount, v))
+}
+
+// AccountEqualFold applies the EqualFold predicate on the "account" field.
+func AccountEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldAccount, v))
+}
+
+// AccountContainsFold applies the ContainsFold predicate on the "account" field.
+func AccountContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldAccount, v))
+}
+
+// NicknameEQ applies the EQ predicate on the "nickname" field.
+func NicknameEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldNickname, v))
+}
+
+// NicknameNEQ applies the NEQ predicate on the "nickname" field.
+func NicknameNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldNickname, v))
+}
+
+// NicknameIn applies the In predicate on the "nickname" field.
+func NicknameIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldNickname, vs...))
+}
+
+// NicknameNotIn applies the NotIn predicate on the "nickname" field.
+func NicknameNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldNickname, vs...))
+}
+
+// NicknameGT applies the GT predicate on the "nickname" field.
+func NicknameGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldNickname, v))
+}
+
+// NicknameGTE applies the GTE predicate on the "nickname" field.
+func NicknameGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldNickname, v))
+}
+
+// NicknameLT applies the LT predicate on the "nickname" field.
+func NicknameLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldNickname, v))
+}
+
+// NicknameLTE applies the LTE predicate on the "nickname" field.
+func NicknameLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldNickname, v))
+}
+
+// NicknameContains applies the Contains predicate on the "nickname" field.
+func NicknameContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldNickname, v))
+}
+
+// NicknameHasPrefix applies the HasPrefix predicate on the "nickname" field.
+func NicknameHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldNickname, v))
+}
+
+// NicknameHasSuffix applies the HasSuffix predicate on the "nickname" field.
+func NicknameHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldNickname, v))
+}
+
+// NicknameEqualFold applies the EqualFold predicate on the "nickname" field.
+func NicknameEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldNickname, v))
+}
+
+// NicknameContainsFold applies the ContainsFold predicate on the "nickname" field.
+func NicknameContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldNickname, v))
+}
+
+// TelEQ applies the EQ predicate on the "tel" field.
+func TelEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldTel, v))
+}
+
+// TelNEQ applies the NEQ predicate on the "tel" field.
+func TelNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldTel, v))
+}
+
+// TelIn applies the In predicate on the "tel" field.
+func TelIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldTel, vs...))
+}
+
+// TelNotIn applies the NotIn predicate on the "tel" field.
+func TelNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldTel, vs...))
+}
+
+// TelGT applies the GT predicate on the "tel" field.
+func TelGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldTel, v))
+}
+
+// TelGTE applies the GTE predicate on the "tel" field.
+func TelGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldTel, v))
+}
+
+// TelLT applies the LT predicate on the "tel" field.
+func TelLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldTel, v))
+}
+
+// TelLTE applies the LTE predicate on the "tel" field.
+func TelLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldTel, v))
+}
+
+// TelContains applies the Contains predicate on the "tel" field.
+func TelContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldTel, v))
+}
+
+// TelHasPrefix applies the HasPrefix predicate on the "tel" field.
+func TelHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldTel, v))
+}
+
+// TelHasSuffix applies the HasSuffix predicate on the "tel" field.
+func TelHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldTel, v))
+}
+
+// TelEqualFold applies the EqualFold predicate on the "tel" field.
+func TelEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldTel, v))
+}
+
+// TelContainsFold applies the ContainsFold predicate on the "tel" field.
+func TelContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldTel, v))
+}
+
+// HeadBigEQ applies the EQ predicate on the "head_big" field.
+func HeadBigEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEQ(FieldHeadBig, v))
+}
+
+// HeadBigNEQ applies the NEQ predicate on the "head_big" field.
+func HeadBigNEQ(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldNEQ(FieldHeadBig, v))
+}
+
+// HeadBigIn applies the In predicate on the "head_big" field.
+func HeadBigIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldIn(FieldHeadBig, vs...))
+}
+
+// HeadBigNotIn applies the NotIn predicate on the "head_big" field.
+func HeadBigNotIn(vs ...string) predicate.Wx {
+	return predicate.Wx(sql.FieldNotIn(FieldHeadBig, vs...))
+}
+
+// HeadBigGT applies the GT predicate on the "head_big" field.
+func HeadBigGT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGT(FieldHeadBig, v))
+}
+
+// HeadBigGTE applies the GTE predicate on the "head_big" field.
+func HeadBigGTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldGTE(FieldHeadBig, v))
+}
+
+// HeadBigLT applies the LT predicate on the "head_big" field.
+func HeadBigLT(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLT(FieldHeadBig, v))
+}
+
+// HeadBigLTE applies the LTE predicate on the "head_big" field.
+func HeadBigLTE(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldLTE(FieldHeadBig, v))
+}
+
+// HeadBigContains applies the Contains predicate on the "head_big" field.
+func HeadBigContains(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContains(FieldHeadBig, v))
+}
+
+// HeadBigHasPrefix applies the HasPrefix predicate on the "head_big" field.
+func HeadBigHasPrefix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasPrefix(FieldHeadBig, v))
+}
+
+// HeadBigHasSuffix applies the HasSuffix predicate on the "head_big" field.
+func HeadBigHasSuffix(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldHasSuffix(FieldHeadBig, v))
+}
+
+// HeadBigEqualFold applies the EqualFold predicate on the "head_big" field.
+func HeadBigEqualFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldEqualFold(FieldHeadBig, v))
+}
+
+// HeadBigContainsFold applies the ContainsFold predicate on the "head_big" field.
+func HeadBigContainsFold(v string) predicate.Wx {
+	return predicate.Wx(sql.FieldContainsFold(FieldHeadBig, v))
+}
+
+// HasServer applies the HasEdge predicate on the "server" edge.
+func HasServer() predicate.Wx {
+	return predicate.Wx(func(s *sql.Selector) {
+		step := sqlgraph.NewStep(
+			sqlgraph.From(Table, FieldID),
+			sqlgraph.Edge(sqlgraph.M2O, true, ServerTable, ServerColumn),
+		)
+		sqlgraph.HasNeighbors(s, step)
+	})
+}
+
+// HasServerWith applies the HasEdge predicate on the "server" edge with a given conditions (other predicates).
+func HasServerWith(preds ...predicate.Server) predicate.Wx {
+	return predicate.Wx(func(s *sql.Selector) {
+		step := newServerStep()
+		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.Wx) predicate.Wx {
+	return predicate.Wx(sql.AndPredicates(predicates...))
+}
+
+// Or groups predicates with the OR operator between them.
+func Or(predicates ...predicate.Wx) predicate.Wx {
+	return predicate.Wx(sql.OrPredicates(predicates...))
+}
+
+// Not applies the not operator on the given predicate.
+func Not(p predicate.Wx) predicate.Wx {
+	return predicate.Wx(sql.NotPredicates(p))
+}

+ 206 - 0
ent/wx/wx.go

@@ -0,0 +1,206 @@
+// Code generated by ent, DO NOT EDIT.
+
+package wx
+
+import (
+	"time"
+
+	"entgo.io/ent"
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+)
+
+const (
+	// Label holds the string label denoting the wx type in the database.
+	Label = "wx"
+	// 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"
+	// FieldServerID holds the string denoting the server_id field in the database.
+	FieldServerID = "server_id"
+	// FieldPort holds the string denoting the port field in the database.
+	FieldPort = "port"
+	// FieldProcessID holds the string denoting the process_id field in the database.
+	FieldProcessID = "process_id"
+	// FieldCallback holds the string denoting the callback field in the database.
+	FieldCallback = "callback"
+	// FieldWxid holds the string denoting the wxid field in the database.
+	FieldWxid = "wxid"
+	// FieldAccount holds the string denoting the account field in the database.
+	FieldAccount = "account"
+	// FieldNickname holds the string denoting the nickname field in the database.
+	FieldNickname = "nickname"
+	// FieldTel holds the string denoting the tel field in the database.
+	FieldTel = "tel"
+	// FieldHeadBig holds the string denoting the head_big field in the database.
+	FieldHeadBig = "head_big"
+	// EdgeServer holds the string denoting the server edge name in mutations.
+	EdgeServer = "server"
+	// Table holds the table name of the wx in the database.
+	Table = "wx"
+	// ServerTable is the table that holds the server relation/edge.
+	ServerTable = "wx"
+	// ServerInverseTable is the table name for the Server entity.
+	// It exists in this package in order to avoid circular dependency with the "server" package.
+	ServerInverseTable = "server"
+	// ServerColumn is the table column denoting the server relation/edge.
+	ServerColumn = "server_id"
+)
+
+// Columns holds all SQL columns for wx fields.
+var Columns = []string{
+	FieldID,
+	FieldCreatedAt,
+	FieldUpdatedAt,
+	FieldStatus,
+	FieldDeletedAt,
+	FieldServerID,
+	FieldPort,
+	FieldProcessID,
+	FieldCallback,
+	FieldWxid,
+	FieldAccount,
+	FieldNickname,
+	FieldTel,
+	FieldHeadBig,
+}
+
+// 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
+	// DefaultServerID holds the default value on creation for the "server_id" field.
+	DefaultServerID uint64
+	// DefaultPort holds the default value on creation for the "port" field.
+	DefaultPort string
+	// DefaultProcessID holds the default value on creation for the "process_id" field.
+	DefaultProcessID string
+	// DefaultCallback holds the default value on creation for the "callback" field.
+	DefaultCallback string
+	// DefaultWxid holds the default value on creation for the "wxid" field.
+	DefaultWxid string
+	// DefaultAccount holds the default value on creation for the "account" field.
+	DefaultAccount string
+	// DefaultNickname holds the default value on creation for the "nickname" field.
+	DefaultNickname string
+	// DefaultTel holds the default value on creation for the "tel" field.
+	DefaultTel string
+	// DefaultHeadBig holds the default value on creation for the "head_big" field.
+	DefaultHeadBig string
+)
+
+// OrderOption defines the ordering options for the Wx 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()
+}
+
+// ByServerID orders the results by the server_id field.
+func ByServerID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldServerID, opts...).ToFunc()
+}
+
+// ByPort orders the results by the port field.
+func ByPort(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldPort, opts...).ToFunc()
+}
+
+// ByProcessID orders the results by the process_id field.
+func ByProcessID(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldProcessID, opts...).ToFunc()
+}
+
+// ByCallback orders the results by the callback field.
+func ByCallback(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldCallback, opts...).ToFunc()
+}
+
+// ByWxid orders the results by the wxid field.
+func ByWxid(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldWxid, opts...).ToFunc()
+}
+
+// ByAccount orders the results by the account field.
+func ByAccount(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldAccount, opts...).ToFunc()
+}
+
+// ByNickname orders the results by the nickname field.
+func ByNickname(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldNickname, opts...).ToFunc()
+}
+
+// ByTel orders the results by the tel field.
+func ByTel(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldTel, opts...).ToFunc()
+}
+
+// ByHeadBig orders the results by the head_big field.
+func ByHeadBig(opts ...sql.OrderTermOption) OrderOption {
+	return sql.OrderByField(FieldHeadBig, opts...).ToFunc()
+}
+
+// ByServerField orders the results by server field.
+func ByServerField(field string, opts ...sql.OrderTermOption) OrderOption {
+	return func(s *sql.Selector) {
+		sqlgraph.OrderByNeighborTerms(s, newServerStep(), sql.OrderByField(field, opts...))
+	}
+}
+func newServerStep() *sqlgraph.Step {
+	return sqlgraph.NewStep(
+		sqlgraph.From(Table, FieldID),
+		sqlgraph.To(ServerInverseTable, FieldID),
+		sqlgraph.Edge(sqlgraph.M2O, true, ServerTable, ServerColumn),
+	)
+}

+ 1344 - 0
ent/wx_create.go

@@ -0,0 +1,1344 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// WxCreate is the builder for creating a Wx entity.
+type WxCreate struct {
+	config
+	mutation *WxMutation
+	hooks    []Hook
+	conflict []sql.ConflictOption
+}
+
+// SetCreatedAt sets the "created_at" field.
+func (wc *WxCreate) SetCreatedAt(t time.Time) *WxCreate {
+	wc.mutation.SetCreatedAt(t)
+	return wc
+}
+
+// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
+func (wc *WxCreate) SetNillableCreatedAt(t *time.Time) *WxCreate {
+	if t != nil {
+		wc.SetCreatedAt(*t)
+	}
+	return wc
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (wc *WxCreate) SetUpdatedAt(t time.Time) *WxCreate {
+	wc.mutation.SetUpdatedAt(t)
+	return wc
+}
+
+// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
+func (wc *WxCreate) SetNillableUpdatedAt(t *time.Time) *WxCreate {
+	if t != nil {
+		wc.SetUpdatedAt(*t)
+	}
+	return wc
+}
+
+// SetStatus sets the "status" field.
+func (wc *WxCreate) SetStatus(u uint8) *WxCreate {
+	wc.mutation.SetStatus(u)
+	return wc
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (wc *WxCreate) SetNillableStatus(u *uint8) *WxCreate {
+	if u != nil {
+		wc.SetStatus(*u)
+	}
+	return wc
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (wc *WxCreate) SetDeletedAt(t time.Time) *WxCreate {
+	wc.mutation.SetDeletedAt(t)
+	return wc
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (wc *WxCreate) SetNillableDeletedAt(t *time.Time) *WxCreate {
+	if t != nil {
+		wc.SetDeletedAt(*t)
+	}
+	return wc
+}
+
+// SetServerID sets the "server_id" field.
+func (wc *WxCreate) SetServerID(u uint64) *WxCreate {
+	wc.mutation.SetServerID(u)
+	return wc
+}
+
+// SetNillableServerID sets the "server_id" field if the given value is not nil.
+func (wc *WxCreate) SetNillableServerID(u *uint64) *WxCreate {
+	if u != nil {
+		wc.SetServerID(*u)
+	}
+	return wc
+}
+
+// SetPort sets the "port" field.
+func (wc *WxCreate) SetPort(s string) *WxCreate {
+	wc.mutation.SetPort(s)
+	return wc
+}
+
+// SetNillablePort sets the "port" field if the given value is not nil.
+func (wc *WxCreate) SetNillablePort(s *string) *WxCreate {
+	if s != nil {
+		wc.SetPort(*s)
+	}
+	return wc
+}
+
+// SetProcessID sets the "process_id" field.
+func (wc *WxCreate) SetProcessID(s string) *WxCreate {
+	wc.mutation.SetProcessID(s)
+	return wc
+}
+
+// SetNillableProcessID sets the "process_id" field if the given value is not nil.
+func (wc *WxCreate) SetNillableProcessID(s *string) *WxCreate {
+	if s != nil {
+		wc.SetProcessID(*s)
+	}
+	return wc
+}
+
+// SetCallback sets the "callback" field.
+func (wc *WxCreate) SetCallback(s string) *WxCreate {
+	wc.mutation.SetCallback(s)
+	return wc
+}
+
+// SetNillableCallback sets the "callback" field if the given value is not nil.
+func (wc *WxCreate) SetNillableCallback(s *string) *WxCreate {
+	if s != nil {
+		wc.SetCallback(*s)
+	}
+	return wc
+}
+
+// SetWxid sets the "wxid" field.
+func (wc *WxCreate) SetWxid(s string) *WxCreate {
+	wc.mutation.SetWxid(s)
+	return wc
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (wc *WxCreate) SetNillableWxid(s *string) *WxCreate {
+	if s != nil {
+		wc.SetWxid(*s)
+	}
+	return wc
+}
+
+// SetAccount sets the "account" field.
+func (wc *WxCreate) SetAccount(s string) *WxCreate {
+	wc.mutation.SetAccount(s)
+	return wc
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (wc *WxCreate) SetNillableAccount(s *string) *WxCreate {
+	if s != nil {
+		wc.SetAccount(*s)
+	}
+	return wc
+}
+
+// SetNickname sets the "nickname" field.
+func (wc *WxCreate) SetNickname(s string) *WxCreate {
+	wc.mutation.SetNickname(s)
+	return wc
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (wc *WxCreate) SetNillableNickname(s *string) *WxCreate {
+	if s != nil {
+		wc.SetNickname(*s)
+	}
+	return wc
+}
+
+// SetTel sets the "tel" field.
+func (wc *WxCreate) SetTel(s string) *WxCreate {
+	wc.mutation.SetTel(s)
+	return wc
+}
+
+// SetNillableTel sets the "tel" field if the given value is not nil.
+func (wc *WxCreate) SetNillableTel(s *string) *WxCreate {
+	if s != nil {
+		wc.SetTel(*s)
+	}
+	return wc
+}
+
+// SetHeadBig sets the "head_big" field.
+func (wc *WxCreate) SetHeadBig(s string) *WxCreate {
+	wc.mutation.SetHeadBig(s)
+	return wc
+}
+
+// SetNillableHeadBig sets the "head_big" field if the given value is not nil.
+func (wc *WxCreate) SetNillableHeadBig(s *string) *WxCreate {
+	if s != nil {
+		wc.SetHeadBig(*s)
+	}
+	return wc
+}
+
+// SetID sets the "id" field.
+func (wc *WxCreate) SetID(u uint64) *WxCreate {
+	wc.mutation.SetID(u)
+	return wc
+}
+
+// SetServer sets the "server" edge to the Server entity.
+func (wc *WxCreate) SetServer(s *Server) *WxCreate {
+	return wc.SetServerID(s.ID)
+}
+
+// Mutation returns the WxMutation object of the builder.
+func (wc *WxCreate) Mutation() *WxMutation {
+	return wc.mutation
+}
+
+// Save creates the Wx in the database.
+func (wc *WxCreate) Save(ctx context.Context) (*Wx, error) {
+	if err := wc.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, wc.sqlSave, wc.mutation, wc.hooks)
+}
+
+// SaveX calls Save and panics if Save returns an error.
+func (wc *WxCreate) SaveX(ctx context.Context) *Wx {
+	v, err := wc.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (wc *WxCreate) Exec(ctx context.Context) error {
+	_, err := wc.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (wc *WxCreate) ExecX(ctx context.Context) {
+	if err := wc.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (wc *WxCreate) defaults() error {
+	if _, ok := wc.mutation.CreatedAt(); !ok {
+		if wx.DefaultCreatedAt == nil {
+			return fmt.Errorf("ent: uninitialized wx.DefaultCreatedAt (forgotten import ent/runtime?)")
+		}
+		v := wx.DefaultCreatedAt()
+		wc.mutation.SetCreatedAt(v)
+	}
+	if _, ok := wc.mutation.UpdatedAt(); !ok {
+		if wx.DefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized wx.DefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := wx.DefaultUpdatedAt()
+		wc.mutation.SetUpdatedAt(v)
+	}
+	if _, ok := wc.mutation.Status(); !ok {
+		v := wx.DefaultStatus
+		wc.mutation.SetStatus(v)
+	}
+	if _, ok := wc.mutation.ServerID(); !ok {
+		v := wx.DefaultServerID
+		wc.mutation.SetServerID(v)
+	}
+	if _, ok := wc.mutation.Port(); !ok {
+		v := wx.DefaultPort
+		wc.mutation.SetPort(v)
+	}
+	if _, ok := wc.mutation.ProcessID(); !ok {
+		v := wx.DefaultProcessID
+		wc.mutation.SetProcessID(v)
+	}
+	if _, ok := wc.mutation.Callback(); !ok {
+		v := wx.DefaultCallback
+		wc.mutation.SetCallback(v)
+	}
+	if _, ok := wc.mutation.Wxid(); !ok {
+		v := wx.DefaultWxid
+		wc.mutation.SetWxid(v)
+	}
+	if _, ok := wc.mutation.Account(); !ok {
+		v := wx.DefaultAccount
+		wc.mutation.SetAccount(v)
+	}
+	if _, ok := wc.mutation.Nickname(); !ok {
+		v := wx.DefaultNickname
+		wc.mutation.SetNickname(v)
+	}
+	if _, ok := wc.mutation.Tel(); !ok {
+		v := wx.DefaultTel
+		wc.mutation.SetTel(v)
+	}
+	if _, ok := wc.mutation.HeadBig(); !ok {
+		v := wx.DefaultHeadBig
+		wc.mutation.SetHeadBig(v)
+	}
+	return nil
+}
+
+// check runs all checks and user-defined validators on the builder.
+func (wc *WxCreate) check() error {
+	if _, ok := wc.mutation.CreatedAt(); !ok {
+		return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Wx.created_at"`)}
+	}
+	if _, ok := wc.mutation.UpdatedAt(); !ok {
+		return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Wx.updated_at"`)}
+	}
+	if _, ok := wc.mutation.Port(); !ok {
+		return &ValidationError{Name: "port", err: errors.New(`ent: missing required field "Wx.port"`)}
+	}
+	if _, ok := wc.mutation.ProcessID(); !ok {
+		return &ValidationError{Name: "process_id", err: errors.New(`ent: missing required field "Wx.process_id"`)}
+	}
+	if _, ok := wc.mutation.Callback(); !ok {
+		return &ValidationError{Name: "callback", err: errors.New(`ent: missing required field "Wx.callback"`)}
+	}
+	if _, ok := wc.mutation.Wxid(); !ok {
+		return &ValidationError{Name: "wxid", err: errors.New(`ent: missing required field "Wx.wxid"`)}
+	}
+	if _, ok := wc.mutation.Account(); !ok {
+		return &ValidationError{Name: "account", err: errors.New(`ent: missing required field "Wx.account"`)}
+	}
+	if _, ok := wc.mutation.Nickname(); !ok {
+		return &ValidationError{Name: "nickname", err: errors.New(`ent: missing required field "Wx.nickname"`)}
+	}
+	if _, ok := wc.mutation.Tel(); !ok {
+		return &ValidationError{Name: "tel", err: errors.New(`ent: missing required field "Wx.tel"`)}
+	}
+	if _, ok := wc.mutation.HeadBig(); !ok {
+		return &ValidationError{Name: "head_big", err: errors.New(`ent: missing required field "Wx.head_big"`)}
+	}
+	return nil
+}
+
+func (wc *WxCreate) sqlSave(ctx context.Context) (*Wx, error) {
+	if err := wc.check(); err != nil {
+		return nil, err
+	}
+	_node, _spec := wc.createSpec()
+	if err := sqlgraph.CreateNode(ctx, wc.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)
+	}
+	wc.mutation.id = &_node.ID
+	wc.mutation.done = true
+	return _node, nil
+}
+
+func (wc *WxCreate) createSpec() (*Wx, *sqlgraph.CreateSpec) {
+	var (
+		_node = &Wx{config: wc.config}
+		_spec = sqlgraph.NewCreateSpec(wx.Table, sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64))
+	)
+	_spec.OnConflict = wc.conflict
+	if id, ok := wc.mutation.ID(); ok {
+		_node.ID = id
+		_spec.ID.Value = id
+	}
+	if value, ok := wc.mutation.CreatedAt(); ok {
+		_spec.SetField(wx.FieldCreatedAt, field.TypeTime, value)
+		_node.CreatedAt = value
+	}
+	if value, ok := wc.mutation.UpdatedAt(); ok {
+		_spec.SetField(wx.FieldUpdatedAt, field.TypeTime, value)
+		_node.UpdatedAt = value
+	}
+	if value, ok := wc.mutation.Status(); ok {
+		_spec.SetField(wx.FieldStatus, field.TypeUint8, value)
+		_node.Status = value
+	}
+	if value, ok := wc.mutation.DeletedAt(); ok {
+		_spec.SetField(wx.FieldDeletedAt, field.TypeTime, value)
+		_node.DeletedAt = value
+	}
+	if value, ok := wc.mutation.Port(); ok {
+		_spec.SetField(wx.FieldPort, field.TypeString, value)
+		_node.Port = value
+	}
+	if value, ok := wc.mutation.ProcessID(); ok {
+		_spec.SetField(wx.FieldProcessID, field.TypeString, value)
+		_node.ProcessID = value
+	}
+	if value, ok := wc.mutation.Callback(); ok {
+		_spec.SetField(wx.FieldCallback, field.TypeString, value)
+		_node.Callback = value
+	}
+	if value, ok := wc.mutation.Wxid(); ok {
+		_spec.SetField(wx.FieldWxid, field.TypeString, value)
+		_node.Wxid = value
+	}
+	if value, ok := wc.mutation.Account(); ok {
+		_spec.SetField(wx.FieldAccount, field.TypeString, value)
+		_node.Account = value
+	}
+	if value, ok := wc.mutation.Nickname(); ok {
+		_spec.SetField(wx.FieldNickname, field.TypeString, value)
+		_node.Nickname = value
+	}
+	if value, ok := wc.mutation.Tel(); ok {
+		_spec.SetField(wx.FieldTel, field.TypeString, value)
+		_node.Tel = value
+	}
+	if value, ok := wc.mutation.HeadBig(); ok {
+		_spec.SetField(wx.FieldHeadBig, field.TypeString, value)
+		_node.HeadBig = value
+	}
+	if nodes := wc.mutation.ServerIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   wx.ServerTable,
+			Columns: []string{wx.ServerColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_node.ServerID = 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.Wx.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.WxUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (wc *WxCreate) OnConflict(opts ...sql.ConflictOption) *WxUpsertOne {
+	wc.conflict = opts
+	return &WxUpsertOne{
+		create: wc,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Wx.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (wc *WxCreate) OnConflictColumns(columns ...string) *WxUpsertOne {
+	wc.conflict = append(wc.conflict, sql.ConflictColumns(columns...))
+	return &WxUpsertOne{
+		create: wc,
+	}
+}
+
+type (
+	// WxUpsertOne is the builder for "upsert"-ing
+	//  one Wx node.
+	WxUpsertOne struct {
+		create *WxCreate
+	}
+
+	// WxUpsert is the "OnConflict" setter.
+	WxUpsert struct {
+		*sql.UpdateSet
+	}
+)
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *WxUpsert) SetUpdatedAt(v time.Time) *WxUpsert {
+	u.Set(wx.FieldUpdatedAt, v)
+	return u
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *WxUpsert) UpdateUpdatedAt() *WxUpsert {
+	u.SetExcluded(wx.FieldUpdatedAt)
+	return u
+}
+
+// SetStatus sets the "status" field.
+func (u *WxUpsert) SetStatus(v uint8) *WxUpsert {
+	u.Set(wx.FieldStatus, v)
+	return u
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *WxUpsert) UpdateStatus() *WxUpsert {
+	u.SetExcluded(wx.FieldStatus)
+	return u
+}
+
+// AddStatus adds v to the "status" field.
+func (u *WxUpsert) AddStatus(v uint8) *WxUpsert {
+	u.Add(wx.FieldStatus, v)
+	return u
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *WxUpsert) ClearStatus() *WxUpsert {
+	u.SetNull(wx.FieldStatus)
+	return u
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *WxUpsert) SetDeletedAt(v time.Time) *WxUpsert {
+	u.Set(wx.FieldDeletedAt, v)
+	return u
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *WxUpsert) UpdateDeletedAt() *WxUpsert {
+	u.SetExcluded(wx.FieldDeletedAt)
+	return u
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *WxUpsert) ClearDeletedAt() *WxUpsert {
+	u.SetNull(wx.FieldDeletedAt)
+	return u
+}
+
+// SetServerID sets the "server_id" field.
+func (u *WxUpsert) SetServerID(v uint64) *WxUpsert {
+	u.Set(wx.FieldServerID, v)
+	return u
+}
+
+// UpdateServerID sets the "server_id" field to the value that was provided on create.
+func (u *WxUpsert) UpdateServerID() *WxUpsert {
+	u.SetExcluded(wx.FieldServerID)
+	return u
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (u *WxUpsert) ClearServerID() *WxUpsert {
+	u.SetNull(wx.FieldServerID)
+	return u
+}
+
+// SetPort sets the "port" field.
+func (u *WxUpsert) SetPort(v string) *WxUpsert {
+	u.Set(wx.FieldPort, v)
+	return u
+}
+
+// UpdatePort sets the "port" field to the value that was provided on create.
+func (u *WxUpsert) UpdatePort() *WxUpsert {
+	u.SetExcluded(wx.FieldPort)
+	return u
+}
+
+// SetProcessID sets the "process_id" field.
+func (u *WxUpsert) SetProcessID(v string) *WxUpsert {
+	u.Set(wx.FieldProcessID, v)
+	return u
+}
+
+// UpdateProcessID sets the "process_id" field to the value that was provided on create.
+func (u *WxUpsert) UpdateProcessID() *WxUpsert {
+	u.SetExcluded(wx.FieldProcessID)
+	return u
+}
+
+// SetCallback sets the "callback" field.
+func (u *WxUpsert) SetCallback(v string) *WxUpsert {
+	u.Set(wx.FieldCallback, v)
+	return u
+}
+
+// UpdateCallback sets the "callback" field to the value that was provided on create.
+func (u *WxUpsert) UpdateCallback() *WxUpsert {
+	u.SetExcluded(wx.FieldCallback)
+	return u
+}
+
+// SetWxid sets the "wxid" field.
+func (u *WxUpsert) SetWxid(v string) *WxUpsert {
+	u.Set(wx.FieldWxid, v)
+	return u
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *WxUpsert) UpdateWxid() *WxUpsert {
+	u.SetExcluded(wx.FieldWxid)
+	return u
+}
+
+// SetAccount sets the "account" field.
+func (u *WxUpsert) SetAccount(v string) *WxUpsert {
+	u.Set(wx.FieldAccount, v)
+	return u
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *WxUpsert) UpdateAccount() *WxUpsert {
+	u.SetExcluded(wx.FieldAccount)
+	return u
+}
+
+// SetNickname sets the "nickname" field.
+func (u *WxUpsert) SetNickname(v string) *WxUpsert {
+	u.Set(wx.FieldNickname, v)
+	return u
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *WxUpsert) UpdateNickname() *WxUpsert {
+	u.SetExcluded(wx.FieldNickname)
+	return u
+}
+
+// SetTel sets the "tel" field.
+func (u *WxUpsert) SetTel(v string) *WxUpsert {
+	u.Set(wx.FieldTel, v)
+	return u
+}
+
+// UpdateTel sets the "tel" field to the value that was provided on create.
+func (u *WxUpsert) UpdateTel() *WxUpsert {
+	u.SetExcluded(wx.FieldTel)
+	return u
+}
+
+// SetHeadBig sets the "head_big" field.
+func (u *WxUpsert) SetHeadBig(v string) *WxUpsert {
+	u.Set(wx.FieldHeadBig, v)
+	return u
+}
+
+// UpdateHeadBig sets the "head_big" field to the value that was provided on create.
+func (u *WxUpsert) UpdateHeadBig() *WxUpsert {
+	u.SetExcluded(wx.FieldHeadBig)
+	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.Wx.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(wx.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *WxUpsertOne) UpdateNewValues() *WxUpsertOne {
+	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(wx.FieldID)
+		}
+		if _, exists := u.create.mutation.CreatedAt(); exists {
+			s.SetIgnore(wx.FieldCreatedAt)
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Wx.Create().
+//	    OnConflict(sql.ResolveWithIgnore()).
+//	    Exec(ctx)
+func (u *WxUpsertOne) Ignore() *WxUpsertOne {
+	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 *WxUpsertOne) DoNothing() *WxUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the WxCreate.OnConflict
+// documentation for more info.
+func (u *WxUpsertOne) Update(set func(*WxUpsert)) *WxUpsertOne {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&WxUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *WxUpsertOne) SetUpdatedAt(v time.Time) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateUpdatedAt() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *WxUpsertOne) SetStatus(v uint8) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *WxUpsertOne) AddStatus(v uint8) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateStatus() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *WxUpsertOne) ClearStatus() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *WxUpsertOne) SetDeletedAt(v time.Time) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateDeletedAt() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *WxUpsertOne) ClearDeletedAt() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetServerID sets the "server_id" field.
+func (u *WxUpsertOne) SetServerID(v uint64) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetServerID(v)
+	})
+}
+
+// UpdateServerID sets the "server_id" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateServerID() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateServerID()
+	})
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (u *WxUpsertOne) ClearServerID() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearServerID()
+	})
+}
+
+// SetPort sets the "port" field.
+func (u *WxUpsertOne) SetPort(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetPort(v)
+	})
+}
+
+// UpdatePort sets the "port" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdatePort() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdatePort()
+	})
+}
+
+// SetProcessID sets the "process_id" field.
+func (u *WxUpsertOne) SetProcessID(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetProcessID(v)
+	})
+}
+
+// UpdateProcessID sets the "process_id" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateProcessID() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateProcessID()
+	})
+}
+
+// SetCallback sets the "callback" field.
+func (u *WxUpsertOne) SetCallback(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetCallback(v)
+	})
+}
+
+// UpdateCallback sets the "callback" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateCallback() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateCallback()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *WxUpsertOne) SetWxid(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateWxid() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAccount sets the "account" field.
+func (u *WxUpsertOne) SetAccount(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetAccount(v)
+	})
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateAccount() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateAccount()
+	})
+}
+
+// SetNickname sets the "nickname" field.
+func (u *WxUpsertOne) SetNickname(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetNickname(v)
+	})
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateNickname() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateNickname()
+	})
+}
+
+// SetTel sets the "tel" field.
+func (u *WxUpsertOne) SetTel(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetTel(v)
+	})
+}
+
+// UpdateTel sets the "tel" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateTel() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateTel()
+	})
+}
+
+// SetHeadBig sets the "head_big" field.
+func (u *WxUpsertOne) SetHeadBig(v string) *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.SetHeadBig(v)
+	})
+}
+
+// UpdateHeadBig sets the "head_big" field to the value that was provided on create.
+func (u *WxUpsertOne) UpdateHeadBig() *WxUpsertOne {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateHeadBig()
+	})
+}
+
+// Exec executes the query.
+func (u *WxUpsertOne) Exec(ctx context.Context) error {
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for WxCreate.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *WxUpsertOne) 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 *WxUpsertOne) 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 *WxUpsertOne) IDX(ctx context.Context) uint64 {
+	id, err := u.ID(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return id
+}
+
+// WxCreateBulk is the builder for creating many Wx entities in bulk.
+type WxCreateBulk struct {
+	config
+	err      error
+	builders []*WxCreate
+	conflict []sql.ConflictOption
+}
+
+// Save creates the Wx entities in the database.
+func (wcb *WxCreateBulk) Save(ctx context.Context) ([]*Wx, error) {
+	if wcb.err != nil {
+		return nil, wcb.err
+	}
+	specs := make([]*sqlgraph.CreateSpec, len(wcb.builders))
+	nodes := make([]*Wx, len(wcb.builders))
+	mutators := make([]Mutator, len(wcb.builders))
+	for i := range wcb.builders {
+		func(i int, root context.Context) {
+			builder := wcb.builders[i]
+			builder.defaults()
+			var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
+				mutation, ok := m.(*WxMutation)
+				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, wcb.builders[i+1].mutation)
+				} else {
+					spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
+					spec.OnConflict = wcb.conflict
+					// Invoke the actual operation on the latest mutation in the chain.
+					if err = sqlgraph.BatchCreate(ctx, wcb.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, wcb.builders[0].mutation); err != nil {
+			return nil, err
+		}
+	}
+	return nodes, nil
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (wcb *WxCreateBulk) SaveX(ctx context.Context) []*Wx {
+	v, err := wcb.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+// Exec executes the query.
+func (wcb *WxCreateBulk) Exec(ctx context.Context) error {
+	_, err := wcb.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (wcb *WxCreateBulk) ExecX(ctx context.Context) {
+	if err := wcb.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
+// of the `INSERT` statement. For example:
+//
+//	client.Wx.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.WxUpsert) {
+//			SetCreatedAt(v+v).
+//		}).
+//		Exec(ctx)
+func (wcb *WxCreateBulk) OnConflict(opts ...sql.ConflictOption) *WxUpsertBulk {
+	wcb.conflict = opts
+	return &WxUpsertBulk{
+		create: wcb,
+	}
+}
+
+// OnConflictColumns calls `OnConflict` and configures the columns
+// as conflict target. Using this option is equivalent to using:
+//
+//	client.Wx.Create().
+//		OnConflict(sql.ConflictColumns(columns...)).
+//		Exec(ctx)
+func (wcb *WxCreateBulk) OnConflictColumns(columns ...string) *WxUpsertBulk {
+	wcb.conflict = append(wcb.conflict, sql.ConflictColumns(columns...))
+	return &WxUpsertBulk{
+		create: wcb,
+	}
+}
+
+// WxUpsertBulk is the builder for "upsert"-ing
+// a bulk of Wx nodes.
+type WxUpsertBulk struct {
+	create *WxCreateBulk
+}
+
+// UpdateNewValues updates the mutable fields using the new values that
+// were set on create. Using this option is equivalent to using:
+//
+//	client.Wx.Create().
+//		OnConflict(
+//			sql.ResolveWithNewValues(),
+//			sql.ResolveWith(func(u *sql.UpdateSet) {
+//				u.SetIgnore(wx.FieldID)
+//			}),
+//		).
+//		Exec(ctx)
+func (u *WxUpsertBulk) UpdateNewValues() *WxUpsertBulk {
+	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(wx.FieldID)
+			}
+			if _, exists := b.mutation.CreatedAt(); exists {
+				s.SetIgnore(wx.FieldCreatedAt)
+			}
+		}
+	}))
+	return u
+}
+
+// Ignore sets each column to itself in case of conflict.
+// Using this option is equivalent to using:
+//
+//	client.Wx.Create().
+//		OnConflict(sql.ResolveWithIgnore()).
+//		Exec(ctx)
+func (u *WxUpsertBulk) Ignore() *WxUpsertBulk {
+	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 *WxUpsertBulk) DoNothing() *WxUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.DoNothing())
+	return u
+}
+
+// Update allows overriding fields `UPDATE` values. See the WxCreateBulk.OnConflict
+// documentation for more info.
+func (u *WxUpsertBulk) Update(set func(*WxUpsert)) *WxUpsertBulk {
+	u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
+		set(&WxUpsert{UpdateSet: update})
+	}))
+	return u
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (u *WxUpsertBulk) SetUpdatedAt(v time.Time) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetUpdatedAt(v)
+	})
+}
+
+// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateUpdatedAt() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateUpdatedAt()
+	})
+}
+
+// SetStatus sets the "status" field.
+func (u *WxUpsertBulk) SetStatus(v uint8) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetStatus(v)
+	})
+}
+
+// AddStatus adds v to the "status" field.
+func (u *WxUpsertBulk) AddStatus(v uint8) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.AddStatus(v)
+	})
+}
+
+// UpdateStatus sets the "status" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateStatus() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateStatus()
+	})
+}
+
+// ClearStatus clears the value of the "status" field.
+func (u *WxUpsertBulk) ClearStatus() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearStatus()
+	})
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (u *WxUpsertBulk) SetDeletedAt(v time.Time) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetDeletedAt(v)
+	})
+}
+
+// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateDeletedAt() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateDeletedAt()
+	})
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (u *WxUpsertBulk) ClearDeletedAt() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearDeletedAt()
+	})
+}
+
+// SetServerID sets the "server_id" field.
+func (u *WxUpsertBulk) SetServerID(v uint64) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetServerID(v)
+	})
+}
+
+// UpdateServerID sets the "server_id" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateServerID() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateServerID()
+	})
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (u *WxUpsertBulk) ClearServerID() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.ClearServerID()
+	})
+}
+
+// SetPort sets the "port" field.
+func (u *WxUpsertBulk) SetPort(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetPort(v)
+	})
+}
+
+// UpdatePort sets the "port" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdatePort() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdatePort()
+	})
+}
+
+// SetProcessID sets the "process_id" field.
+func (u *WxUpsertBulk) SetProcessID(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetProcessID(v)
+	})
+}
+
+// UpdateProcessID sets the "process_id" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateProcessID() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateProcessID()
+	})
+}
+
+// SetCallback sets the "callback" field.
+func (u *WxUpsertBulk) SetCallback(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetCallback(v)
+	})
+}
+
+// UpdateCallback sets the "callback" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateCallback() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateCallback()
+	})
+}
+
+// SetWxid sets the "wxid" field.
+func (u *WxUpsertBulk) SetWxid(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetWxid(v)
+	})
+}
+
+// UpdateWxid sets the "wxid" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateWxid() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateWxid()
+	})
+}
+
+// SetAccount sets the "account" field.
+func (u *WxUpsertBulk) SetAccount(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetAccount(v)
+	})
+}
+
+// UpdateAccount sets the "account" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateAccount() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateAccount()
+	})
+}
+
+// SetNickname sets the "nickname" field.
+func (u *WxUpsertBulk) SetNickname(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetNickname(v)
+	})
+}
+
+// UpdateNickname sets the "nickname" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateNickname() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateNickname()
+	})
+}
+
+// SetTel sets the "tel" field.
+func (u *WxUpsertBulk) SetTel(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetTel(v)
+	})
+}
+
+// UpdateTel sets the "tel" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateTel() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateTel()
+	})
+}
+
+// SetHeadBig sets the "head_big" field.
+func (u *WxUpsertBulk) SetHeadBig(v string) *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.SetHeadBig(v)
+	})
+}
+
+// UpdateHeadBig sets the "head_big" field to the value that was provided on create.
+func (u *WxUpsertBulk) UpdateHeadBig() *WxUpsertBulk {
+	return u.Update(func(s *WxUpsert) {
+		s.UpdateHeadBig()
+	})
+}
+
+// Exec executes the query.
+func (u *WxUpsertBulk) 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 WxCreateBulk instead", i)
+		}
+	}
+	if len(u.create.conflict) == 0 {
+		return errors.New("ent: missing options for WxCreateBulk.OnConflict")
+	}
+	return u.create.Exec(ctx)
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (u *WxUpsertBulk) ExecX(ctx context.Context) {
+	if err := u.create.Exec(ctx); err != nil {
+		panic(err)
+	}
+}

+ 88 - 0
ent/wx_delete.go

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

+ 605 - 0
ent/wx_query.go

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

+ 741 - 0
ent/wx_update.go

@@ -0,0 +1,741 @@
+// Code generated by ent, DO NOT EDIT.
+
+package ent
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"time"
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/server"
+	"wechat-api/ent/wx"
+
+	"entgo.io/ent/dialect/sql"
+	"entgo.io/ent/dialect/sql/sqlgraph"
+	"entgo.io/ent/schema/field"
+)
+
+// WxUpdate is the builder for updating Wx entities.
+type WxUpdate struct {
+	config
+	hooks    []Hook
+	mutation *WxMutation
+}
+
+// Where appends a list predicates to the WxUpdate builder.
+func (wu *WxUpdate) Where(ps ...predicate.Wx) *WxUpdate {
+	wu.mutation.Where(ps...)
+	return wu
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (wu *WxUpdate) SetUpdatedAt(t time.Time) *WxUpdate {
+	wu.mutation.SetUpdatedAt(t)
+	return wu
+}
+
+// SetStatus sets the "status" field.
+func (wu *WxUpdate) SetStatus(u uint8) *WxUpdate {
+	wu.mutation.ResetStatus()
+	wu.mutation.SetStatus(u)
+	return wu
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableStatus(u *uint8) *WxUpdate {
+	if u != nil {
+		wu.SetStatus(*u)
+	}
+	return wu
+}
+
+// AddStatus adds u to the "status" field.
+func (wu *WxUpdate) AddStatus(u int8) *WxUpdate {
+	wu.mutation.AddStatus(u)
+	return wu
+}
+
+// ClearStatus clears the value of the "status" field.
+func (wu *WxUpdate) ClearStatus() *WxUpdate {
+	wu.mutation.ClearStatus()
+	return wu
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (wu *WxUpdate) SetDeletedAt(t time.Time) *WxUpdate {
+	wu.mutation.SetDeletedAt(t)
+	return wu
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableDeletedAt(t *time.Time) *WxUpdate {
+	if t != nil {
+		wu.SetDeletedAt(*t)
+	}
+	return wu
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (wu *WxUpdate) ClearDeletedAt() *WxUpdate {
+	wu.mutation.ClearDeletedAt()
+	return wu
+}
+
+// SetServerID sets the "server_id" field.
+func (wu *WxUpdate) SetServerID(u uint64) *WxUpdate {
+	wu.mutation.SetServerID(u)
+	return wu
+}
+
+// SetNillableServerID sets the "server_id" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableServerID(u *uint64) *WxUpdate {
+	if u != nil {
+		wu.SetServerID(*u)
+	}
+	return wu
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (wu *WxUpdate) ClearServerID() *WxUpdate {
+	wu.mutation.ClearServerID()
+	return wu
+}
+
+// SetPort sets the "port" field.
+func (wu *WxUpdate) SetPort(s string) *WxUpdate {
+	wu.mutation.SetPort(s)
+	return wu
+}
+
+// SetNillablePort sets the "port" field if the given value is not nil.
+func (wu *WxUpdate) SetNillablePort(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetPort(*s)
+	}
+	return wu
+}
+
+// SetProcessID sets the "process_id" field.
+func (wu *WxUpdate) SetProcessID(s string) *WxUpdate {
+	wu.mutation.SetProcessID(s)
+	return wu
+}
+
+// SetNillableProcessID sets the "process_id" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableProcessID(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetProcessID(*s)
+	}
+	return wu
+}
+
+// SetCallback sets the "callback" field.
+func (wu *WxUpdate) SetCallback(s string) *WxUpdate {
+	wu.mutation.SetCallback(s)
+	return wu
+}
+
+// SetNillableCallback sets the "callback" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableCallback(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetCallback(*s)
+	}
+	return wu
+}
+
+// SetWxid sets the "wxid" field.
+func (wu *WxUpdate) SetWxid(s string) *WxUpdate {
+	wu.mutation.SetWxid(s)
+	return wu
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableWxid(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetWxid(*s)
+	}
+	return wu
+}
+
+// SetAccount sets the "account" field.
+func (wu *WxUpdate) SetAccount(s string) *WxUpdate {
+	wu.mutation.SetAccount(s)
+	return wu
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableAccount(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetAccount(*s)
+	}
+	return wu
+}
+
+// SetNickname sets the "nickname" field.
+func (wu *WxUpdate) SetNickname(s string) *WxUpdate {
+	wu.mutation.SetNickname(s)
+	return wu
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableNickname(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetNickname(*s)
+	}
+	return wu
+}
+
+// SetTel sets the "tel" field.
+func (wu *WxUpdate) SetTel(s string) *WxUpdate {
+	wu.mutation.SetTel(s)
+	return wu
+}
+
+// SetNillableTel sets the "tel" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableTel(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetTel(*s)
+	}
+	return wu
+}
+
+// SetHeadBig sets the "head_big" field.
+func (wu *WxUpdate) SetHeadBig(s string) *WxUpdate {
+	wu.mutation.SetHeadBig(s)
+	return wu
+}
+
+// SetNillableHeadBig sets the "head_big" field if the given value is not nil.
+func (wu *WxUpdate) SetNillableHeadBig(s *string) *WxUpdate {
+	if s != nil {
+		wu.SetHeadBig(*s)
+	}
+	return wu
+}
+
+// SetServer sets the "server" edge to the Server entity.
+func (wu *WxUpdate) SetServer(s *Server) *WxUpdate {
+	return wu.SetServerID(s.ID)
+}
+
+// Mutation returns the WxMutation object of the builder.
+func (wu *WxUpdate) Mutation() *WxMutation {
+	return wu.mutation
+}
+
+// ClearServer clears the "server" edge to the Server entity.
+func (wu *WxUpdate) ClearServer() *WxUpdate {
+	wu.mutation.ClearServer()
+	return wu
+}
+
+// Save executes the query and returns the number of nodes affected by the update operation.
+func (wu *WxUpdate) Save(ctx context.Context) (int, error) {
+	if err := wu.defaults(); err != nil {
+		return 0, err
+	}
+	return withHooks(ctx, wu.sqlSave, wu.mutation, wu.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (wu *WxUpdate) SaveX(ctx context.Context) int {
+	affected, err := wu.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return affected
+}
+
+// Exec executes the query.
+func (wu *WxUpdate) Exec(ctx context.Context) error {
+	_, err := wu.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (wu *WxUpdate) ExecX(ctx context.Context) {
+	if err := wu.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (wu *WxUpdate) defaults() error {
+	if _, ok := wu.mutation.UpdatedAt(); !ok {
+		if wx.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized wx.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := wx.UpdateDefaultUpdatedAt()
+		wu.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (wu *WxUpdate) sqlSave(ctx context.Context) (n int, err error) {
+	_spec := sqlgraph.NewUpdateSpec(wx.Table, wx.Columns, sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64))
+	if ps := wu.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := wu.mutation.UpdatedAt(); ok {
+		_spec.SetField(wx.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := wu.mutation.Status(); ok {
+		_spec.SetField(wx.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := wu.mutation.AddedStatus(); ok {
+		_spec.AddField(wx.FieldStatus, field.TypeUint8, value)
+	}
+	if wu.mutation.StatusCleared() {
+		_spec.ClearField(wx.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := wu.mutation.DeletedAt(); ok {
+		_spec.SetField(wx.FieldDeletedAt, field.TypeTime, value)
+	}
+	if wu.mutation.DeletedAtCleared() {
+		_spec.ClearField(wx.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := wu.mutation.Port(); ok {
+		_spec.SetField(wx.FieldPort, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.ProcessID(); ok {
+		_spec.SetField(wx.FieldProcessID, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.Callback(); ok {
+		_spec.SetField(wx.FieldCallback, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.Wxid(); ok {
+		_spec.SetField(wx.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.Account(); ok {
+		_spec.SetField(wx.FieldAccount, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.Nickname(); ok {
+		_spec.SetField(wx.FieldNickname, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.Tel(); ok {
+		_spec.SetField(wx.FieldTel, field.TypeString, value)
+	}
+	if value, ok := wu.mutation.HeadBig(); ok {
+		_spec.SetField(wx.FieldHeadBig, field.TypeString, value)
+	}
+	if wu.mutation.ServerCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   wx.ServerTable,
+			Columns: []string{wx.ServerColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := wu.mutation.ServerIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   wx.ServerTable,
+			Columns: []string{wx.ServerColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(server.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, wu.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{wx.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return 0, err
+	}
+	wu.mutation.done = true
+	return n, nil
+}
+
+// WxUpdateOne is the builder for updating a single Wx entity.
+type WxUpdateOne struct {
+	config
+	fields   []string
+	hooks    []Hook
+	mutation *WxMutation
+}
+
+// SetUpdatedAt sets the "updated_at" field.
+func (wuo *WxUpdateOne) SetUpdatedAt(t time.Time) *WxUpdateOne {
+	wuo.mutation.SetUpdatedAt(t)
+	return wuo
+}
+
+// SetStatus sets the "status" field.
+func (wuo *WxUpdateOne) SetStatus(u uint8) *WxUpdateOne {
+	wuo.mutation.ResetStatus()
+	wuo.mutation.SetStatus(u)
+	return wuo
+}
+
+// SetNillableStatus sets the "status" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableStatus(u *uint8) *WxUpdateOne {
+	if u != nil {
+		wuo.SetStatus(*u)
+	}
+	return wuo
+}
+
+// AddStatus adds u to the "status" field.
+func (wuo *WxUpdateOne) AddStatus(u int8) *WxUpdateOne {
+	wuo.mutation.AddStatus(u)
+	return wuo
+}
+
+// ClearStatus clears the value of the "status" field.
+func (wuo *WxUpdateOne) ClearStatus() *WxUpdateOne {
+	wuo.mutation.ClearStatus()
+	return wuo
+}
+
+// SetDeletedAt sets the "deleted_at" field.
+func (wuo *WxUpdateOne) SetDeletedAt(t time.Time) *WxUpdateOne {
+	wuo.mutation.SetDeletedAt(t)
+	return wuo
+}
+
+// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableDeletedAt(t *time.Time) *WxUpdateOne {
+	if t != nil {
+		wuo.SetDeletedAt(*t)
+	}
+	return wuo
+}
+
+// ClearDeletedAt clears the value of the "deleted_at" field.
+func (wuo *WxUpdateOne) ClearDeletedAt() *WxUpdateOne {
+	wuo.mutation.ClearDeletedAt()
+	return wuo
+}
+
+// SetServerID sets the "server_id" field.
+func (wuo *WxUpdateOne) SetServerID(u uint64) *WxUpdateOne {
+	wuo.mutation.SetServerID(u)
+	return wuo
+}
+
+// SetNillableServerID sets the "server_id" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableServerID(u *uint64) *WxUpdateOne {
+	if u != nil {
+		wuo.SetServerID(*u)
+	}
+	return wuo
+}
+
+// ClearServerID clears the value of the "server_id" field.
+func (wuo *WxUpdateOne) ClearServerID() *WxUpdateOne {
+	wuo.mutation.ClearServerID()
+	return wuo
+}
+
+// SetPort sets the "port" field.
+func (wuo *WxUpdateOne) SetPort(s string) *WxUpdateOne {
+	wuo.mutation.SetPort(s)
+	return wuo
+}
+
+// SetNillablePort sets the "port" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillablePort(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetPort(*s)
+	}
+	return wuo
+}
+
+// SetProcessID sets the "process_id" field.
+func (wuo *WxUpdateOne) SetProcessID(s string) *WxUpdateOne {
+	wuo.mutation.SetProcessID(s)
+	return wuo
+}
+
+// SetNillableProcessID sets the "process_id" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableProcessID(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetProcessID(*s)
+	}
+	return wuo
+}
+
+// SetCallback sets the "callback" field.
+func (wuo *WxUpdateOne) SetCallback(s string) *WxUpdateOne {
+	wuo.mutation.SetCallback(s)
+	return wuo
+}
+
+// SetNillableCallback sets the "callback" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableCallback(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetCallback(*s)
+	}
+	return wuo
+}
+
+// SetWxid sets the "wxid" field.
+func (wuo *WxUpdateOne) SetWxid(s string) *WxUpdateOne {
+	wuo.mutation.SetWxid(s)
+	return wuo
+}
+
+// SetNillableWxid sets the "wxid" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableWxid(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetWxid(*s)
+	}
+	return wuo
+}
+
+// SetAccount sets the "account" field.
+func (wuo *WxUpdateOne) SetAccount(s string) *WxUpdateOne {
+	wuo.mutation.SetAccount(s)
+	return wuo
+}
+
+// SetNillableAccount sets the "account" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableAccount(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetAccount(*s)
+	}
+	return wuo
+}
+
+// SetNickname sets the "nickname" field.
+func (wuo *WxUpdateOne) SetNickname(s string) *WxUpdateOne {
+	wuo.mutation.SetNickname(s)
+	return wuo
+}
+
+// SetNillableNickname sets the "nickname" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableNickname(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetNickname(*s)
+	}
+	return wuo
+}
+
+// SetTel sets the "tel" field.
+func (wuo *WxUpdateOne) SetTel(s string) *WxUpdateOne {
+	wuo.mutation.SetTel(s)
+	return wuo
+}
+
+// SetNillableTel sets the "tel" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableTel(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetTel(*s)
+	}
+	return wuo
+}
+
+// SetHeadBig sets the "head_big" field.
+func (wuo *WxUpdateOne) SetHeadBig(s string) *WxUpdateOne {
+	wuo.mutation.SetHeadBig(s)
+	return wuo
+}
+
+// SetNillableHeadBig sets the "head_big" field if the given value is not nil.
+func (wuo *WxUpdateOne) SetNillableHeadBig(s *string) *WxUpdateOne {
+	if s != nil {
+		wuo.SetHeadBig(*s)
+	}
+	return wuo
+}
+
+// SetServer sets the "server" edge to the Server entity.
+func (wuo *WxUpdateOne) SetServer(s *Server) *WxUpdateOne {
+	return wuo.SetServerID(s.ID)
+}
+
+// Mutation returns the WxMutation object of the builder.
+func (wuo *WxUpdateOne) Mutation() *WxMutation {
+	return wuo.mutation
+}
+
+// ClearServer clears the "server" edge to the Server entity.
+func (wuo *WxUpdateOne) ClearServer() *WxUpdateOne {
+	wuo.mutation.ClearServer()
+	return wuo
+}
+
+// Where appends a list predicates to the WxUpdate builder.
+func (wuo *WxUpdateOne) Where(ps ...predicate.Wx) *WxUpdateOne {
+	wuo.mutation.Where(ps...)
+	return wuo
+}
+
+// Select allows selecting one or more fields (columns) of the returned entity.
+// The default is selecting all fields defined in the entity schema.
+func (wuo *WxUpdateOne) Select(field string, fields ...string) *WxUpdateOne {
+	wuo.fields = append([]string{field}, fields...)
+	return wuo
+}
+
+// Save executes the query and returns the updated Wx entity.
+func (wuo *WxUpdateOne) Save(ctx context.Context) (*Wx, error) {
+	if err := wuo.defaults(); err != nil {
+		return nil, err
+	}
+	return withHooks(ctx, wuo.sqlSave, wuo.mutation, wuo.hooks)
+}
+
+// SaveX is like Save, but panics if an error occurs.
+func (wuo *WxUpdateOne) SaveX(ctx context.Context) *Wx {
+	node, err := wuo.Save(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return node
+}
+
+// Exec executes the query on the entity.
+func (wuo *WxUpdateOne) Exec(ctx context.Context) error {
+	_, err := wuo.Save(ctx)
+	return err
+}
+
+// ExecX is like Exec, but panics if an error occurs.
+func (wuo *WxUpdateOne) ExecX(ctx context.Context) {
+	if err := wuo.Exec(ctx); err != nil {
+		panic(err)
+	}
+}
+
+// defaults sets the default values of the builder before save.
+func (wuo *WxUpdateOne) defaults() error {
+	if _, ok := wuo.mutation.UpdatedAt(); !ok {
+		if wx.UpdateDefaultUpdatedAt == nil {
+			return fmt.Errorf("ent: uninitialized wx.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+		}
+		v := wx.UpdateDefaultUpdatedAt()
+		wuo.mutation.SetUpdatedAt(v)
+	}
+	return nil
+}
+
+func (wuo *WxUpdateOne) sqlSave(ctx context.Context) (_node *Wx, err error) {
+	_spec := sqlgraph.NewUpdateSpec(wx.Table, wx.Columns, sqlgraph.NewFieldSpec(wx.FieldID, field.TypeUint64))
+	id, ok := wuo.mutation.ID()
+	if !ok {
+		return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Wx.id" for update`)}
+	}
+	_spec.Node.ID.Value = id
+	if fields := wuo.fields; len(fields) > 0 {
+		_spec.Node.Columns = make([]string, 0, len(fields))
+		_spec.Node.Columns = append(_spec.Node.Columns, wx.FieldID)
+		for _, f := range fields {
+			if !wx.ValidColumn(f) {
+				return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
+			}
+			if f != wx.FieldID {
+				_spec.Node.Columns = append(_spec.Node.Columns, f)
+			}
+		}
+	}
+	if ps := wuo.mutation.predicates; len(ps) > 0 {
+		_spec.Predicate = func(selector *sql.Selector) {
+			for i := range ps {
+				ps[i](selector)
+			}
+		}
+	}
+	if value, ok := wuo.mutation.UpdatedAt(); ok {
+		_spec.SetField(wx.FieldUpdatedAt, field.TypeTime, value)
+	}
+	if value, ok := wuo.mutation.Status(); ok {
+		_spec.SetField(wx.FieldStatus, field.TypeUint8, value)
+	}
+	if value, ok := wuo.mutation.AddedStatus(); ok {
+		_spec.AddField(wx.FieldStatus, field.TypeUint8, value)
+	}
+	if wuo.mutation.StatusCleared() {
+		_spec.ClearField(wx.FieldStatus, field.TypeUint8)
+	}
+	if value, ok := wuo.mutation.DeletedAt(); ok {
+		_spec.SetField(wx.FieldDeletedAt, field.TypeTime, value)
+	}
+	if wuo.mutation.DeletedAtCleared() {
+		_spec.ClearField(wx.FieldDeletedAt, field.TypeTime)
+	}
+	if value, ok := wuo.mutation.Port(); ok {
+		_spec.SetField(wx.FieldPort, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.ProcessID(); ok {
+		_spec.SetField(wx.FieldProcessID, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.Callback(); ok {
+		_spec.SetField(wx.FieldCallback, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.Wxid(); ok {
+		_spec.SetField(wx.FieldWxid, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.Account(); ok {
+		_spec.SetField(wx.FieldAccount, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.Nickname(); ok {
+		_spec.SetField(wx.FieldNickname, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.Tel(); ok {
+		_spec.SetField(wx.FieldTel, field.TypeString, value)
+	}
+	if value, ok := wuo.mutation.HeadBig(); ok {
+		_spec.SetField(wx.FieldHeadBig, field.TypeString, value)
+	}
+	if wuo.mutation.ServerCleared() {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   wx.ServerTable,
+			Columns: []string{wx.ServerColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64),
+			},
+		}
+		_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
+	}
+	if nodes := wuo.mutation.ServerIDs(); len(nodes) > 0 {
+		edge := &sqlgraph.EdgeSpec{
+			Rel:     sqlgraph.M2O,
+			Inverse: true,
+			Table:   wx.ServerTable,
+			Columns: []string{wx.ServerColumn},
+			Bidi:    false,
+			Target: &sqlgraph.EdgeTarget{
+				IDSpec: sqlgraph.NewFieldSpec(server.FieldID, field.TypeUint64),
+			},
+		}
+		for _, k := range nodes {
+			edge.Target.Nodes = append(edge.Target.Nodes, k)
+		}
+		_spec.Edges.Add = append(_spec.Edges.Add, edge)
+	}
+	_node = &Wx{config: wuo.config}
+	_spec.Assign = _node.assignValues
+	_spec.ScanValues = _node.scanValues
+	if err = sqlgraph.UpdateNode(ctx, wuo.driver, _spec); err != nil {
+		if _, ok := err.(*sqlgraph.NotFoundError); ok {
+			err = &NotFoundError{wx.Label}
+		} else if sqlgraph.IsConstraintError(err) {
+			err = &ConstraintError{msg: err.Error(), wrap: err}
+		}
+		return nil, err
+	}
+	wuo.mutation.done = true
+	return _node, nil
+}

+ 64 - 0
etc/wechat.yaml

@@ -0,0 +1,64 @@
+Name: Wechat.api
+Host: 0.0.0.0
+Port: 19101
+Timeout: 30000
+
+Auth:
+  AccessSecret: "jS6VKDtsJf3z1n2VKDtsJf3z1n2"
+  AccessExpire: 259200
+
+CROSConf:
+  Address: '*'
+
+Log:
+  ServiceName: WechatApiLogger
+  Mode: console
+  Path: D:\code\gooki\sa\logs\Wechat\api
+  Level: info
+  Compress: false
+  KeepDays: 7
+  StackCoolDownMillis: 100
+
+DatabaseConf:
+  Type: mysql
+  Host: 127.0.0.1
+  Port: 3306
+  DBName: wechat
+  Username: root
+  Password: p@ssw0rd123456
+  MaxOpenConn: 100
+  SSLMode: disable
+  CacheTime: 5
+
+CoreRpc:
+  # Target: k8s://default/core-rpc-svc:9101
+  Endpoints:
+    - 127.0.0.1:9101
+  Enabled: true
+
+RedisConf:
+  Host: 127.0.0.1:6379
+
+CasbinDatabaseConf:
+  Type: mysql
+  Host: 127.0.0.1
+  Port: 3306
+  DBName: simple_admin
+  Username: root
+  Password: p@ssw0rd123456
+  MaxOpenConn: 100
+  SSLMode: disable
+  CacheTime: 5
+
+CasbinConf:
+  ModelText: |
+    [request_definition]
+    r = sub, obj, act
+    [policy_definition]
+    p = sub, obj, act
+    [role_definition]
+    g = _, _
+    [policy_effect]
+    e = some(where (p.eft == allow))
+    [matchers]
+    m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act

+ 143 - 0
go.mod

@@ -0,0 +1,143 @@
+module wechat-api
+
+go 1.22.1
+
+require (
+	entgo.io/ent v0.13.1
+	github.com/casbin/casbin/v2 v2.85.0
+	github.com/imroc/req/v3 v3.43.1
+	github.com/redis/go-redis/v9 v9.5.1
+	github.com/suyuan32/simple-admin-common v1.3.11
+	github.com/suyuan32/simple-admin-core v1.3.11
+	github.com/zeromicro/go-zero v1.6.3
+)
+
+require (
+	ariga.io/atlas v0.19.2 // indirect
+	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/agext/levenshtein v1.2.3 // indirect
+	github.com/andybalholm/brotli v1.1.0 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/casbin/ent-adapter v0.3.0 // indirect
+	github.com/casbin/govaluate v1.1.1 // indirect
+	github.com/casbin/redis-watcher/v2 v2.5.0 // indirect
+	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/cloudflare/circl v1.3.7 // indirect
+	github.com/coreos/go-semver v0.3.1 // indirect
+	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+	github.com/fatih/color v1.16.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/go-logr/logr v1.4.1 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-openapi/inflect v0.21.0 // indirect
+	github.com/go-openapi/jsonpointer v0.19.6 // indirect
+	github.com/go-openapi/jsonreference v0.20.2 // indirect
+	github.com/go-openapi/swag v0.22.4 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.19.0 // indirect
+	github.com/go-sql-driver/mysql v1.8.0 // indirect
+	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
+	github.com/gofrs/uuid/v5 v5.0.0 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
+	github.com/golang/mock v1.6.0 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/google/gnostic-models v0.6.8 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/gofuzz v1.2.0 // indirect
+	github.com/google/pprof v0.0.0-20240320155624-b11c3daa6f07 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/hcl/v2 v2.20.0 // indirect
+	github.com/jackc/chunkreader/v2 v2.0.1 // indirect
+	github.com/jackc/pgconn v1.14.3 // indirect
+	github.com/jackc/pgio v1.0.0 // indirect
+	github.com/jackc/pgpassfile v1.0.0 // indirect
+	github.com/jackc/pgproto3/v2 v2.3.3 // indirect
+	github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
+	github.com/jackc/pgtype v1.14.2 // indirect
+	github.com/jackc/pgx/v4 v4.18.3 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.17.7 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/lib/pq v1.10.9 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mattn/go-sqlite3 v1.14.22 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect
+	github.com/onsi/ginkgo/v2 v2.17.1 // indirect
+	github.com/openzipkin/zipkin-go v0.4.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.1.1 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/prometheus/client_golang v1.19.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/common v0.48.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/quic-go/qpack v0.4.0 // indirect
+	github.com/quic-go/quic-go v0.42.0 // indirect
+	github.com/refraction-networking/utls v1.6.3 // indirect
+	github.com/spaolacci/murmur3 v1.1.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
+	github.com/zclconf/go-cty v1.14.3 // indirect
+	go.etcd.io/etcd/api/v3 v3.5.12 // indirect
+	go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect
+	go.etcd.io/etcd/client/v3 v3.5.12 // indirect
+	go.opentelemetry.io/otel v1.24.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
+	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
+	go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
+	go.opentelemetry.io/otel/metric v1.24.0 // indirect
+	go.opentelemetry.io/otel/sdk v1.24.0 // indirect
+	go.opentelemetry.io/otel/trace v1.24.0 // indirect
+	go.opentelemetry.io/proto/otlp v1.1.0 // indirect
+	go.uber.org/atomic v1.11.0 // indirect
+	go.uber.org/automaxprocs v1.5.3 // indirect
+	go.uber.org/mock v0.4.0 // indirect
+	go.uber.org/multierr v1.11.0 // indirect
+	go.uber.org/zap v1.24.0 // indirect
+	golang.org/x/crypto v0.21.0 // indirect
+	golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
+	golang.org/x/mod v0.16.0 // indirect
+	golang.org/x/net v0.22.0 // indirect
+	golang.org/x/oauth2 v0.18.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/term v0.18.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/time v0.5.0 // indirect
+	golang.org/x/tools v0.19.0 // indirect
+	google.golang.org/appengine v1.6.8 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
+	google.golang.org/grpc v1.62.1 // indirect
+	google.golang.org/protobuf v1.33.0 // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	k8s.io/api v0.29.3 // indirect
+	k8s.io/apimachinery v0.29.3 // indirect
+	k8s.io/client-go v0.29.3 // indirect
+	k8s.io/klog/v2 v2.110.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
+	k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect
+	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
+	sigs.k8s.io/yaml v1.3.0 // indirect
+)
+
+replace github.com/zeromicro/go-zero v1.6.3 => github.com/suyuan32/simple-admin-tools v1.6.9

+ 837 - 0
go.sum

@@ -0,0 +1,837 @@
+ariga.io/atlas v0.19.2 h1:ulK06d4joEaMP06HNNPxdpD8dFgZGzjzjk+Mb5VfF08=
+ariga.io/atlas v0.19.2/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+entgo.io/ent v0.8.0/go.mod h1:KNjsukat/NJi6zJh1utwRadsbGOZsBbAZNDxkW7tMCc=
+entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
+entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
+github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis/v2 v2.32.1 h1:Bz7CciDnYSaa0mX5xODh6GUITRSx+cVhjNoOR4JssBo=
+github.com/alicebob/miniredis/v2 v2.32.1/go.mod h1:AqkLNAfUm0K07J28hnAyyQKf/x0YkCY/g5DCtuL01Mw=
+github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
+github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
+github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
+github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
+github.com/casbin/casbin/v2 v2.29.2/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
+github.com/casbin/casbin/v2 v2.85.0 h1:VajW9GR/T0fp3SND183gneZGIAdYtl9C7bDYBrqQiGg=
+github.com/casbin/casbin/v2 v2.85.0/go.mod h1:jX8uoN4veP85O/n2674r2qtfSXI6myvxW85f6TH50fw=
+github.com/casbin/ent-adapter v0.3.0 h1:4lkhB/BwXAhj84iSrZG/gQ4avkO4uPwz4kdDP1VEnww=
+github.com/casbin/ent-adapter v0.3.0/go.mod h1:U6saAFuVDEOWLCtrgx35d95M12FC0uh5GtJL82QunRM=
+github.com/casbin/govaluate v1.1.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
+github.com/casbin/govaluate v1.1.1 h1:J1rFKIBhiC5xr0APd5HP6rDL+xt+BRoyq1pa4o2i/5c=
+github.com/casbin/govaluate v1.1.1/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
+github.com/casbin/redis-watcher/v2 v2.5.0 h1:a0922GOKYDSSiD7hEQxmLh/psea2eLZtf1V12XzLI5w=
+github.com/casbin/redis-watcher/v2 v2.5.0/go.mod h1:lgtjnQrfbo+xZIwMPtLu9is/XpnCfAT94SLgMzY7HGk=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
+github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
+github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-bindata/go-bindata v1.0.1-0.20190711162640-ee3c2418e368/go.mod h1:7xCgX1lzlrXPHkfvn3EhumqHkmSlzt8at9q7v0ax19c=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
+github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk=
+github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw=
+github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
+github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-sql-driver/mysql v1.5.1-0.20200311113236-681ffa848bae/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4=
+github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
+github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
+github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
+github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20240320155624-b11c3daa6f07 h1:57oOH2Mu5Nw16KnZAVLdlUjmPH/TSYCKTJgG0OVfX0Y=
+github.com/google/pprof v0.0.0-20240320155624-b11c3daa6f07/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl/v2 v2.20.0 h1:l++cRs/5jQOiKVvqXZm/P1ZEfVXJmvLS9WSVxkaeTb4=
+github.com/hashicorp/hcl/v2 v2.20.0/go.mod h1:WmcD/Ym72MDOOx5F62Ly+leloeu6H7m0pG7VBiU6pQk=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/imroc/req/v3 v3.43.1 h1:tsWAhvxik4egtHAvMlxcjaWJtHlJL8EpBqJMOm5rmyQ=
+github.com/imroc/req/v3 v3.43.1/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
+github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
+github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
+github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
+github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgtype v1.14.2 h1:QBdZQTKpPdBlw2AdKwHEyqUcm/lrl2cwWAHjCMyln/o=
+github.com/jackc/pgtype v1.14.2/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
+github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
+github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+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=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+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=
+github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
+github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
+github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
+github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
+github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
+github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
+github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
+github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
+github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
+github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
+github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgRilRIdHb6fDc=
+github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+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=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/suyuan32/simple-admin-common v1.3.11 h1:9AxqIkyAA2du5uh+BMM38iJhDSXwCzQpN/SH66eKmFg=
+github.com/suyuan32/simple-admin-common v1.3.11/go.mod h1:ZKNZ/S/pIqs6E2NRHngDhdDvx9s2n10+7F/AnpFw4AQ=
+github.com/suyuan32/simple-admin-core v1.3.11 h1:FeIHNvS9WnHm4CMWuxxhjTrt4nSyYz1PEsjMq94TOnw=
+github.com/suyuan32/simple-admin-core v1.3.11/go.mod h1:prymrTp+RjbqoH87HfXHOUrG5nu9lyFg6eNoy9hayLo=
+github.com/suyuan32/simple-admin-tools v1.6.9 h1:wEHV1YeEXdyKIh5MHT73NxQaNGKZo4eLzzK2bg7Zvho=
+github.com/suyuan32/simple-admin-tools v1.6.9/go.mod h1:RtX0cyNWNEd5mquIpl4azH5dUp790bYVmLIzxELS5Pw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
+github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
+github.com/zclconf/go-cty v1.14.3 h1:1JXy1XroaGrzZuG6X9dt7HL6s9AwbY+l4UNL8o5B6ho=
+github.com/zclconf/go-cty v1.14.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
+go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
+go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg=
+go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
+go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
+go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
+go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
+go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
+golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
+golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
+golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
+golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
+google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
+gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
+k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
+k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
+k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=
+k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
+k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
+k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
+k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
+k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY=
+k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

+ 18 - 0
hook/contact.go

@@ -0,0 +1,18 @@
+package hook
+
+import "fmt"
+
+// 获取好友和群信息
+func (h *Hook) GetFriendAndChatRoomList(typeStr string) (result GetFriendAndChatRoomListReap, err error) {
+	resp, err := h.Client.R().SetBody(&GetFriendAndChatRoomListReq{
+		Type: typeStr,
+	}).SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/GetFriendAndChatRoomList")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("GetFriendAndChatRoomList failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}

+ 43 - 0
hook/init.go

@@ -0,0 +1,43 @@
+package hook
+
+import (
+	"github.com/imroc/req/v3"
+	"time"
+)
+
+type Hook struct {
+	ServerIp  string
+	AdminPort string
+	WxPort    string
+	Client    *req.Client
+}
+
+func NewHook(serverIp string, adminPort string, WxPort string) *Hook {
+
+	client := req.C().DevMode()
+	client.SetCommonRetryCount(2).
+		SetCommonRetryBackoffInterval(1*time.Second, 5*time.Second).
+		SetCommonRetryFixedInterval(2 * time.Second).SetTimeout(30 * time.Second)
+
+	return &Hook{
+		ServerIp:  serverIp,
+		AdminPort: adminPort,
+		WxPort:    WxPort,
+		Client:    req.C().DevMode(),
+	}
+}
+
+func (h *Hook) setServerIp(ip string) *Hook {
+	h.ServerIp = ip
+	return h
+}
+
+func (h *Hook) setAdminPort(port string) *Hook {
+	h.AdminPort = port
+	return h
+}
+
+func (h *Hook) setWxPort(port string) *Hook {
+	h.WxPort = port
+	return h
+}

+ 19 - 0
hook/message.go

@@ -0,0 +1,19 @@
+package hook
+
+import "fmt"
+
+// 开启/关闭实时消息接收功能
+func (h *Hook) ConfigureMsgRecive(isEnable string, url string) (err error) {
+	resp, err := h.Client.R().SetBody(&ConfigureMsgReciveReq{
+		IsEnable: isEnable,
+		URL:      url,
+	}).Post("http://" + h.ServerIp + ":" + h.WxPort + "/ConfigureMsgRecive")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("ConfigureMsgRecive failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}

+ 114 - 0
hook/sys.go

@@ -0,0 +1,114 @@
+package hook
+
+import (
+	"fmt"
+)
+
+// 退出登陆
+func (h *Hook) Logout() (result LogoutResp, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/Logout")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("Logout failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 获取微信总数
+func (h *Hook) GetWeChatProcessNumber() (result GetWeChatProcessNumberResp, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.AdminPort + "/Get_WeChatProcessNumber")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("GetWeChatProcessNumber failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 点击登陆微信按钮
+func (h *Hook) ClickLoginButton() (result ClickLoginButtonResp, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/ClickLoginButton")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("ClickLoginButton failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 启动微信
+func (h *Hook) StartWechat(port string) (result StartWechatResp, err error) {
+	resp, err := h.Client.R().SetBody(&StartWechatReq{
+		StartPort: port,
+	}).SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.AdminPort + "/StartWechat")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("StartWechat failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 获取进程端口占用信息
+func (h *Hook) GetPortOccupiedInfo(port string) (result GetPortOccupiedInfoResp, err error) {
+	resp, err := h.Client.R().SetBody(&GetPortOccupiedInfoReq{
+		CheckPort: port,
+	}).SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.AdminPort + "/Get_PortOccupiedInfo")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("GetPortOccupiedInfo failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 刷新登陆二维码
+func (h *Hook) RefreshLoginQRCode() (err error) {
+	resp, err := h.Client.R().Post("http://" + h.ServerIp + ":" + h.WxPort + "/RefreshLoginQRCode")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("RefreshLoginQRCode failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 获取登陆二维码
+func (h *Hook) GetLoginQRCode() (result GetLoginQRCodeReap, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/GetLoginQRCode")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("GetLoginQRCode failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}
+
+// 查询登录状态
+func (h *Hook) IsLoginStatus() (result IsLoginStatusResp, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/IsLoginStatus")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("IsLoginStatus failed with status code %d", resp.StatusCode)
+		return
+	}
+
+	return
+}

+ 107 - 0
hook/type.go

@@ -0,0 +1,107 @@
+package hook
+
+type GetFriendAndChatRoomListReq struct {
+	Type string `json:"type"`
+}
+
+type GetFriendAndChatRoomListReap struct {
+	CountFriend string `json:"count_friend"`
+	Friend      []struct {
+		Index     string `json:"index"`
+		Wxid      string `json:"wxid"`
+		Account   string `json:"account"`
+		Nickname  string `json:"nickname"`
+		V3        string `json:"v3"`
+		Markname  string `json:"markname"`
+		Starrole  string `json:"starrole"`
+		Dontseeit string `json:"dontseeit"`
+		Dontseeme string `json:"dontseeme"`
+		Headimg   string `json:"headimg"`
+		Sex       string `json:"sex"`
+		Lag       string `json:"lag"`
+	} `json:"friend"`
+	CountChatroom string `json:"count_chatroom"`
+	Chatroom      []struct {
+		Index    string `json:"index"`
+		Gid      string `json:"gid"`
+		Gname    string `json:"gname"`
+		Markname string `json:"markname"`
+		V3       string `json:"v3"`
+	} `json:"chatroom"`
+	CountGh string `json:"count_gh"`
+	Gh      []struct {
+		Index    string `json:"index"`
+		Wxid     string `json:"wxid"`
+		Account  string `json:"account"`
+		Nickname string `json:"nickname"`
+		Markname string `json:"markname"`
+		V3       string `json:"v3"`
+	} `json:"gh"`
+}
+
+type ConfigureMsgReciveReq struct {
+	IsEnable string `json:"isEnable"`
+	URL      string `json:"url"`
+}
+
+type GetSelfLoginInfoResp struct {
+	ProcessID string `json:"ProcessID"`
+	Wxid      string `json:"wxid"`
+	Account   string `json:"account"`
+	Nickname  string `json:"nickname"`
+	Tel       string `json:"tel"`
+	Country   string `json:"country"`
+	Province  string `json:"province"`
+	City      string `json:"city"`
+	HeadBig   string `json:"head_big"`
+	DiySign   string `json:"diy_sign"`
+}
+
+type LogoutResp struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+}
+
+type GetWeChatProcessNumberResp struct {
+	TotalNum string `json:"total_num"`
+	List     []struct {
+		Index       int    `json:"Index"`
+		ProcessName string `json:"ProcessName"`
+		PID         int    `json:"PID"`
+		Par         string `json:"Par"`
+		Port        int    `json:"Port"`
+	} `json:"List"`
+}
+
+type GetLoginQRCodeReap struct {
+	Base64 string `json:"base64"`
+}
+
+type IsLoginStatusResp struct {
+	Onlinestatus string `json:"onlinestatus"`
+	Msg          string `json:"msg"`
+	LoginLoading string `json:"login_loading"`
+	Selfwxid     string `json:"selfwxid"`
+	Nickname     string `json:"nickname"`
+}
+
+type GetPortOccupiedInfoReq struct {
+	CheckPort string `json:"CheckPort"`
+}
+
+type GetPortOccupiedInfoResp struct {
+	Occupied string `json:"Occupied"`
+}
+
+type StartWechatReq struct {
+	StartPort string `json:"StartPort"`
+}
+
+type StartWechatResp struct {
+	StartPort string `json:"StartPort"`
+	Success   string `json:"success"`
+}
+
+type ClickLoginButtonResp struct {
+	ClickLoginButton string `json:"ClickLoginButton"`
+}

+ 16 - 0
hook/user.go

@@ -0,0 +1,16 @@
+package hook
+
+import "fmt"
+
+// 获取个人详细信息
+func (h *Hook) GetSelfLoginInfo() (result GetSelfLoginInfoResp, err error) {
+	resp, err := h.Client.R().SetSuccessResult(&result).Post("http://" + h.ServerIp + ":" + h.WxPort + "/GetSelfLoginInfo")
+	if err != nil {
+		return
+	}
+	if !resp.IsSuccessState() {
+		err = fmt.Errorf("GetPersonalInfo failed with status code %d", resp.StatusCode)
+		return
+	}
+	return
+}

+ 19 - 0
internal/config/config.go

@@ -0,0 +1,19 @@
+package config
+
+import (
+	"github.com/suyuan32/simple-admin-common/config"
+	"github.com/suyuan32/simple-admin-common/plugins/casbin"
+	"github.com/zeromicro/go-zero/rest"
+	"github.com/zeromicro/go-zero/zrpc"
+)
+
+type Config struct {
+	rest.RestConf
+	Auth               rest.AuthConf
+	CROSConf           config.CROSConf
+	CasbinDatabaseConf config.DatabaseConf
+	RedisConf          config.RedisConf
+	CasbinConf         casbin.CasbinConf
+	DatabaseConf       config.DatabaseConf
+	CoreRpc            zrpc.RpcClientConf
+}

+ 44 - 0
internal/handler/Contact/create_contact_handler.go

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

+ 44 - 0
internal/handler/Contact/delete_contact_handler.go

@@ -0,0 +1,44 @@
+package Contact
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /contact/delete Contact DeleteContact
+//
+// Delete contact information | 删除Contact信息
+//
+// Delete contact information | 删除Contact信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteContactHandler(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 := Contact.NewDeleteContactLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteContact(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Contact/get_contact_by_id_handler.go

@@ -0,0 +1,44 @@
+package Contact
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Contact"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /contact Contact GetContactById
+//
+// Get contact by ID | 通过ID获取Contact
+//
+// Get contact by ID | 通过ID获取Contact
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: ContactInfoResp
+
+func GetContactByIdHandler(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 := Contact.NewGetContactByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetContactById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Contact/get_contact_list_handler.go

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

+ 44 - 0
internal/handler/Contact/update_contact_handler.go

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

+ 44 - 0
internal/handler/WechatServer/create_server_handler.go

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

+ 44 - 0
internal/handler/WechatServer/delete_server_handler.go

@@ -0,0 +1,44 @@
+package WechatServer
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/WechatServer"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /server/delete WechatServer DeleteServer
+//
+// Delete server information | 删除Server信息
+//
+// Delete server information | 删除Server信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteServerHandler(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 := WechatServer.NewDeleteServerLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteServer(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/WechatServer/get_server_by_id_handler.go

@@ -0,0 +1,44 @@
+package WechatServer
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/WechatServer"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /server WechatServer GetServerById
+//
+// Get server by ID | 通过ID获取Server
+//
+// Get server by ID | 通过ID获取Server
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: ServerInfoResp
+
+func GetServerByIdHandler(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 := WechatServer.NewGetServerByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetServerById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/WechatServer/get_server_list_handler.go

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

+ 44 - 0
internal/handler/WechatServer/update_server_handler.go

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

+ 44 - 0
internal/handler/Wx/create_wx_handler.go

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

+ 44 - 0
internal/handler/Wx/delete_wx_handler.go

@@ -0,0 +1,44 @@
+package Wx
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wx"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wx/delete Wx DeleteWx
+//
+// Delete wx information | 删除Wx信息
+//
+// Delete wx information | 删除Wx信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDsReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func DeleteWxHandler(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 := Wx.NewDeleteWxLogic(r.Context(), svcCtx)
+		resp, err := l.DeleteWx(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Wx/get_wx_by_id_handler.go

@@ -0,0 +1,44 @@
+package Wx
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wx"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wx Wx GetWxById
+//
+// Get wx by ID | 通过ID获取Wx
+//
+// Get wx by ID | 通过ID获取Wx
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: WxInfoResp
+
+func GetWxByIdHandler(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 := Wx.NewGetWxByIdLogic(r.Context(), svcCtx)
+		resp, err := l.GetWxById(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Wx/get_wx_list_handler.go

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

+ 44 - 0
internal/handler/Wx/refresh_login_q_r_handler.go

@@ -0,0 +1,44 @@
+package Wx
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wx"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wx/refreshLoginQR Wx RefreshLoginQR
+//
+// Refresh login QR code | 刷新登陆二维码
+//
+// Refresh login QR code | 刷新登陆二维码
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: RefreshLoginQRReq
+//
+// Responses:
+//  200: RefreshLoginQRResp
+
+func RefreshLoginQRHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.RefreshLoginQRReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := Wx.NewRefreshLoginQRLogic(r.Context(), svcCtx)
+		resp, err := l.RefreshLoginQR(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Wx/update_wx_handler.go

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

+ 44 - 0
internal/handler/Wxhook/get_friends_and_groups_handler.go

@@ -0,0 +1,44 @@
+package Wxhook
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wxhook"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wxhook/getFriendsAndGroups Wxhook GetFriendsAndGroups
+//
+// 获取好友和群信息
+//
+// 获取好友和群信息
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func GetFriendsAndGroupsHandler(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 := Wxhook.NewGetFriendsAndGroupsLogic(r.Context(), svcCtx)
+		resp, err := l.GetFriendsAndGroups(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Wxhook/logout_handler.go

@@ -0,0 +1,44 @@
+package Wxhook
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wxhook"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wxhook/logout Wxhook Logout
+//
+// 退出登陆
+//
+// 退出登陆
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: IDReq
+//
+// Responses:
+//  200: BaseMsgResp
+
+func LogoutHandler(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 := Wxhook.NewLogoutLogic(r.Context(), svcCtx)
+		resp, err := l.Logout(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 44 - 0
internal/handler/Wxhook/refresh_login_q_r_handler.go

@@ -0,0 +1,44 @@
+package Wxhook
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/Wxhook"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /wxhook/refreshLoginQR Wxhook RefreshLoginQR
+//
+// Refresh login QR code | 刷新登陆二维码
+//
+// Refresh login QR code | 刷新登陆二维码
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: RefreshLoginQRReq
+//
+// Responses:
+//  200: RefreshLoginQRResp
+
+func RefreshLoginQRHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.RefreshLoginQRReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := Wxhook.NewRefreshLoginQRLogic(r.Context(), svcCtx)
+		resp, err := l.RefreshLoginQR(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 31 - 0
internal/handler/base/init_database_handler.go

@@ -0,0 +1,31 @@
+package base
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/base"
+	"wechat-api/internal/svc"
+)
+
+// swagger:route get /init/database base InitDatabase
+//
+// Initialize database | 初始化数据库
+//
+// Initialize database | 初始化数据库
+//
+// Responses:
+//  200: BaseMsgResp
+
+func InitDatabaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		l := base.NewInitDatabaseLogic(r.Context(), svcCtx)
+		resp, err := l.InitDatabase()
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 153 - 0
internal/handler/routes.go

@@ -0,0 +1,153 @@
+// Code generated by goctl. DO NOT EDIT.
+package handler
+
+import (
+	"net/http"
+
+	Contact "wechat-api/internal/handler/Contact"
+	WechatServer "wechat-api/internal/handler/WechatServer"
+	Wx "wechat-api/internal/handler/Wx"
+	Wxhook "wechat-api/internal/handler/Wxhook"
+	base "wechat-api/internal/handler/base"
+	"wechat-api/internal/svc"
+
+	"github.com/zeromicro/go-zero/rest"
+)
+
+func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
+	server.AddRoutes(
+		[]rest.Route{
+			{
+				Method:  http.MethodGet,
+				Path:    "/init/database",
+				Handler: base.InitDatabaseHandler(serverCtx),
+			},
+		},
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/server/create",
+					Handler: WechatServer.CreateServerHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/server/update",
+					Handler: WechatServer.UpdateServerHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/server/delete",
+					Handler: WechatServer.DeleteServerHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/server/list",
+					Handler: WechatServer.GetServerListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/server",
+					Handler: WechatServer.GetServerByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/wx/create",
+					Handler: Wx.CreateWxHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wx/update",
+					Handler: Wx.UpdateWxHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wx/delete",
+					Handler: Wx.DeleteWxHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wx/list",
+					Handler: Wx.GetWxListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wx",
+					Handler: Wx.GetWxByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/wxhook/refreshLoginQR",
+					Handler: Wxhook.RefreshLoginQRHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wxhook/logout",
+					Handler: Wxhook.LogoutHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/wxhook/getFriendsAndGroups",
+					Handler: Wxhook.GetFriendsAndGroupsHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+
+	server.AddRoutes(
+		rest.WithMiddlewares(
+			[]rest.Middleware{serverCtx.Authority},
+			[]rest.Route{
+				{
+					Method:  http.MethodPost,
+					Path:    "/contact/create",
+					Handler: Contact.CreateContactHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/contact/update",
+					Handler: Contact.UpdateContactHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/contact/delete",
+					Handler: Contact.DeleteContactHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/contact/list",
+					Handler: Contact.GetContactListHandler(serverCtx),
+				},
+				{
+					Method:  http.MethodPost,
+					Path:    "/contact",
+					Handler: Contact.GetContactByIdHandler(serverCtx),
+				},
+			}...,
+		),
+		rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
+	)
+}

+ 54 - 0
internal/logic/Contact/create_contact_logic.go

@@ -0,0 +1,54 @@
+package Contact
+
+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 CreateContactLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateContactLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateContactLogic {
+	return &CreateContactLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateContactLogic) CreateContact(req *types.ContactInfo) (*types.BaseMsgResp, error) {
+    _, err := l.svcCtx.DB.Contact.Create().
+			SetNotNilStatus(req.Status).
+			SetNotNilWxWxid(req.WxWxid).
+			SetNotNilType(req.Type).
+			SetNotNilWxid(req.Wxid).
+			SetNotNilAccount(req.Account).
+			SetNotNilNickname(req.Nickname).
+			SetNotNilMarkname(req.Markname).
+			SetNotNilHeadimg(req.Headimg).
+			SetNotNilSex(req.Sex).
+			SetNotNilStarrole(req.Starrole).
+			SetNotNilDontseeit(req.Dontseeit).
+			SetNotNilDontseeme(req.Dontseeme).
+			SetNotNilLag(req.Lag).
+			SetNotNilGid(req.Gid).
+			SetNotNilGname(req.Gname).
+			SetNotNilV3(req.V3).
+			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/Contact/delete_contact_logic.go

@@ -0,0 +1,37 @@
+package Contact
+
+import (
+	"context"
+
+    "wechat-api/ent/contact"
+    "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 DeleteContactLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteContactLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteContactLogic {
+	return &DeleteContactLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteContactLogic) DeleteContact(req *types.IDsReq) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.Contact.Delete().Where(contact.IDIn(req.Ids...)).Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 66 - 0
internal/logic/Contact/get_contact_by_id_logic.go

@@ -0,0 +1,66 @@
+package Contact
+
+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 GetContactByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetContactByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetContactByIdLogic {
+	return &GetContactByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetContactByIdLogic) GetContactById(req *types.IDReq) (*types.ContactInfoResp, error) {
+	data, err := l.svcCtx.DB.Contact.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.ContactInfoResp{
+	    BaseDataInfo: types.BaseDataInfo{
+            Code: 0,
+            Msg:  errormsg.Success,
+        },
+        Data: types.ContactInfo{
+            BaseIDInfo:    types.BaseIDInfo{
+				Id:          &data.ID,
+				CreatedAt:    pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+            },
+			Status:	&data.Status,
+			WxWxid:	&data.WxWxid,
+			Type:	&data.Type,
+			Wxid:	&data.Wxid,
+			Account:	&data.Account,
+			Nickname:	&data.Nickname,
+			Markname:	&data.Markname,
+			Headimg:	&data.Headimg,
+			Sex:	&data.Sex,
+			Starrole:	&data.Starrole,
+			Dontseeit:	&data.Dontseeit,
+			Dontseeme:	&data.Dontseeme,
+			Lag:	&data.Lag,
+			Gid:	&data.Gid,
+			Gname:	&data.Gname,
+			V3:	&data.V3,
+        },
+	}, nil
+}
+

+ 81 - 0
internal/logic/Contact/get_contact_list_logic.go

@@ -0,0 +1,81 @@
+package Contact
+
+import (
+	"context"
+
+	"wechat-api/ent/contact"
+	"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 GetContactListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetContactListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetContactListLogic {
+	return &GetContactListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetContactListLogic) GetContactList(req *types.ContactListReq) (*types.ContactListResp, error) {
+	var predicates []predicate.Contact
+	if req.WxWxid != nil {
+		predicates = append(predicates, contact.WxWxidContains(*req.WxWxid))
+	}
+	if req.Wxid != nil {
+		predicates = append(predicates, contact.WxidContains(*req.Wxid))
+	}
+	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)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.ContactListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		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,
+		})
+	}
+
+	return resp, nil
+}

+ 54 - 0
internal/logic/Contact/update_contact_logic.go

@@ -0,0 +1,54 @@
+package Contact
+
+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 UpdateContactLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateContactLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateContactLogic {
+	return &UpdateContactLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateContactLogic) UpdateContact(req *types.ContactInfo) (*types.BaseMsgResp, error) {
+    err := l.svcCtx.DB.Contact.UpdateOneID(*req.Id).
+			SetNotNilStatus(req.Status).
+			SetNotNilWxWxid(req.WxWxid).
+			SetNotNilType(req.Type).
+			SetNotNilWxid(req.Wxid).
+			SetNotNilAccount(req.Account).
+			SetNotNilNickname(req.Nickname).
+			SetNotNilMarkname(req.Markname).
+			SetNotNilHeadimg(req.Headimg).
+			SetNotNilSex(req.Sex).
+			SetNotNilStarrole(req.Starrole).
+			SetNotNilDontseeit(req.Dontseeit).
+			SetNotNilDontseeme(req.Dontseeme).
+			SetNotNilLag(req.Lag).
+			SetNotNilGid(req.Gid).
+			SetNotNilGname(req.Gname).
+			SetNotNilV3(req.V3).
+			Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 43 - 0
internal/logic/WechatServer/create_server_logic.go

@@ -0,0 +1,43 @@
+package WechatServer
+
+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 CreateServerLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateServerLogic {
+	return &CreateServerLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateServerLogic) CreateServer(req *types.ServerInfo) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.Server.Create().
+		SetNotNilStatus(req.Status).
+		SetNotNilName(req.Name).
+		SetNotNilPublicIP(req.PublicIp).
+		SetNotNilPrivateIP(req.PrivateIp).
+		SetNotNilAdminPort(req.AdminPort).
+		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/WechatServer/delete_server_logic.go

@@ -0,0 +1,37 @@
+package WechatServer
+
+import (
+	"context"
+
+	"wechat-api/ent/server"
+	"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 DeleteServerLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteServerLogic {
+	return &DeleteServerLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteServerLogic) DeleteServer(req *types.IDsReq) (*types.BaseMsgResp, error) {
+	_, err := l.svcCtx.DB.Server.Delete().Where(server.IDIn(req.Ids...)).Exec(l.ctx)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 54 - 0
internal/logic/WechatServer/get_server_by_id_logic.go

@@ -0,0 +1,54 @@
+package WechatServer
+
+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 GetServerByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetServerByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetServerByIdLogic {
+	return &GetServerByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetServerByIdLogic) GetServerById(req *types.IDReq) (*types.ServerInfoResp, error) {
+	data, err := l.svcCtx.DB.Server.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.ServerInfoResp{
+		BaseDataInfo: types.BaseDataInfo{
+			Code: 0,
+			Msg:  errormsg.Success,
+		},
+		Data: types.ServerInfo{
+			BaseIDInfo: types.BaseIDInfo{
+				Id:        &data.ID,
+				CreatedAt: pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt: pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+			},
+			Status:    &data.Status,
+			Name:      &data.Name,
+			PublicIp:  &data.PublicIP,
+			PrivateIp: &data.PrivateIP,
+			AdminPort: &data.AdminPort,
+		},
+	}, nil
+}

+ 70 - 0
internal/logic/WechatServer/get_server_list_logic.go

@@ -0,0 +1,70 @@
+package WechatServer
+
+import (
+	"context"
+
+	"wechat-api/ent/predicate"
+	"wechat-api/ent/server"
+	"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 GetServerListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetServerListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetServerListLogic {
+	return &GetServerListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetServerListLogic) GetServerList(req *types.ServerListReq) (*types.ServerListResp, error) {
+	var predicates []predicate.Server
+	if req.Name != nil {
+		predicates = append(predicates, server.NameContains(*req.Name))
+	}
+	if req.PublicIp != nil {
+		predicates = append(predicates, server.PublicIPContains(*req.PublicIp))
+	}
+	if req.PrivateIp != nil {
+		predicates = append(predicates, server.PrivateIPContains(*req.PrivateIp))
+	}
+	data, err := l.svcCtx.DB.Server.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.ServerListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		resp.Data.Data = append(resp.Data.Data,
+			types.ServerInfo{
+				BaseIDInfo: types.BaseIDInfo{
+					Id:        &v.ID,
+					CreatedAt: pointy.GetPointer(v.CreatedAt.UnixMilli()),
+					UpdatedAt: pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+				},
+				Status:    &v.Status,
+				Name:      &v.Name,
+				PublicIp:  &v.PublicIP,
+				PrivateIp: &v.PrivateIP,
+				AdminPort: &v.AdminPort,
+			})
+	}
+
+	return resp, nil
+}

+ 42 - 0
internal/logic/WechatServer/update_server_logic.go

@@ -0,0 +1,42 @@
+package WechatServer
+
+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 UpdateServerLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateServerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateServerLogic {
+	return &UpdateServerLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateServerLogic) UpdateServer(req *types.ServerInfo) (*types.BaseMsgResp, error) {
+	err := l.svcCtx.DB.Server.UpdateOneID(*req.Id).
+		SetNotNilStatus(req.Status).
+		SetNotNilName(req.Name).
+		SetNotNilPublicIP(req.PublicIp).
+		SetNotNilPrivateIP(req.PrivateIp).
+		SetNotNilAdminPort(req.AdminPort).
+		Exec(l.ctx)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 111 - 0
internal/logic/Wx/create_wx_logic.go

@@ -0,0 +1,111 @@
+package Wx
+
+import (
+	"context"
+	"github.com/zeromicro/go-zero/core/errorx"
+	"wechat-api/ent"
+	"wechat-api/ent/wx"
+	"wechat-api/hook"
+	"wechat-api/internal/utils/dberrorhandler"
+
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type CreateWxLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewCreateWxLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateWxLogic {
+	return &CreateWxLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *CreateWxLogic) CreateWx(req *types.WxInfo) (*types.BaseMsgResp, error) {
+
+	server, err := l.svcCtx.DB.Server.Get(l.ctx, *req.ServerId)
+	if err != nil {
+		l.Error("获取服务器信息失败", err)
+		return nil, err
+	}
+
+	hook := hook.NewHook(server.PrivateIP, server.AdminPort, *req.Port)
+
+	portOccupied, err := hook.GetPortOccupiedInfo(*req.Port)
+	if err != nil {
+		l.Error("获取端口占用信息失败", err)
+		return nil, err
+	}
+
+	if portOccupied.Occupied != "1" {
+		l.Error("端口未使用,请重新扫码登陆", err)
+		return nil, err
+	}
+
+	loginStatus, err := hook.IsLoginStatus()
+	if err != nil {
+		return nil, err
+	}
+
+	if loginStatus.Onlinestatus == "3" {
+		selfInfo, err := hook.GetSelfLoginInfo()
+		if err != nil {
+			return nil, err
+		}
+
+		wxInfo, err := l.svcCtx.DB.Wx.Query().Where(wx.ServerIDEQ(server.ID)).Where(wx.PortEQ(*req.Port)).Limit(1).Only(l.ctx)
+		if err != nil && !ent.IsNotFound(err) {
+			l.Error("查询微信信息失败", err)
+			return nil, err
+		}
+
+		var dbErr error
+		if ent.IsNotFound(err) {
+			if req.Callback != nil && *req.Callback != "" {
+				_ = hook.ConfigureMsgRecive("1", *req.Callback)
+			}
+			_, dbErr = l.svcCtx.DB.Wx.Create().
+				SetNotNilServerID(req.ServerId).
+				SetNotNilPort(req.Port).
+				SetNotNilProcessID(&selfInfo.ProcessID).
+				SetNotNilCallback(req.Callback).
+				SetNotNilWxid(&selfInfo.Wxid).
+				SetNotNilAccount(&selfInfo.Account).
+				SetNotNilNickname(&selfInfo.Nickname).
+				SetNotNilTel(&selfInfo.Tel).
+				SetNotNilHeadBig(&selfInfo.HeadBig).
+				SetStatus(1).
+				Save(l.ctx)
+		} else {
+			if req.Callback != nil && *req.Callback != "" && wxInfo.Callback != *req.Callback {
+				_ = hook.ConfigureMsgRecive("1", *req.Callback)
+			}
+			_, dbErr = l.svcCtx.DB.Wx.UpdateOneID(wxInfo.ID).
+				SetNotNilProcessID(&selfInfo.ProcessID).
+				SetNotNilCallback(req.Callback).
+				SetNotNilWxid(&selfInfo.Wxid).
+				SetNotNilAccount(&selfInfo.Account).
+				SetNotNilNickname(&selfInfo.Nickname).
+				SetNotNilTel(&selfInfo.Tel).
+				SetNotNilHeadBig(&selfInfo.HeadBig).
+				SetStatus(1).
+				Save(l.ctx)
+		}
+		if dbErr != nil {
+			return nil, dberrorhandler.DefaultEntError(l.Logger, dbErr, req)
+		}
+	} else {
+		l.Error("微信未登录", "loginStatus", loginStatus)
+		return nil, errorx.NewDefaultError("微信未登陆,当前登陆状态:" + loginStatus.Onlinestatus + "," + loginStatus.Msg)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.Success}, nil
+}

+ 38 - 0
internal/logic/Wx/delete_wx_logic.go

@@ -0,0 +1,38 @@
+package Wx
+
+import (
+	"context"
+
+	"wechat-api/ent/wx"
+	"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 DeleteWxLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewDeleteWxLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteWxLogic {
+	return &DeleteWxLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *DeleteWxLogic) DeleteWx(req *types.IDsReq) (*types.BaseMsgResp, error) {
+
+	_, err := l.svcCtx.DB.Wx.Delete().Where(wx.IDIn(req.Ids...)).Exec(l.ctx)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.BaseMsgResp{Msg: errormsg.DeleteSuccess}, nil
+}

+ 60 - 0
internal/logic/Wx/get_wx_by_id_logic.go

@@ -0,0 +1,60 @@
+package Wx
+
+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 GetWxByIdLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetWxByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWxByIdLogic {
+	return &GetWxByIdLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetWxByIdLogic) GetWxById(req *types.IDReq) (*types.WxInfoResp, error) {
+	data, err := l.svcCtx.DB.Wx.Get(l.ctx, req.Id)
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	return &types.WxInfoResp{
+	    BaseDataInfo: types.BaseDataInfo{
+            Code: 0,
+            Msg:  errormsg.Success,
+        },
+        Data: types.WxInfo{
+            BaseIDInfo:    types.BaseIDInfo{
+				Id:          &data.ID,
+				CreatedAt:    pointy.GetPointer(data.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(data.UpdatedAt.UnixMilli()),
+            },
+			Status:	&data.Status,
+			ServerId:	&data.ServerID,
+			Port:	&data.Port,
+			ProcessId:	&data.ProcessID,
+			Callback:	&data.Callback,
+			Wxid:	&data.Wxid,
+			Account:	&data.Account,
+			Nickname:	&data.Nickname,
+			Tel:	&data.Tel,
+			HeadBig:	&data.HeadBig,
+        },
+	}, nil
+}
+

+ 75 - 0
internal/logic/Wx/get_wx_list_logic.go

@@ -0,0 +1,75 @@
+package Wx
+
+import (
+	"context"
+
+	"wechat-api/ent/wx"
+	"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 GetWxListLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewGetWxListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWxListLogic {
+	return &GetWxListLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *GetWxListLogic) GetWxList(req *types.WxListReq) (*types.WxListResp, error) {
+	var predicates []predicate.Wx
+	if req.Port != nil {
+		predicates = append(predicates, wx.PortContains(*req.Port))
+	}
+	if req.ProcessId != nil {
+		predicates = append(predicates, wx.ProcessIDContains(*req.ProcessId))
+	}
+	if req.Callback != nil {
+		predicates = append(predicates, wx.CallbackContains(*req.Callback))
+	}
+	data, err := l.svcCtx.DB.Wx.Query().Where(predicates...).Page(l.ctx, req.Page, req.PageSize)
+
+	if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+	resp := &types.WxListResp{}
+	resp.Msg = errormsg.Success
+	resp.Data.Total = data.PageDetails.Total
+
+	for _, v := range data.List {
+		resp.Data.Data = append(resp.Data.Data,
+		types.WxInfo{
+			BaseIDInfo:    types.BaseIDInfo{
+				Id:          &v.ID,
+				CreatedAt:    pointy.GetPointer(v.CreatedAt.UnixMilli()),
+				UpdatedAt:    pointy.GetPointer(v.UpdatedAt.UnixMilli()),
+            },
+			Status:	&v.Status,
+			ServerId:	&v.ServerID,
+			Port:	&v.Port,
+			ProcessId:	&v.ProcessID,
+			Callback:	&v.Callback,
+			Wxid:	&v.Wxid,
+			Account:	&v.Account,
+			Nickname:	&v.Nickname,
+			Tel:	&v.Tel,
+			HeadBig:	&v.HeadBig,
+		})
+	}
+
+	return resp, nil
+}

+ 29 - 0
internal/logic/Wx/refresh_login_q_r_logic.go

@@ -0,0 +1,29 @@
+package Wx
+
+import (
+	"context"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type RefreshLoginQRLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewRefreshLoginQRLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RefreshLoginQRLogic {
+	return &RefreshLoginQRLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *RefreshLoginQRLogic) RefreshLoginQR(req *types.RefreshLoginQRReq) (resp *types.RefreshLoginQRResp, err error) {
+	// todo: add your logic here and delete this line
+
+	return
+}

+ 48 - 0
internal/logic/Wx/update_wx_logic.go

@@ -0,0 +1,48 @@
+package Wx
+
+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 UpdateWxLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewUpdateWxLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateWxLogic {
+	return &UpdateWxLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+func (l *UpdateWxLogic) UpdateWx(req *types.WxInfo) (*types.BaseMsgResp, error) {
+    err := l.svcCtx.DB.Wx.UpdateOneID(*req.Id).
+			SetNotNilStatus(req.Status).
+			SetNotNilServerID(req.ServerId).
+			SetNotNilPort(req.Port).
+			SetNotNilProcessID(req.ProcessId).
+			SetNotNilCallback(req.Callback).
+			SetNotNilWxid(req.Wxid).
+			SetNotNilAccount(req.Account).
+			SetNotNilNickname(req.Nickname).
+			SetNotNilTel(req.Tel).
+			SetNotNilHeadBig(req.HeadBig).
+			Exec(l.ctx)
+
+    if err != nil {
+		return nil, dberrorhandler.DefaultEntError(l.Logger, err, req)
+	}
+
+    return &types.BaseMsgResp{Msg: errormsg.UpdateSuccess}, nil
+}

+ 115 - 0
internal/logic/Wxhook/get_friends_and_groups_logic.go

@@ -0,0 +1,115 @@
+package Wxhook
+
+import (
+	"context"
+	"github.com/spf13/cast"
+	"github.com/suyuan32/simple-admin-common/enum/errorcode"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"wechat-api/hook"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GetFriendsAndGroupsLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewGetFriendsAndGroupsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFriendsAndGroupsLogic {
+	return &GetFriendsAndGroupsLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *GetFriendsAndGroupsLogic) GetFriendsAndGroups(req *types.IDReq) (resp *types.BaseMsgResp, err error) {
+
+	wxInfo, err := l.svcCtx.DB.Wx.Get(l.ctx, req.Id)
+	if err != nil {
+		l.Error("查询微信信息失败", err)
+		return
+	}
+
+	serverInfo, err := l.svcCtx.DB.Server.Get(l.ctx, wxInfo.ServerID)
+	if err != nil {
+		l.Error("查询服务器信息失败", err)
+		return
+	}
+
+	hookClient := hook.NewHook(serverInfo.PrivateIP, serverInfo.AdminPort, wxInfo.Port)
+
+	friendAndChatRoomList, err := hookClient.GetFriendAndChatRoomList("0")
+
+	if err != nil {
+		l.Error("获取好友列表失败", err)
+		return
+	}
+
+	friendCnt := cast.ToInt(friendAndChatRoomList.CountFriend)
+	if friendCnt > 0 {
+		for _, friend := range friendAndChatRoomList.Friend {
+			l.svcCtx.DB.Contact.Create().
+				SetWxWxid(wxInfo.Wxid).
+				SetType(1).
+				SetWxid(friend.Wxid).
+				SetAccount(friend.Account).
+				SetNickname(friend.Nickname).
+				SetMarkname(friend.Markname).
+				SetHeadimg(friend.Headimg).
+				SetSex(cast.ToInt(friend.Sex)).
+				SetStarrole(friend.Starrole).
+				SetDontseeit(cast.ToInt(friend.Dontseeit)).
+				SetDontseeme(cast.ToInt(friend.Dontseeme)).
+				SetLag(friend.Lag).
+				SetV3(friend.V3).
+				OnConflict().
+				UpdateNewValues().
+				ID(l.ctx)
+		}
+	}
+	chatroomCnt := cast.ToInt(friendAndChatRoomList.CountChatroom)
+	if chatroomCnt > 0 {
+		for _, chatroom := range friendAndChatRoomList.Chatroom {
+			l.svcCtx.DB.Contact.Create().
+				SetWxWxid(wxInfo.Wxid).
+				SetType(2).
+				SetWxid(chatroom.Gid).
+				SetNickname(chatroom.Gname).
+				SetGid(chatroom.Gid).
+				SetGname(chatroom.Gname).
+				SetMarkname(chatroom.Markname).
+				SetV3(chatroom.V3).
+				OnConflict().
+				UpdateNewValues().
+				ID(l.ctx)
+		}
+	}
+
+	ghCnt := cast.ToInt(friendAndChatRoomList.CountGh)
+	if ghCnt > 0 {
+		for _, gh := range friendAndChatRoomList.Gh {
+			l.svcCtx.DB.Contact.Create().
+				SetWxWxid(wxInfo.Wxid).
+				SetType(3).
+				SetWxid(gh.Wxid).
+				SetAccount(gh.Account).
+				SetNickname(gh.Nickname).
+				SetMarkname(gh.Markname).
+				SetV3(gh.V3).
+				OnConflict().
+				UpdateNewValues().
+				ID(l.ctx)
+		}
+	}
+
+	resp = &types.BaseMsgResp{
+		Msg:  errormsg.Success,
+		Code: errorcode.OK,
+	}
+
+	return
+}

+ 59 - 0
internal/logic/Wxhook/logout_logic.go

@@ -0,0 +1,59 @@
+package Wxhook
+
+import (
+	"context"
+	"github.com/suyuan32/simple-admin-common/enum/errorcode"
+	"wechat-api/hook"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type LogoutLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic {
+	return &LogoutLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *LogoutLogic) Logout(req *types.IDReq) (resp *types.BaseMsgResp, err error) {
+	wxInfo, err := l.svcCtx.DB.Wx.Get(l.ctx, req.Id)
+	if err != nil {
+		l.Error("查询微信信息失败", err)
+		return
+	}
+
+	serverInfo, err := l.svcCtx.DB.Server.Get(l.ctx, wxInfo.ServerID)
+	if err != nil {
+		l.Error("查询服务器信息失败", err)
+		return
+	}
+
+	hookClient := hook.NewHook(serverInfo.PrivateIP, serverInfo.AdminPort, wxInfo.Port)
+	logout, err := hookClient.Logout()
+	if err != nil {
+		l.Error("退出登录失败", err)
+		return
+	}
+
+	l.svcCtx.DB.Wx.UpdateOne(wxInfo).SetStatus(0).Save(l.ctx)
+
+	resp = &types.BaseMsgResp{
+		Msg: logout.Msg,
+	}
+	if logout.Code == "1" {
+		resp.Code = errorcode.OK
+	} else {
+		resp.Code = errorcode.Unknown
+	}
+
+	return
+}

Някои файлове не бяха показани, защото твърде много файлове са промени