Repository: goal-web/goal Branch: 1.0 Commit: 29044846b598 Files: 96 Total size: 194.9 KB Directory structure: gitextract_fxwyv0x_/ ├── .github/ │ └── ISSUE_TEMPLATE.MD ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── app/ │ ├── console/ │ │ ├── commands/ │ │ │ └── runner.go │ │ └── kernel.go │ ├── controllers/ │ │ ├── helloworld.go │ │ ├── kernel.go │ │ ├── project/ │ │ │ └── Project_gen.go │ │ └── user/ │ │ └── Auth_gen.go │ ├── enums/ │ │ └── Code_gen.go │ ├── exceptions/ │ │ └── handler.go │ ├── http/ │ │ ├── middlewares/ │ │ │ └── example.go │ │ └── sse/ │ │ └── demo.go │ ├── jobs/ │ │ └── demo.go │ ├── listeners/ │ │ └── debug_query.go │ ├── models/ │ │ ├── Article_gen.go │ │ ├── Project_gen.go │ │ ├── User_gen.go │ │ ├── project/ │ │ │ └── GetProjectRessult_gen.go │ │ ├── project.go │ │ └── user/ │ │ └── WechatInfoData_gen.go │ ├── providers/ │ │ ├── app.go │ │ ├── console.go │ │ └── events.go │ ├── requests/ │ │ ├── project/ │ │ │ ├── CreateProject_gen.go │ │ │ ├── DeleteProject_gen.go │ │ │ ├── GetProject_gen.go │ │ │ ├── ListProjects_gen.go │ │ │ └── UpdateProject_gen.go │ │ └── user/ │ │ ├── LoginByWxCode_gen.go │ │ └── LoginByWxInfo_gen.go │ ├── response/ │ │ └── utils.go │ ├── results/ │ │ ├── ResponseResult_gen.go │ │ ├── project/ │ │ │ ├── CreateProjectResult_gen.go │ │ │ ├── DeleteProjectResult_gen.go │ │ │ ├── GetProjectResult_gen.go │ │ │ ├── ListProjectsResult_gen.go │ │ │ └── UpdateProjectResult_gen.go │ │ └── user/ │ │ └── LoginByWxResult_gen.go │ ├── services/ │ │ ├── project/ │ │ │ ├── Project_gen.go │ │ │ └── project.go │ │ └── user/ │ │ └── Auth_gen.go │ └── websocket/ │ └── demo.go ├── bootstrap/ │ ├── console/ │ │ └── main.go │ ├── core/ │ │ └── application.go │ ├── queue/ │ │ └── main.go │ └── schedule/ │ └── main.go ├── config/ │ ├── README_cache_config.md │ ├── app.go │ ├── auth.go │ ├── bloomfilter.go │ ├── cache.go │ ├── cache_example.toml │ ├── database.go │ ├── encryption.go │ ├── filesystem.go │ ├── http.go │ ├── mail.go │ ├── queue.go │ ├── redis.go │ ├── serialization.go │ ├── session.go │ ├── views.go │ └── websocket.go ├── database/ │ ├── .gitignore │ └── migrations/ │ ├── 2024_05_09_141932_create_articles.down.sql │ └── 2024_05_09_141932_create_articles.sql ├── env.toml ├── go.mod ├── go.sum ├── main.go ├── pro/ │ ├── Article.proto │ ├── Project.proto │ ├── common.proto │ ├── goal-cli.go │ └── user.proto ├── routes/ │ ├── api.go │ ├── sse.go │ └── ws.go ├── sdk.tmpl ├── server.conf ├── storage/ │ ├── app/ │ │ └── .gitignore │ ├── framework/ │ │ ├── bloomfilter/ │ │ │ └── .gitignore │ │ ├── cache/ │ │ │ └── .gitignore │ │ └── sessions/ │ │ └── .gitignore │ └── logs/ │ └── .gitignore ├── supervisor.conf ├── template.tmpl ├── tests/ │ ├── bootstrap.go │ ├── bootstrap_test.go │ ├── db_test.go │ └── env.toml └── views/ └── view.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE.MD ================================================ ### 1. What version of `Go` and system type/arch are you using? ### 2. What version of `Goal` are you using? ### 3. Can this issue be re-produced with the latest release? ### 4. What did you do? ### 5. What did you expect to see? ### 6. What did you see instead? ================================================ FILE: .gitignore ================================================ .idea database/*.sqlite *.pid /bin* go.work go.work.sum ================================================ FILE: Dockerfile ================================================ FROM golang:1.20 as builder LABEL maintainer="qbhy " WORKDIR /app COPY . /app ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 ENV GOPROXY=https://proxy.golang.com.cn,direct RUN go build -ldflags="-s -w" -o app main.go FROM alpine WORKDIR /app COPY --from=builder /app/app . # run ENTRYPOINT ["/app/app"] ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 桥边红药 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ DOCKER_TAG=goal gen: go run pro/goal-cli.go --template template.tmpl run: go run main.go run build: go build -o ./bin -v ./ test: go test -json ./tests image: docker build -t $(DOCKER_TAG) . migrate: go run bootstrap/console/main.go migrate migrate-rollback: go run bootstrap/console/main.go migrate:rollback migrate-refresh: go run bootstrap/console/main.go migrate:refresh migrate-reset: go run bootstrap/console/main.go migrate:reset migrate-status: go run bootstrap/console/main.go migrate:status make-migration: go run bootstrap/console/main.go make:migration $(NAME) ================================================ FILE: README.md ================================================ # Goal Framework [![codecov](https://codecov.io/gh/goal-web/goal/branch/master/graph/badge.svg)](https://codecov.io/gh/goal-web/goal) [![Go Report Card](https://goreportcard.com/badge/github.com/goal-web/goal)](https://goreportcard.com/report/github.com/goal-web/goal) [![GoDoc](https://pkg.go.dev/badge/github.com/goal-web/goal?status.svg)](https://pkg.go.dev/github.com/goal-web/goal?tab=doc) [![Join the chat at https://gitter.im/goal-web/goal](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/goal-web/goal?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sourcegraph](https://sourcegraph.com/github.com/goal-web/goal/-/badge.svg)](https://sourcegraph.com/github.com/goal-web/contracts?badge) [![Open Source Helpers](https://www.codetriage.com/goal-web/goal/badges/users.svg)](https://www.codetriage.com/goal-web/goal) [![Release](https://img.shields.io/github/release/goal-web/goal.svg?style=flat-square)](https://github.com/goal-web/goal/releases) [![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/goal-web/goal)](https://www.tickgit.com/browse?repo=github.com/goal-web/goal) ## Star History ![https://api.star-history.com/svg?repos=goal-web/goal&type=Date](https://api.star-history.com/svg?repos=goal-web/goal&type=Date) ## About Goal Framework Goal Framework is a common application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Goal Framework takes the pain out of development by easing common tasks used in many web projects, such as: - [Simple and powerful middleware](https://github.com/goal-web/pipeline). - [Powerful dependency injection container](https://github.com/goal-web/container). - Multiple back-ends for [session](https://github.com/goal-web/session) and [cache](https://github.com/goal-web/cache) storage. - Expressive, intuitive [database](https://github.com/goal-web/database). - [Robust background job processing](https://github.com/goal-web/queue). Goal framework is accessible, powerful, and provides tools required for large, robust applications. ## Learning Goal Framework * [Installation](https://github.com/goal-web/doc/blob/wiki/%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/%E5%AE%89%E8%A3%85.md) * [Documents](https://github.com/goal-web/doc/blob/wiki/README.md) ## Contributing Thank you for considering contributing to the Goal framework! The contribution guide can be found in the [Goal documentation](https://github.com/goal-web/doc/blob/wiki/%E5%89%8D%E8%A8%80/%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%BC%95.md). ## License The Goal framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). ================================================ FILE: app/console/commands/runner.go ================================================ package commands import ( "fmt" "github.com/goal-web/contracts" "github.com/goal-web/supports/commands" "github.com/goal-web/supports/logs" "os" ) type runner struct { commands.Command app contracts.Application } func Runner() (contracts.Command, contracts.CommandHandlerProvider) { return commands.Base("run", "启动 goal"), func(app contracts.Application) contracts.CommandHandler { return &runner{app: app} } } func (runner *runner) Handle() any { path, _ := os.Getwd() pidPath := path + "/goal.pid" // 写入 pid 文件 _ = os.WriteFile(pidPath, []byte(fmt.Sprintf("%d", os.Getpid())), os.ModePerm) if errors := runner.app.Start(); len(errors) > 0 { logs.WithField("errors", errors).Fatal("goal 启动异常!") } else { _ = os.Remove(pidPath) logs.Default().Info("goal 已关闭") } return nil } ================================================ FILE: app/console/kernel.go ================================================ package console import ( "github.com/goal-web/config" "github.com/goal-web/contracts" "github.com/goal-web/goal/app/console/commands" "github.com/goal-web/supports/logs" ) var Commands = []contracts.CommandProvider{ commands.Runner, config.EncryptionCommand, } func Schedule(schedule contracts.Schedule) { schedule.Call(func() { //fmt.Println("打印 hello") logs.Default().Info("打印 hello") }).EveryFiveSeconds() } ================================================ FILE: app/controllers/helloworld.go ================================================ package controllers import ( "fmt" "github.com/goal-web/contracts" "github.com/goal-web/goal/app/models" "github.com/gookit/goutil/dump" ) func HelloWorld() any { createProject() updateProject() dump.P(23) projects := getProjectList() return contracts.Fields{ "data": projects, } } func createProject() { fields := contracts.Fields{ "uuid": "45", "name": "your_project_name", "creator_id": 1, "group_id": 1, "key_id": 1, "repo_address": "your_repo_address", "project_path": "your_project_path", "default_branch": "main", "settings": "{}", } model := models.NewProjectModel(fields) err := model.Save() if err != nil { fmt.Printf("Failed to create project: %v\n", err) } else { fmt.Println("Project created successfully111") } } func getProjectOne() any { query := models.ProjectQuery() project := query.Where("id", 1).First() // 假设查询 id 为 1 的记录 fmt.Printf("Project: %+v\n", project) return project } func getProjectList() any { query := models.ProjectQuery() projects := query.Get().ToAnyArray() // dump.P(projects) return projects } func updateProject() { query := models.ProjectQuery() project := query.Where("id", 1).First() // 假设更新 id 为 1 的记录 updateFields := contracts.Fields{ "name": "updated_project_name11", } err := project.Update(updateFields) dump.P(err) } func deleteProject() { query := models.ProjectQuery() project := query.Where("id", 1).First() // 假设删除 id 为 1 的记录 _ = project.Delete() } ================================================ FILE: app/controllers/kernel.go ================================================ package controllers import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/app/controllers/project" "github.com/goal-web/goal/app/controllers/user" ) // Register 注册路由函数 func Register(router contracts.HttpRouter) { user.AuthServiceRouter(router) project.ProjectServiceRouter(router) // 在这里添加您的路由注册逻辑 } ================================================ FILE: app/controllers/project/Project_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" project "github.com/goal-web/goal/app/requests/project" "github.com/goal-web/goal/app/response" svc "github.com/goal-web/goal/app/services/project" "github.com/goal-web/validation" ) func ProjectServiceRouter(router contracts.HttpRouter) { routeGroup := router.Group("/project") routeGroup.Post("/CreateProject", ProjectServiceCreateProject) routeGroup.Get("/GetProject", ProjectServiceGetProject) routeGroup.Get("/ListProjects", ProjectServiceListProjects) routeGroup.Post("/UpdateProject", ProjectServiceUpdateProject) routeGroup.Post("/DeleteProject", ProjectServiceDeleteProject) } func ProjectServiceCreateProject(request contracts.HttpRequest) any { var req project.CreateProjectReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.ProjectServiceCreateProject(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } func ProjectServiceGetProject(request contracts.HttpRequest) any { var req project.GetProjectReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.ProjectServiceGetProject(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } func ProjectServiceListProjects(request contracts.HttpRequest) any { var req project.ListProjectsReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.ProjectServiceListProjects(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } func ProjectServiceUpdateProject(request contracts.HttpRequest) any { var req project.UpdateProjectReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.ProjectServiceUpdateProject(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } func ProjectServiceDeleteProject(request contracts.HttpRequest) any { var req project.DeleteProjectReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.ProjectServiceDeleteProject(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } ================================================ FILE: app/controllers/user/Auth_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import ( "github.com/goal-web/contracts" user "github.com/goal-web/goal/app/requests/user" "github.com/goal-web/goal/app/response" svc "github.com/goal-web/goal/app/services/user" "github.com/goal-web/validation" ) func AuthServiceRouter(router contracts.HttpRouter) { routeGroup := router.Group("/auth") routeGroup.Post("/LoginByWxAppCode", AuthServiceLoginByWxAppCode, "guest") routeGroup.Post("/LoginByWxAppInfo", AuthServiceLoginByWxAppInfo, "guest") } func AuthServiceLoginByWxAppCode(request contracts.HttpRequest) any { var req user.LoginByWxCodeReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.AuthServiceLoginByWxAppCode(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } func AuthServiceLoginByWxAppInfo(request contracts.HttpRequest) any { var req user.LoginByWxInfoReq if err := request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := svc.AuthServiceLoginByWxAppInfo(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } ================================================ FILE: app/enums/Code_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/common.proto // package enums type Code int const ( // CodeSuccess // @msg:成功 CodeSuccess Code = 0 // CodeParseReqErr // @msg:参数解析失败 CodeParseReqErr Code = 10400 // CodeUnauthorized // @msg:未登录 CodeUnauthorized Code = 10401 // CodeForbidden // @msg:没有权限 CodeForbidden Code = 100403 // CodeNotFound // @msg:找不到 CodeNotFound Code = 100404 // CodeBizErr // @msg:业务错误 CodeBizErr Code = 10201 CodeUnknown Code = -1000 ) func (item Code) String() string { switch item { case CodeSuccess: return "Success" case CodeParseReqErr: return "ParseReqErr" case CodeUnauthorized: return "Unauthorized" case CodeForbidden: return "Forbidden" case CodeNotFound: return "NotFound" case CodeBizErr: return "BizErr" default: return "Unknown" } } func (item Code) Message() string { switch item { case CodeSuccess: return "成功" case CodeParseReqErr: return "参数解析失败" case CodeUnauthorized: return "未登录" case CodeForbidden: return "没有权限" case CodeNotFound: return "找不到" case CodeBizErr: return "业务错误" default: return "Unknown" } } func ParseCodeFromString(msg string) Code { switch msg { case "Success": return CodeSuccess case "ParseReqErr": return CodeParseReqErr case "Unauthorized": return CodeUnauthorized case "Forbidden": return CodeForbidden case "NotFound": return CodeNotFound case "BizErr": return CodeBizErr default: return CodeUnknown } } ================================================ FILE: app/exceptions/handler.go ================================================ package exceptions import ( "reflect" "runtime/debug" "strings" "github.com/goal-web/contracts" "github.com/goal-web/http" "github.com/goal-web/supports/logs" "github.com/goal-web/supports/utils" "github.com/goal-web/validation" ) type ExceptionHandler struct { dontReportExceptions []reflect.Type } func NewHandler() contracts.ExceptionHandler { return &ExceptionHandler{utils.ToTypes([]contracts.Exception{})} } func (handler *ExceptionHandler) Handle(exception contracts.Exception) any { logs.WithException(exception).Warn("报错了") switch e := exception.(type) { case http.Exception: // http 支持在异常处理器返回响应 return handler.handleHttpException(e) case *validation.Exception: return handler.renderValidationException(e) default: debug.PrintStack() } logs.WithException(exception). WithField("exception", reflect.TypeOf(exception).String()). Error("ExceptionHandler") if httpException, isHttpException := exception.(http.Exception); isHttpException { logs.WithException(httpException).WithFields(contracts.Fields{}).Debug("http请求报错") } if handler.ShouldReport(exception) { handler.Report(exception) } return nil } func (handler *ExceptionHandler) handleHttpException(exception http.Exception) any { switch e := exception.Exception.(type) { case *validation.Exception: return handler.renderValidationException(e) default: if !strings.Contains(exception.Error(), "404") { debug.PrintStack() } return contracts.Fields{ "path": exception.Request.Path(), "error": e.Error(), } } } func (handler *ExceptionHandler) renderValidationException(exception *validation.Exception) any { return contracts.Fields{ "msg": exception.Error(), "fields": exception.Param, "errors": exception.Errors, } } func (handler *ExceptionHandler) Report(exception contracts.Exception) { } func (handler *ExceptionHandler) ShouldReport(exception contracts.Exception) bool { return !utils.IsInstanceIn(exception, handler.dontReportExceptions...) } ================================================ FILE: app/http/middlewares/example.go ================================================ package middlewares import ( "fmt" "github.com/goal-web/contracts" "github.com/goal-web/http" ) func Example(request contracts.HttpRequest, next contracts.Pipe) any { fmt.Println("controller before") result := next(request) fmt.Println("controller after") return http.NewJsonResponse(contracts.Fields{ "result": result, }, 200) } ================================================ FILE: app/http/sse/demo.go ================================================ package sse import ( "errors" "github.com/goal-web/contracts" ) type DemoController struct { } func (d DemoController) OnConnect(request contracts.HttpRequest, fd uint64) error { // 伪代码 if request.GetString("token") != "goal" { return errors.New("401") } // todo: 绑定用户和 fd return nil } func (d DemoController) OnClose(fd uint64) { // todo: 实现解绑 } ================================================ FILE: app/jobs/demo.go ================================================ package jobs import ( "github.com/goal-web/contracts" "github.com/goal-web/queue" "github.com/goal-web/supports/class" "github.com/goal-web/supports/logs" "github.com/goal-web/supports/utils" "time" ) var DemoClass = class.Any(Demo{}) type Demo struct { *queue.Job Info string `json:"info"` } func NewDemo(info string) contracts.Job { return &Demo{ Job: &queue.Job{ UUID: utils.RandStr(5), CreatedAt: time.Now().Unix(), Queue: "default", Connection: "default", Tries: 0, MaxTries: 3, Timeout: 0, }, Info: info, } } func (demo *Demo) Handle() { logs.Default().WithField("info", demo.Info).Info("demo job") } ================================================ FILE: app/listeners/debug_query.go ================================================ package listeners import ( "github.com/goal-web/contracts" "github.com/goal-web/database/events" "github.com/goal-web/supports/logs" ) type DebugQuery struct { } func (d DebugQuery) Handle(event contracts.Event) { if e, ok := event.(*events.QueryExecuted); ok { logs.WithFields(contracts.Fields{ "sql": e.Sql, "bindings": e.Bindings, "connection": e.Connection, "time": e.Time, }).Debug("sql executed") } } ================================================ FILE: app/models/Article_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Article.proto // package models import ( "encoding/json" "fmt" "github.com/goal-web/collection" "github.com/goal-web/contracts" "github.com/goal-web/database/table" "github.com/goal-web/migration/migrate" "github.com/goal-web/supports/logs" "github.com/goal-web/supports/utils" "github.com/spf13/cast" ) var () // ArticleModel // @timestamps type ArticleModel struct { Id uint32 `json:"id" query:"id" form:"id" db:"id;type:INT UNSIGNED;not null;primary key;AUTO_INCREMENT;"` Title string `json:"title" query:"title" form:"title" db:"title;type:VARCHAR(255);not null;"` CreatedAt string `json:"created_at" query:"created_at" form:"created_at" db:"created_at;type:timestamp;default CURRENT_TIMESTAMP;"` UpdatedAt string `json:"updated_at" query:"updated_at" form:"updated_at" db:"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;"` _raw contracts.Fields _update contracts.Fields _append contracts.Fields _hidden map[string]struct{} _relation_loaded map[contracts.RelationType]struct{} } var ArticleDefine ArticleStatic type ArticleStatic struct { TableName string Hidden []string Indexes []string With []contracts.RelationType Appends map[string]func(model *ArticleModel) any IdGetter func(model *ArticleModel, raw uint32) uint32 IdSetter func(model *ArticleModel, raw uint32) uint32 TitleGetter func(model *ArticleModel, raw string) string TitleSetter func(model *ArticleModel, raw string) string CreatedAtGetter func(model *ArticleModel, raw string) string CreatedAtSetter func(model *ArticleModel, raw string) string UpdatedAtGetter func(model *ArticleModel, raw string) string UpdatedAtSetter func(model *ArticleModel, raw string) string Saving func(model *ArticleModel) contracts.Exception Saved func(model *ArticleModel) Updating func(model *ArticleModel, fields contracts.Fields) contracts.Exception Updated func(model *ArticleModel, fields contracts.Fields) Deleting func(model *ArticleModel) contracts.Exception Deleted func(model *ArticleModel) PrimaryKeyGetter func(model *ArticleModel) any } func ArticleMigrator() migrate.Migrator { return func(executor contracts.SqlExecutor) contracts.Exception { return migrate.Migrate(ArticleDefine.TableName, ArticleDefine.Indexes, ArticleModel{}, executor) } } func init() { ArticleDefine.TableName = "articles" ArticleDefine.Appends = make(map[string]func(model *ArticleModel) any) } func NewArticleModel(fields contracts.Fields) *ArticleModel { var model = ArticleModel{ _raw: fields, } model.Set(fields) return &model } func ArticleModelSingleRelationSetter[T any](key contracts.RelationType) func(item *ArticleModel, value []any) { return func(item *ArticleModel, values []any) { var value T if len(values) > 0 { value = values[0].(T) } item.Set(contracts.Fields{ string(key): value, }) } } func ArticleModelMultiRelationSetter[T any](key contracts.RelationType) func(item *ArticleModel, value []any) { return func(model *ArticleModel, value []any) { var results []T for _, item := range value { results = append(results, item.(T)) } model.Set(contracts.Fields{string(key): results}) } } func ArticleModelLocalKeyGetter(key string) func(item *ArticleModel) any { return func(item *ArticleModel) any { return item.Get(key) } } func ArticleModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} for key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) { results[key] = collection.New(values).ToAnyArray() } return results } } func ArticleModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} groupKey := fmt.Sprintf("%s.%s", midTable, firstKey) for key, values := range query(). AddSelect(fmt.Sprintf("(%s) as _group_key", groupKey)). WhereIn(groupKey, keys). Join(midTable, fmt.Sprintf("%s.%s", midTable, secondLocalKey), "=", fmt.Sprintf("%s.%s", query().GetTableName(), secondKey)). Get().GroupBy("_group_key") { results[key] = collection.New(values).ToAnyArray() } return results } } func ArticleQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[ArticleModel] { return ArticleQuery().SetExecutor(executor) } func ArticleQuery() *table.Table[ArticleModel] { return table.NewQuery(ArticleDefine.TableName, NewArticleModel). SetPrimaryKey("id"). SetCreatedTimeColumn("created_at"). SetUpdatedTimeColumn("updated_at"). SetWiths(ArticleDefine.With...) } func (model *ArticleModel) Hidden(fields ...string) *ArticleModel { for _, field := range fields { if model._hidden == nil { model._hidden = map[string]struct{}{ field: struct{}{}, } } else { model._hidden[field] = struct{}{} } } return model } func (model *ArticleModel) Exists() bool { return ArticleQuery().Where("id", model.GetPrimaryKey()).Count() > 0 } func (model *ArticleModel) Save() contracts.Exception { if model._update == nil { return nil } if ArticleDefine.Saving != nil { if err := ArticleDefine.Saving(model); err != nil { return err } } var err contracts.Exception var pk = model.GetPrimaryKey() if cast.ToUint64(pk) == 0 { pk, err = ArticleQuery().Where("id", model.GetPrimaryKey()).InsertGetIdE(model._update) if err == nil { model.SetId(cast.ToUint32(pk)) } } else { _, err = ArticleQuery().Where("id", model.GetPrimaryKey()).UpdateE(model._update) } if err == nil { model._update = nil if ArticleDefine.Saved != nil { ArticleDefine.Saved(model) } } return err } func (model *ArticleModel) Set(fields contracts.Fields) { for key, value := range fields { switch key { case "id": switch v := value.(type) { case uint32: model.SetId(v) case func() uint32: model.SetId(v()) case string: var vd uint32 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) case []byte: var vd uint32 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) default: model.SetId(cast.ToUint32(v)) } case "title": switch v := value.(type) { case string: model.SetTitle(v) case func() string: model.SetTitle(v()) case []byte: model.SetTitle(string(v)) default: model.SetTitle(cast.ToString(v)) } case "created_at": switch v := value.(type) { case string: model.SetCreatedAt(v) case func() string: model.SetCreatedAt(v()) case []byte: model.SetCreatedAt(string(v)) default: model.SetCreatedAt(cast.ToString(v)) } case "updated_at": switch v := value.(type) { case string: model.SetUpdatedAt(v) case func() string: model.SetUpdatedAt(v()) case []byte: model.SetUpdatedAt(string(v)) default: model.SetUpdatedAt(cast.ToString(v)) } } } } func (model *ArticleModel) Only(key ...string) contracts.Fields { var fields = make(contracts.Fields) for _, k := range key { if k == "id" { fields[k] = model.GetId() continue } if k == "title" { fields[k] = model.GetTitle() continue } if k == "created_at" { fields[k] = model.GetCreatedAt() continue } if k == "updated_at" { fields[k] = model.GetUpdatedAt() continue } if ArticleDefine.Appends[k] != nil { fields[k] = ArticleDefine.Appends[k](model) } } return fields } func (model *ArticleModel) Get(key string) any { switch key { case "id": return model.GetId() case "title": return model.GetTitle() case "created_at": return model.GetCreatedAt() case "updated_at": return model.GetUpdatedAt() } if value, exists := model._append[key]; exists { return value } if fn, exists := ArticleDefine.Appends[key]; exists { model._append[key] = fn(model) return model._append[key] } switch contracts.RelationType(key) { } return nil } func (model *ArticleModel) Except(keys ...string) contracts.Fields { var excepts = map[string]struct{}{} for _, k := range keys { excepts[k] = struct{}{} } var fields = make(contracts.Fields) for key, value := range model.ToFields() { if _, ok := excepts[key]; ok { continue } fields[key] = value } return fields } func (model *ArticleModel) ToFields() contracts.Fields { if model == nil { return nil } model.Hidden(ArticleDefine.Hidden...) fields := contracts.Fields{} if _, exists := model._hidden["id"]; !exists { fields["id"] = model.GetId() } if _, exists := model._hidden["title"]; !exists { fields["title"] = model.GetTitle() } if _, exists := model._hidden["created_at"]; !exists { fields["created_at"] = model.GetCreatedAt() } if _, exists := model._hidden["updated_at"]; !exists { fields["updated_at"] = model.GetUpdatedAt() } for key := range ArticleDefine.Appends { value := model.Get(key) if fieldsProvider, ok := value.(contracts.FieldsProvider); ok { fields[key] = fieldsProvider.ToFields() } else { fields[key] = value } } for key := range model._relation_loaded { switch key { } } for key, value := range model._raw { _, hidden := model._hidden[key] if _, exists := fields[key]; !exists && !hidden { fields[key] = value } } return fields } func (model *ArticleModel) Update(fields contracts.Fields) contracts.Exception { if ArticleDefine.Updating != nil { if err := ArticleDefine.Updating(model, fields); err != nil { return err } } if model._update != nil { utils.MergeFields(model._update, fields) } _, err := ArticleQuery().Where("id", model.GetPrimaryKey()).UpdateE(fields) if err == nil { model.Set(fields) model._update = nil if ArticleDefine.Updated != nil { ArticleDefine.Updated(model, fields) } } return err } func (model *ArticleModel) Refresh() contracts.Exception { fields, err := table.ArrayQuery("articles").Where("id", model.GetPrimaryKey()).FirstE() if err != nil { return err } model.Set(*fields) return nil } func (model *ArticleModel) Delete() contracts.Exception { if ArticleDefine.Deleting != nil { if err := ArticleDefine.Deleting(model); err != nil { return err } } _, err := ArticleQuery().Where("id", model.GetPrimaryKey()).DeleteE() if err == nil && ArticleDefine.Deleted != nil { ArticleDefine.Deleted(model) } return err } func (model *ArticleModel) GetPrimaryKey() any { if ArticleDefine.PrimaryKeyGetter != nil { return ArticleDefine.PrimaryKeyGetter(model) } return model.Id } func (model *ArticleModel) GetId() uint32 { if ArticleDefine.IdGetter != nil { return ArticleDefine.IdGetter(model, model.Id) } return model.Id } func (model *ArticleModel) SetId(value uint32) { if ArticleDefine.IdSetter != nil { value = ArticleDefine.IdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"id": value} } else { model._update["id"] = value } model.Id = value } func (model *ArticleModel) GetTitle() string { if ArticleDefine.TitleGetter != nil { return ArticleDefine.TitleGetter(model, model.Title) } return model.Title } func (model *ArticleModel) SetTitle(value string) { if ArticleDefine.TitleSetter != nil { value = ArticleDefine.TitleSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"title": value} } else { model._update["title"] = value } model.Title = value } func (model *ArticleModel) GetCreatedAt() string { if ArticleDefine.CreatedAtGetter != nil { return ArticleDefine.CreatedAtGetter(model, model.CreatedAt) } return model.CreatedAt } func (model *ArticleModel) SetCreatedAt(value string) { if ArticleDefine.CreatedAtSetter != nil { value = ArticleDefine.CreatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"created_at": value} } else { model._update["created_at"] = value } model.CreatedAt = value } func (model *ArticleModel) GetUpdatedAt() string { if ArticleDefine.UpdatedAtGetter != nil { return ArticleDefine.UpdatedAtGetter(model, model.UpdatedAt) } return model.UpdatedAt } func (model *ArticleModel) SetUpdatedAt(value string) { if ArticleDefine.UpdatedAtSetter != nil { value = ArticleDefine.UpdatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"updated_at": value} } else { model._update["updated_at"] = value } model.UpdatedAt = value } ================================================ FILE: app/models/Project_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package models import ( "encoding/json" "fmt" "github.com/goal-web/collection" "github.com/goal-web/contracts" "github.com/goal-web/database/table" "github.com/goal-web/migration/migrate" "github.com/goal-web/supports/logs" "github.com/goal-web/supports/utils" "github.com/spf13/cast" ) var () // ProjectModel // @timestamps type ProjectModel struct { Id int64 `json:"id" query:"id" form:"id" db:"id;type:BIGINT;not null;primary key;AUTO_INCREMENT;"` Uuid string `json:"uuid" query:"uuid" form:"uuid" db:"uuid;type:VARCHAR(255);not null;"` Name string `json:"name" query:"name" form:"name" db:"name;type:VARCHAR(255);not null;"` CreatorId int64 `json:"creator_id" query:"creator_id" form:"creator_id" db:"creator_id;type:BIGINT;not null;"` GroupId int64 `json:"group_id" query:"group_id" form:"group_id" db:"group_id;type:BIGINT;not null;"` KeyId int64 `json:"key_id" query:"key_id" form:"key_id" db:"key_id;type:BIGINT;not null;"` RepoAddress string `json:"repo_address" query:"repo_address" form:"repo_address" db:"repo_address;type:VARCHAR(255);not null;"` ProjectPath string `json:"project_path" query:"project_path" form:"project_path" db:"project_path;type:VARCHAR(255);not null;"` DefaultBranch string `json:"default_branch" query:"default_branch" form:"default_branch" db:"default_branch;type:VARCHAR(255);not null;"` Settings string `json:"settings" query:"settings" form:"settings" db:"settings;type:VARCHAR(255);not null;"` CreatedAt string `json:"created_at" query:"created_at" form:"created_at" db:"created_at;type:timestamp;default CURRENT_TIMESTAMP;"` UpdatedAt string `json:"updated_at" query:"updated_at" form:"updated_at" db:"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;"` _raw contracts.Fields _update contracts.Fields _append contracts.Fields _hidden map[string]struct{} _relation_loaded map[contracts.RelationType]struct{} } var ProjectDefine ProjectStatic type ProjectStatic struct { TableName string Hidden []string Indexes []string With []contracts.RelationType Appends map[string]func(model *ProjectModel) any IdGetter func(model *ProjectModel, raw int64) int64 IdSetter func(model *ProjectModel, raw int64) int64 UuidGetter func(model *ProjectModel, raw string) string UuidSetter func(model *ProjectModel, raw string) string NameGetter func(model *ProjectModel, raw string) string NameSetter func(model *ProjectModel, raw string) string CreatorIdGetter func(model *ProjectModel, raw int64) int64 CreatorIdSetter func(model *ProjectModel, raw int64) int64 GroupIdGetter func(model *ProjectModel, raw int64) int64 GroupIdSetter func(model *ProjectModel, raw int64) int64 KeyIdGetter func(model *ProjectModel, raw int64) int64 KeyIdSetter func(model *ProjectModel, raw int64) int64 RepoAddressGetter func(model *ProjectModel, raw string) string RepoAddressSetter func(model *ProjectModel, raw string) string ProjectPathGetter func(model *ProjectModel, raw string) string ProjectPathSetter func(model *ProjectModel, raw string) string DefaultBranchGetter func(model *ProjectModel, raw string) string DefaultBranchSetter func(model *ProjectModel, raw string) string SettingsGetter func(model *ProjectModel, raw string) string SettingsSetter func(model *ProjectModel, raw string) string CreatedAtGetter func(model *ProjectModel, raw string) string CreatedAtSetter func(model *ProjectModel, raw string) string UpdatedAtGetter func(model *ProjectModel, raw string) string UpdatedAtSetter func(model *ProjectModel, raw string) string Saving func(model *ProjectModel) contracts.Exception Saved func(model *ProjectModel) Updating func(model *ProjectModel, fields contracts.Fields) contracts.Exception Updated func(model *ProjectModel, fields contracts.Fields) Deleting func(model *ProjectModel) contracts.Exception Deleted func(model *ProjectModel) PrimaryKeyGetter func(model *ProjectModel) any } func ProjectMigrator() migrate.Migrator { return func(executor contracts.SqlExecutor) contracts.Exception { return migrate.Migrate(ProjectDefine.TableName, ProjectDefine.Indexes, ProjectModel{}, executor) } } func init() { ProjectDefine.TableName = "projects" ProjectDefine.Appends = make(map[string]func(model *ProjectModel) any) } func NewProjectModel(fields contracts.Fields) *ProjectModel { var model = ProjectModel{ _raw: fields, } model.Set(fields) return &model } func ProjectModelSingleRelationSetter[T any](key contracts.RelationType) func(item *ProjectModel, value []any) { return func(item *ProjectModel, values []any) { var value T if len(values) > 0 { value = values[0].(T) } item.Set(contracts.Fields{ string(key): value, }) } } func ProjectModelMultiRelationSetter[T any](key contracts.RelationType) func(item *ProjectModel, value []any) { return func(model *ProjectModel, value []any) { var results []T for _, item := range value { results = append(results, item.(T)) } model.Set(contracts.Fields{string(key): results}) } } func ProjectModelLocalKeyGetter(key string) func(item *ProjectModel) any { return func(item *ProjectModel) any { return item.Get(key) } } func ProjectModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} for key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) { results[key] = collection.New(values).ToAnyArray() } return results } } func ProjectModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} groupKey := fmt.Sprintf("%s.%s", midTable, firstKey) for key, values := range query(). AddSelect(fmt.Sprintf("(%s) as _group_key", groupKey)). WhereIn(groupKey, keys). Join(midTable, fmt.Sprintf("%s.%s", midTable, secondLocalKey), "=", fmt.Sprintf("%s.%s", query().GetTableName(), secondKey)). Get().GroupBy("_group_key") { results[key] = collection.New(values).ToAnyArray() } return results } } func ProjectQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[ProjectModel] { return ProjectQuery().SetExecutor(executor) } func ProjectQuery() *table.Table[ProjectModel] { return table.NewQuery(ProjectDefine.TableName, NewProjectModel). SetPrimaryKey("id"). SetCreatedTimeColumn("created_at"). SetUpdatedTimeColumn("updated_at"). SetWiths(ProjectDefine.With...) } func (model *ProjectModel) Hidden(fields ...string) *ProjectModel { for _, field := range fields { if model._hidden == nil { model._hidden = map[string]struct{}{ field: struct{}{}, } } else { model._hidden[field] = struct{}{} } } return model } func (model *ProjectModel) Exists() bool { return ProjectQuery().Where("id", model.GetPrimaryKey()).Count() > 0 } func (model *ProjectModel) Save() contracts.Exception { if model._update == nil { return nil } if ProjectDefine.Saving != nil { if err := ProjectDefine.Saving(model); err != nil { return err } } var err contracts.Exception var pk = model.GetPrimaryKey() if cast.ToUint64(pk) == 0 { pk, err = ProjectQuery().Where("id", model.GetPrimaryKey()).InsertGetIdE(model._update) if err == nil { model.SetId(cast.ToInt64(pk)) } } else { _, err = ProjectQuery().Where("id", model.GetPrimaryKey()).UpdateE(model._update) } if err == nil { model._update = nil if ProjectDefine.Saved != nil { ProjectDefine.Saved(model) } } return err } func (model *ProjectModel) Set(fields contracts.Fields) { for key, value := range fields { switch key { case "id": switch v := value.(type) { case int64: model.SetId(v) case func() int64: model.SetId(v()) case string: var vd int64 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) case []byte: var vd int64 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) default: model.SetId(cast.ToInt64(v)) } case "uuid": switch v := value.(type) { case string: model.SetUuid(v) case func() string: model.SetUuid(v()) case []byte: model.SetUuid(string(v)) default: model.SetUuid(cast.ToString(v)) } case "name": switch v := value.(type) { case string: model.SetName(v) case func() string: model.SetName(v()) case []byte: model.SetName(string(v)) default: model.SetName(cast.ToString(v)) } case "creator_id": switch v := value.(type) { case int64: model.SetCreatorId(v) case func() int64: model.SetCreatorId(v()) case string: var vd int64 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetCreatorId(vd) case []byte: var vd int64 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetCreatorId(vd) default: model.SetCreatorId(cast.ToInt64(v)) } case "group_id": switch v := value.(type) { case int64: model.SetGroupId(v) case func() int64: model.SetGroupId(v()) case string: var vd int64 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetGroupId(vd) case []byte: var vd int64 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetGroupId(vd) default: model.SetGroupId(cast.ToInt64(v)) } case "key_id": switch v := value.(type) { case int64: model.SetKeyId(v) case func() int64: model.SetKeyId(v()) case string: var vd int64 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetKeyId(vd) case []byte: var vd int64 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetKeyId(vd) default: model.SetKeyId(cast.ToInt64(v)) } case "repo_address": switch v := value.(type) { case string: model.SetRepoAddress(v) case func() string: model.SetRepoAddress(v()) case []byte: model.SetRepoAddress(string(v)) default: model.SetRepoAddress(cast.ToString(v)) } case "project_path": switch v := value.(type) { case string: model.SetProjectPath(v) case func() string: model.SetProjectPath(v()) case []byte: model.SetProjectPath(string(v)) default: model.SetProjectPath(cast.ToString(v)) } case "default_branch": switch v := value.(type) { case string: model.SetDefaultBranch(v) case func() string: model.SetDefaultBranch(v()) case []byte: model.SetDefaultBranch(string(v)) default: model.SetDefaultBranch(cast.ToString(v)) } case "settings": switch v := value.(type) { case string: model.SetSettings(v) case func() string: model.SetSettings(v()) case []byte: model.SetSettings(string(v)) default: model.SetSettings(cast.ToString(v)) } case "created_at": switch v := value.(type) { case string: model.SetCreatedAt(v) case func() string: model.SetCreatedAt(v()) case []byte: model.SetCreatedAt(string(v)) default: model.SetCreatedAt(cast.ToString(v)) } case "updated_at": switch v := value.(type) { case string: model.SetUpdatedAt(v) case func() string: model.SetUpdatedAt(v()) case []byte: model.SetUpdatedAt(string(v)) default: model.SetUpdatedAt(cast.ToString(v)) } } } } func (model *ProjectModel) Only(key ...string) contracts.Fields { var fields = make(contracts.Fields) for _, k := range key { if k == "id" { fields[k] = model.GetId() continue } if k == "uuid" { fields[k] = model.GetUuid() continue } if k == "name" { fields[k] = model.GetName() continue } if k == "creator_id" { fields[k] = model.GetCreatorId() continue } if k == "group_id" { fields[k] = model.GetGroupId() continue } if k == "key_id" { fields[k] = model.GetKeyId() continue } if k == "repo_address" { fields[k] = model.GetRepoAddress() continue } if k == "project_path" { fields[k] = model.GetProjectPath() continue } if k == "default_branch" { fields[k] = model.GetDefaultBranch() continue } if k == "settings" { fields[k] = model.GetSettings() continue } if k == "created_at" { fields[k] = model.GetCreatedAt() continue } if k == "updated_at" { fields[k] = model.GetUpdatedAt() continue } if ProjectDefine.Appends[k] != nil { fields[k] = ProjectDefine.Appends[k](model) } } return fields } func (model *ProjectModel) Get(key string) any { switch key { case "id": return model.GetId() case "uuid": return model.GetUuid() case "name": return model.GetName() case "creator_id": return model.GetCreatorId() case "group_id": return model.GetGroupId() case "key_id": return model.GetKeyId() case "repo_address": return model.GetRepoAddress() case "project_path": return model.GetProjectPath() case "default_branch": return model.GetDefaultBranch() case "settings": return model.GetSettings() case "created_at": return model.GetCreatedAt() case "updated_at": return model.GetUpdatedAt() } if value, exists := model._append[key]; exists { return value } if fn, exists := ProjectDefine.Appends[key]; exists { model._append[key] = fn(model) return model._append[key] } switch contracts.RelationType(key) { } return nil } func (model *ProjectModel) Except(keys ...string) contracts.Fields { var excepts = map[string]struct{}{} for _, k := range keys { excepts[k] = struct{}{} } var fields = make(contracts.Fields) for key, value := range model.ToFields() { if _, ok := excepts[key]; ok { continue } fields[key] = value } return fields } func (model *ProjectModel) ToFields() contracts.Fields { if model == nil { return nil } model.Hidden(ProjectDefine.Hidden...) fields := contracts.Fields{} if _, exists := model._hidden["id"]; !exists { fields["id"] = model.GetId() } if _, exists := model._hidden["uuid"]; !exists { fields["uuid"] = model.GetUuid() } if _, exists := model._hidden["name"]; !exists { fields["name"] = model.GetName() } if _, exists := model._hidden["creator_id"]; !exists { fields["creator_id"] = model.GetCreatorId() } if _, exists := model._hidden["group_id"]; !exists { fields["group_id"] = model.GetGroupId() } if _, exists := model._hidden["key_id"]; !exists { fields["key_id"] = model.GetKeyId() } if _, exists := model._hidden["repo_address"]; !exists { fields["repo_address"] = model.GetRepoAddress() } if _, exists := model._hidden["project_path"]; !exists { fields["project_path"] = model.GetProjectPath() } if _, exists := model._hidden["default_branch"]; !exists { fields["default_branch"] = model.GetDefaultBranch() } if _, exists := model._hidden["settings"]; !exists { fields["settings"] = model.GetSettings() } if _, exists := model._hidden["created_at"]; !exists { fields["created_at"] = model.GetCreatedAt() } if _, exists := model._hidden["updated_at"]; !exists { fields["updated_at"] = model.GetUpdatedAt() } for key := range ProjectDefine.Appends { value := model.Get(key) if fieldsProvider, ok := value.(contracts.FieldsProvider); ok { fields[key] = fieldsProvider.ToFields() } else { fields[key] = value } } for key := range model._relation_loaded { switch key { } } for key, value := range model._raw { _, hidden := model._hidden[key] if _, exists := fields[key]; !exists && !hidden { fields[key] = value } } return fields } func (model *ProjectModel) Update(fields contracts.Fields) contracts.Exception { if ProjectDefine.Updating != nil { if err := ProjectDefine.Updating(model, fields); err != nil { return err } } if model._update != nil { utils.MergeFields(model._update, fields) } _, err := ProjectQuery().Where("id", model.GetPrimaryKey()).UpdateE(fields) if err == nil { model.Set(fields) model._update = nil if ProjectDefine.Updated != nil { ProjectDefine.Updated(model, fields) } } return err } func (model *ProjectModel) Refresh() contracts.Exception { fields, err := table.ArrayQuery("projects").Where("id", model.GetPrimaryKey()).FirstE() if err != nil { return err } model.Set(*fields) return nil } func (model *ProjectModel) Delete() contracts.Exception { if ProjectDefine.Deleting != nil { if err := ProjectDefine.Deleting(model); err != nil { return err } } _, err := ProjectQuery().Where("id", model.GetPrimaryKey()).DeleteE() if err == nil && ProjectDefine.Deleted != nil { ProjectDefine.Deleted(model) } return err } func (model *ProjectModel) GetPrimaryKey() any { if ProjectDefine.PrimaryKeyGetter != nil { return ProjectDefine.PrimaryKeyGetter(model) } return model.Id } func (model *ProjectModel) GetId() int64 { if ProjectDefine.IdGetter != nil { return ProjectDefine.IdGetter(model, model.Id) } return model.Id } func (model *ProjectModel) SetId(value int64) { if ProjectDefine.IdSetter != nil { value = ProjectDefine.IdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"id": value} } else { model._update["id"] = value } model.Id = value } func (model *ProjectModel) GetUuid() string { if ProjectDefine.UuidGetter != nil { return ProjectDefine.UuidGetter(model, model.Uuid) } return model.Uuid } func (model *ProjectModel) SetUuid(value string) { if ProjectDefine.UuidSetter != nil { value = ProjectDefine.UuidSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"uuid": value} } else { model._update["uuid"] = value } model.Uuid = value } func (model *ProjectModel) GetName() string { if ProjectDefine.NameGetter != nil { return ProjectDefine.NameGetter(model, model.Name) } return model.Name } func (model *ProjectModel) SetName(value string) { if ProjectDefine.NameSetter != nil { value = ProjectDefine.NameSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"name": value} } else { model._update["name"] = value } model.Name = value } func (model *ProjectModel) GetCreatorId() int64 { if ProjectDefine.CreatorIdGetter != nil { return ProjectDefine.CreatorIdGetter(model, model.CreatorId) } return model.CreatorId } func (model *ProjectModel) SetCreatorId(value int64) { if ProjectDefine.CreatorIdSetter != nil { value = ProjectDefine.CreatorIdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"creator_id": value} } else { model._update["creator_id"] = value } model.CreatorId = value } func (model *ProjectModel) GetGroupId() int64 { if ProjectDefine.GroupIdGetter != nil { return ProjectDefine.GroupIdGetter(model, model.GroupId) } return model.GroupId } func (model *ProjectModel) SetGroupId(value int64) { if ProjectDefine.GroupIdSetter != nil { value = ProjectDefine.GroupIdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"group_id": value} } else { model._update["group_id"] = value } model.GroupId = value } func (model *ProjectModel) GetKeyId() int64 { if ProjectDefine.KeyIdGetter != nil { return ProjectDefine.KeyIdGetter(model, model.KeyId) } return model.KeyId } func (model *ProjectModel) SetKeyId(value int64) { if ProjectDefine.KeyIdSetter != nil { value = ProjectDefine.KeyIdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"key_id": value} } else { model._update["key_id"] = value } model.KeyId = value } func (model *ProjectModel) GetRepoAddress() string { if ProjectDefine.RepoAddressGetter != nil { return ProjectDefine.RepoAddressGetter(model, model.RepoAddress) } return model.RepoAddress } func (model *ProjectModel) SetRepoAddress(value string) { if ProjectDefine.RepoAddressSetter != nil { value = ProjectDefine.RepoAddressSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"repo_address": value} } else { model._update["repo_address"] = value } model.RepoAddress = value } func (model *ProjectModel) GetProjectPath() string { if ProjectDefine.ProjectPathGetter != nil { return ProjectDefine.ProjectPathGetter(model, model.ProjectPath) } return model.ProjectPath } func (model *ProjectModel) SetProjectPath(value string) { if ProjectDefine.ProjectPathSetter != nil { value = ProjectDefine.ProjectPathSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"project_path": value} } else { model._update["project_path"] = value } model.ProjectPath = value } func (model *ProjectModel) GetDefaultBranch() string { if ProjectDefine.DefaultBranchGetter != nil { return ProjectDefine.DefaultBranchGetter(model, model.DefaultBranch) } return model.DefaultBranch } func (model *ProjectModel) SetDefaultBranch(value string) { if ProjectDefine.DefaultBranchSetter != nil { value = ProjectDefine.DefaultBranchSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"default_branch": value} } else { model._update["default_branch"] = value } model.DefaultBranch = value } func (model *ProjectModel) GetSettings() string { if ProjectDefine.SettingsGetter != nil { return ProjectDefine.SettingsGetter(model, model.Settings) } return model.Settings } func (model *ProjectModel) SetSettings(value string) { if ProjectDefine.SettingsSetter != nil { value = ProjectDefine.SettingsSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"settings": value} } else { model._update["settings"] = value } model.Settings = value } func (model *ProjectModel) GetCreatedAt() string { if ProjectDefine.CreatedAtGetter != nil { return ProjectDefine.CreatedAtGetter(model, model.CreatedAt) } return model.CreatedAt } func (model *ProjectModel) SetCreatedAt(value string) { if ProjectDefine.CreatedAtSetter != nil { value = ProjectDefine.CreatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"created_at": value} } else { model._update["created_at"] = value } model.CreatedAt = value } func (model *ProjectModel) GetUpdatedAt() string { if ProjectDefine.UpdatedAtGetter != nil { return ProjectDefine.UpdatedAtGetter(model, model.UpdatedAt) } return model.UpdatedAt } func (model *ProjectModel) SetUpdatedAt(value string) { if ProjectDefine.UpdatedAtSetter != nil { value = ProjectDefine.UpdatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"updated_at": value} } else { model._update["updated_at"] = value } model.UpdatedAt = value } ================================================ FILE: app/models/User_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package models import ( "encoding/json" "fmt" "github.com/goal-web/collection" "github.com/goal-web/contracts" "github.com/goal-web/database/table" user "github.com/goal-web/goal/app/models/user" "github.com/goal-web/migration/migrate" "github.com/goal-web/supports/logs" "github.com/goal-web/supports/utils" "github.com/spf13/cast" ) var () // UserModel // 用户注释 // @authenticatable // @timestamps type UserModel struct { Id int64 `json:"id" query:"id" form:"id" db:"id;type:BIGINT;not null;primary key;AUTO_INCREMENT;"` Name string `json:"name" query:"name" form:"name" db:"name;type:VARCHAR(255);not null;"` Avatar string `json:"avatar" query:"avatar" form:"avatar" db:"avatar;type:VARCHAR(255);not null;"` //@index //@goTag:db:"open_id;type:varchar(255);default 'xxasdasdsx'" OpenId string `db:"open_id;type:varchar(255);default 'xxasdasdsx'" json:"open_id" query:"open_id" form:"open_id"` WechatInfo *user.WechatInfoData `json:"wechat_info" query:"wechat_info" form:"wechat_info" db:"wechat_info;type:json;not null;"` Channel string `json:"channel" query:"channel" form:"channel" db:"channel;type:VARCHAR(255);not null;"` //@hidden Password string `json:"password" query:"password" form:"password" db:"password;type:VARCHAR(255);not null;"` CreatedAt string `json:"created_at" query:"created_at" form:"created_at" db:"created_at;type:timestamp;default CURRENT_TIMESTAMP;"` UpdatedAt string `json:"updated_at" query:"updated_at" form:"updated_at" db:"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;"` _raw contracts.Fields _update contracts.Fields _append contracts.Fields _hidden map[string]struct{} _relation_loaded map[contracts.RelationType]struct{} } var UserDefine UserStatic type UserStatic struct { TableName string Hidden []string Indexes []string With []contracts.RelationType Appends map[string]func(model *UserModel) any IdGetter func(model *UserModel, raw int64) int64 IdSetter func(model *UserModel, raw int64) int64 NameGetter func(model *UserModel, raw string) string NameSetter func(model *UserModel, raw string) string AvatarGetter func(model *UserModel, raw string) string AvatarSetter func(model *UserModel, raw string) string OpenIdGetter func(model *UserModel, raw string) string OpenIdSetter func(model *UserModel, raw string) string WechatInfoGetter func(model *UserModel, raw *user.WechatInfoData) *user.WechatInfoData WechatInfoSetter func(model *UserModel, raw *user.WechatInfoData) *user.WechatInfoData ChannelGetter func(model *UserModel, raw string) string ChannelSetter func(model *UserModel, raw string) string PasswordGetter func(model *UserModel, raw string) string PasswordSetter func(model *UserModel, raw string) string CreatedAtGetter func(model *UserModel, raw string) string CreatedAtSetter func(model *UserModel, raw string) string UpdatedAtGetter func(model *UserModel, raw string) string UpdatedAtSetter func(model *UserModel, raw string) string Saving func(model *UserModel) contracts.Exception Saved func(model *UserModel) Updating func(model *UserModel, fields contracts.Fields) contracts.Exception Updated func(model *UserModel, fields contracts.Fields) Deleting func(model *UserModel) contracts.Exception Deleted func(model *UserModel) PrimaryKeyGetter func(model *UserModel) any } func UserMigrator() migrate.Migrator { return func(executor contracts.SqlExecutor) contracts.Exception { return migrate.Migrate(UserDefine.TableName, UserDefine.Indexes, UserModel{}, executor) } } func init() { UserDefine.TableName = "users" UserDefine.Appends = make(map[string]func(model *UserModel) any) UserDefine.Hidden = append( UserDefine.Hidden, "password", ) UserDefine.Indexes = append( UserDefine.Indexes, "index;open_id_idx;(open_id)", ) } func NewUserModel(fields contracts.Fields) *UserModel { var model = UserModel{ _raw: fields, } model.Set(fields) return &model } func UserModelSingleRelationSetter[T any](key contracts.RelationType) func(item *UserModel, value []any) { return func(item *UserModel, values []any) { var value T if len(values) > 0 { value = values[0].(T) } item.Set(contracts.Fields{ string(key): value, }) } } func UserModelMultiRelationSetter[T any](key contracts.RelationType) func(item *UserModel, value []any) { return func(model *UserModel, value []any) { var results []T for _, item := range value { results = append(results, item.(T)) } model.Set(contracts.Fields{string(key): results}) } } func UserModelLocalKeyGetter(key string) func(item *UserModel) any { return func(item *UserModel) any { return item.Get(key) } } func UserModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} for key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) { results[key] = collection.New(values).ToAnyArray() } return results } } func UserModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} groupKey := fmt.Sprintf("%s.%s", midTable, firstKey) for key, values := range query(). AddSelect(fmt.Sprintf("(%s) as _group_key", groupKey)). WhereIn(groupKey, keys). Join(midTable, fmt.Sprintf("%s.%s", midTable, secondLocalKey), "=", fmt.Sprintf("%s.%s", query().GetTableName(), secondKey)). Get().GroupBy("_group_key") { results[key] = collection.New(values).ToAnyArray() } return results } } func UserQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[UserModel] { return UserQuery().SetExecutor(executor) } func UserQuery() *table.Table[UserModel] { return table.NewQuery(UserDefine.TableName, NewUserModel). SetPrimaryKey("id"). SetCreatedTimeColumn("created_at"). SetUpdatedTimeColumn("updated_at"). SetWiths(UserDefine.With...) } func (model *UserModel) Hidden(fields ...string) *UserModel { for _, field := range fields { if model._hidden == nil { model._hidden = map[string]struct{}{ field: struct{}{}, } } else { model._hidden[field] = struct{}{} } } return model } func (model *UserModel) Exists() bool { return UserQuery().Where("id", model.GetPrimaryKey()).Count() > 0 } func (model *UserModel) Save() contracts.Exception { if model._update == nil { return nil } if UserDefine.Saving != nil { if err := UserDefine.Saving(model); err != nil { return err } } var err contracts.Exception var pk = model.GetPrimaryKey() if cast.ToUint64(pk) == 0 { pk, err = UserQuery().Where("id", model.GetPrimaryKey()).InsertGetIdE(model._update) if err == nil { model.SetId(cast.ToInt64(pk)) } } else { _, err = UserQuery().Where("id", model.GetPrimaryKey()).UpdateE(model._update) } if err == nil { model._update = nil if UserDefine.Saved != nil { UserDefine.Saved(model) } } return err } func (model *UserModel) Set(fields contracts.Fields) { for key, value := range fields { switch key { case "id": switch v := value.(type) { case int64: model.SetId(v) case func() int64: model.SetId(v()) case string: var vd int64 err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) case []byte: var vd int64 err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetId(vd) default: model.SetId(cast.ToInt64(v)) } case "name": switch v := value.(type) { case string: model.SetName(v) case func() string: model.SetName(v()) case []byte: model.SetName(string(v)) default: model.SetName(cast.ToString(v)) } case "avatar": switch v := value.(type) { case string: model.SetAvatar(v) case func() string: model.SetAvatar(v()) case []byte: model.SetAvatar(string(v)) default: model.SetAvatar(cast.ToString(v)) } case "open_id": switch v := value.(type) { case string: model.SetOpenId(v) case func() string: model.SetOpenId(v()) case []byte: model.SetOpenId(string(v)) default: model.SetOpenId(cast.ToString(v)) } case "wechat_info": switch v := value.(type) { case *user.WechatInfoData: model.SetWechatInfo(v) case func() *user.WechatInfoData: model.SetWechatInfo(v()) case string: var vd *user.WechatInfoData err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetWechatInfo(vd) case []byte: var vd *user.WechatInfoData err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field " + key) continue } model.SetWechatInfo(vd) } case "channel": switch v := value.(type) { case string: model.SetChannel(v) case func() string: model.SetChannel(v()) case []byte: model.SetChannel(string(v)) default: model.SetChannel(cast.ToString(v)) } case "password": switch v := value.(type) { case string: model.SetPassword(v) case func() string: model.SetPassword(v()) case []byte: model.SetPassword(string(v)) default: model.SetPassword(cast.ToString(v)) } case "created_at": switch v := value.(type) { case string: model.SetCreatedAt(v) case func() string: model.SetCreatedAt(v()) case []byte: model.SetCreatedAt(string(v)) default: model.SetCreatedAt(cast.ToString(v)) } case "updated_at": switch v := value.(type) { case string: model.SetUpdatedAt(v) case func() string: model.SetUpdatedAt(v()) case []byte: model.SetUpdatedAt(string(v)) default: model.SetUpdatedAt(cast.ToString(v)) } } } } func (model *UserModel) Only(key ...string) contracts.Fields { var fields = make(contracts.Fields) for _, k := range key { if k == "id" { fields[k] = model.GetId() continue } if k == "name" { fields[k] = model.GetName() continue } if k == "avatar" { fields[k] = model.GetAvatar() continue } if k == "open_id" { fields[k] = model.GetOpenId() continue } if k == "wechat_info" { fields[k] = model.GetWechatInfo() continue } if k == "channel" { fields[k] = model.GetChannel() continue } if k == "password" { fields[k] = model.GetPassword() continue } if k == "created_at" { fields[k] = model.GetCreatedAt() continue } if k == "updated_at" { fields[k] = model.GetUpdatedAt() continue } if UserDefine.Appends[k] != nil { fields[k] = UserDefine.Appends[k](model) } } return fields } func (model *UserModel) Get(key string) any { switch key { case "id": return model.GetId() case "name": return model.GetName() case "avatar": return model.GetAvatar() case "open_id": return model.GetOpenId() case "wechat_info": return model.GetWechatInfo() case "channel": return model.GetChannel() case "password": return model.GetPassword() case "created_at": return model.GetCreatedAt() case "updated_at": return model.GetUpdatedAt() } if value, exists := model._append[key]; exists { return value } if fn, exists := UserDefine.Appends[key]; exists { model._append[key] = fn(model) return model._append[key] } switch contracts.RelationType(key) { } return nil } func (model *UserModel) Except(keys ...string) contracts.Fields { var excepts = map[string]struct{}{} for _, k := range keys { excepts[k] = struct{}{} } var fields = make(contracts.Fields) for key, value := range model.ToFields() { if _, ok := excepts[key]; ok { continue } fields[key] = value } return fields } func (model *UserModel) ToFields() contracts.Fields { if model == nil { return nil } model.Hidden(UserDefine.Hidden...) fields := contracts.Fields{} if _, exists := model._hidden["id"]; !exists { fields["id"] = model.GetId() } if _, exists := model._hidden["name"]; !exists { fields["name"] = model.GetName() } if _, exists := model._hidden["avatar"]; !exists { fields["avatar"] = model.GetAvatar() } if _, exists := model._hidden["open_id"]; !exists { fields["open_id"] = model.GetOpenId() } if _, exists := model._hidden["wechat_info"]; !exists { fields["wechat_info"] = model.GetWechatInfo() } if _, exists := model._hidden["channel"]; !exists { fields["channel"] = model.GetChannel() } if _, exists := model._hidden["password"]; !exists { fields["password"] = model.GetPassword() } if _, exists := model._hidden["created_at"]; !exists { fields["created_at"] = model.GetCreatedAt() } if _, exists := model._hidden["updated_at"]; !exists { fields["updated_at"] = model.GetUpdatedAt() } for key := range UserDefine.Appends { value := model.Get(key) if fieldsProvider, ok := value.(contracts.FieldsProvider); ok { fields[key] = fieldsProvider.ToFields() } else { fields[key] = value } } for key := range model._relation_loaded { switch key { } } for key, value := range model._raw { _, hidden := model._hidden[key] if _, exists := fields[key]; !exists && !hidden { fields[key] = value } } return fields } func (model *UserModel) Update(fields contracts.Fields) contracts.Exception { if UserDefine.Updating != nil { if err := UserDefine.Updating(model, fields); err != nil { return err } } if model._update != nil { utils.MergeFields(model._update, fields) } _, err := UserQuery().Where("id", model.GetPrimaryKey()).UpdateE(fields) if err == nil { model.Set(fields) model._update = nil if UserDefine.Updated != nil { UserDefine.Updated(model, fields) } } return err } func (model *UserModel) Refresh() contracts.Exception { fields, err := table.ArrayQuery("users").Where("id", model.GetPrimaryKey()).FirstE() if err != nil { return err } model.Set(*fields) return nil } func (model *UserModel) Delete() contracts.Exception { if UserDefine.Deleting != nil { if err := UserDefine.Deleting(model); err != nil { return err } } _, err := UserQuery().Where("id", model.GetPrimaryKey()).DeleteE() if err == nil && UserDefine.Deleted != nil { UserDefine.Deleted(model) } return err } func (model *UserModel) GetPrimaryKey() any { if UserDefine.PrimaryKeyGetter != nil { return UserDefine.PrimaryKeyGetter(model) } return model.Id } func (model *UserModel) GetAuthenticatableKey() string { return fmt.Sprintf("%v", model.GetPrimaryKey()) } func UserAuthProvider(identify string) contracts.Authenticatable { return UserQuery().Find(identify) } func (model *UserModel) GetId() int64 { if UserDefine.IdGetter != nil { return UserDefine.IdGetter(model, model.Id) } return model.Id } func (model *UserModel) SetId(value int64) { if UserDefine.IdSetter != nil { value = UserDefine.IdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"id": value} } else { model._update["id"] = value } model.Id = value } func (model *UserModel) GetName() string { if UserDefine.NameGetter != nil { return UserDefine.NameGetter(model, model.Name) } return model.Name } func (model *UserModel) SetName(value string) { if UserDefine.NameSetter != nil { value = UserDefine.NameSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"name": value} } else { model._update["name"] = value } model.Name = value } func (model *UserModel) GetAvatar() string { if UserDefine.AvatarGetter != nil { return UserDefine.AvatarGetter(model, model.Avatar) } return model.Avatar } func (model *UserModel) SetAvatar(value string) { if UserDefine.AvatarSetter != nil { value = UserDefine.AvatarSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"avatar": value} } else { model._update["avatar"] = value } model.Avatar = value } func (model *UserModel) GetOpenId() string { if UserDefine.OpenIdGetter != nil { return UserDefine.OpenIdGetter(model, model.OpenId) } return model.OpenId } func (model *UserModel) SetOpenId(value string) { if UserDefine.OpenIdSetter != nil { value = UserDefine.OpenIdSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"open_id": value} } else { model._update["open_id"] = value } model.OpenId = value } func (model *UserModel) GetWechatInfo() *user.WechatInfoData { if UserDefine.WechatInfoGetter != nil { return UserDefine.WechatInfoGetter(model, model.WechatInfo) } return model.WechatInfo } func (model *UserModel) SetWechatInfo(value *user.WechatInfoData) { if UserDefine.WechatInfoSetter != nil { value = UserDefine.WechatInfoSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"wechat_info": value} } else { model._update["wechat_info"] = value } model.WechatInfo = value } func (model *UserModel) GetChannel() string { if UserDefine.ChannelGetter != nil { return UserDefine.ChannelGetter(model, model.Channel) } return model.Channel } func (model *UserModel) SetChannel(value string) { if UserDefine.ChannelSetter != nil { value = UserDefine.ChannelSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"channel": value} } else { model._update["channel"] = value } model.Channel = value } func (model *UserModel) GetPassword() string { if UserDefine.PasswordGetter != nil { return UserDefine.PasswordGetter(model, model.Password) } return model.Password } func (model *UserModel) SetPassword(value string) { if UserDefine.PasswordSetter != nil { value = UserDefine.PasswordSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"password": value} } else { model._update["password"] = value } model.Password = value } func (model *UserModel) GetCreatedAt() string { if UserDefine.CreatedAtGetter != nil { return UserDefine.CreatedAtGetter(model, model.CreatedAt) } return model.CreatedAt } func (model *UserModel) SetCreatedAt(value string) { if UserDefine.CreatedAtSetter != nil { value = UserDefine.CreatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"created_at": value} } else { model._update["created_at"] = value } model.CreatedAt = value } func (model *UserModel) GetUpdatedAt() string { if UserDefine.UpdatedAtGetter != nil { return UserDefine.UpdatedAtGetter(model, model.UpdatedAt) } return model.UpdatedAt } func (model *UserModel) SetUpdatedAt(value string) { if UserDefine.UpdatedAtSetter != nil { value = UserDefine.UpdatedAtSetter(model, value) } if model._update == nil { model._update = contracts.Fields{"updated_at": value} } else { model._update["updated_at"] = value } model.UpdatedAt = value } ================================================ FILE: app/models/project/GetProjectRessult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:21:38 // source: pro/Project.proto // package project import ( models "github.com/goal-web/goal/app/models" ) type GetProjectRessult struct { Project models.ProjectModel `json:"project" query:"project" form:"project"` } ================================================ FILE: app/models/project.go ================================================ package models func init() { ProjectDefine.Appends = map[string]func(model *ProjectModel) any{ "id-plus-1": func(model *ProjectModel) any { return model.Id + 0 }, } } ================================================ FILE: app/models/user/WechatInfoData_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import () type WechatInfoData struct { City string `json:"city" query:"city" form:"city"` Gender int64 `json:"gender" query:"gender" form:"gender"` OpenId string `json:"open_id" query:"open_id" form:"open_id"` Country string `json:"country" query:"country" form:"country"` Language string `json:"language" query:"language" form:"language"` Nickname string `json:"nickname" query:"nickname" form:"nickname"` Province string `json:"province" query:"province" form:"province"` AvatarUrl string `json:"avatar_url" query:"avatar_url" form:"avatar_url"` } ================================================ FILE: app/providers/app.go ================================================ package providers import ( "github.com/goal-web/application" "github.com/goal-web/contracts" "github.com/goal-web/goal/app/console" "github.com/goal-web/goal/app/models" "github.com/goal-web/migration/migrate" "github.com/golang-module/carbon/v2" ) type appServiceProvider struct { serviceProviders []contracts.ServiceProvider } func NewApp() contracts.ServiceProvider { return &appServiceProvider{ serviceProviders: []contracts.ServiceProvider{ NewConsoleService( console.Commands, console.Schedule, ), }, } } func (app appServiceProvider) Register(instance contracts.Application) { instance.RegisterServices(app.serviceProviders...) instance.Call(func(config contracts.Config, dispatcher contracts.EventDispatcher, factory contracts.DBFactory) { appConfig := config.Get("app").(application.Config) carbon.SetLocale(appConfig.Locale) carbon.SetTimezone(appConfig.Timezone) instance.Instance("app.env", appConfig.Env) migrate.Auto( factory, models.UserMigrator(), models.ProjectMigrator(), ) }) } func (app appServiceProvider) Start() error { return nil } func (app appServiceProvider) Stop() { } ================================================ FILE: app/providers/console.go ================================================ package providers import ( "github.com/goal-web/contracts" ) type Console struct { Commands []contracts.CommandProvider Schedule func(schedule contracts.Schedule) } func NewConsoleService(commands []contracts.CommandProvider, schedule func(schedule2 contracts.Schedule)) contracts.ServiceProvider { return Console{ Commands: commands, Schedule: schedule, } } func (c Console) Register(application contracts.Application) { application.Call(func(console contracts.Console, schedule contracts.Schedule) { for _, provider := range c.Commands { console.RegisterCommand(provider) } c.Schedule(schedule) }) } func (c Console) Start() error { return nil } func (c Console) Stop() { } ================================================ FILE: app/providers/events.go ================================================ package providers import ( "github.com/goal-web/contracts" events2 "github.com/goal-web/database/events" "github.com/goal-web/goal/app/listeners" ) type EventsServiceProvider struct { listeners map[contracts.Event][]contracts.EventListener } func NewEvents() contracts.ServiceProvider { return &EventsServiceProvider{ listeners: map[contracts.Event][]contracts.EventListener{ &events2.QueryExecuted{}: {listeners.DebugQuery{}}, }, } } func (provider EventsServiceProvider) Stop() { } func (provider EventsServiceProvider) Start() error { return nil } func (provider EventsServiceProvider) Register(container contracts.Application) { container.Call(func(dispatcher contracts.EventDispatcher) { for event, items := range provider.listeners { for _, listener := range items { dispatcher.Register(event.Event(), listener) } } }) } ================================================ FILE: app/requests/project/CreateProject_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type CreateProjectReq struct { Uuid string `json:"uuid" query:"uuid" form:"uuid"` Name string `json:"name" query:"name" form:"name"` CreatorId int64 `json:"creator_id" query:"creator_id" form:"creator_id"` GroupId int64 `json:"group_id" query:"group_id" form:"group_id"` KeyId int64 `json:"key_id" query:"key_id" form:"key_id"` RepoAddress string `json:"repo_address" query:"repo_address" form:"repo_address"` ProjectPath string `json:"project_path" query:"project_path" form:"project_path"` DefaultBranch string `json:"default_branch" query:"default_branch" form:"default_branch"` Settings string `json:"settings" query:"settings" form:"settings"` } func (model *CreateProjectReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "uuid": model.Uuid, "name": model.Name, "creator_id": model.CreatorId, "group_id": model.GroupId, "key_id": model.KeyId, "repo_address": model.RepoAddress, "project_path": model.ProjectPath, "default_branch": model.DefaultBranch, "settings": model.Settings, } return fields } ================================================ FILE: app/requests/project/DeleteProject_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type DeleteProjectReq struct { Id string `json:"id" query:"id" form:"id"` } func (model *DeleteProjectReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "id": model.Id, } return fields } ================================================ FILE: app/requests/project/GetProject_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type GetProjectReq struct { Id string `json:"id" query:"id" form:"id"` } func (model *GetProjectReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "id": model.Id, } return fields } ================================================ FILE: app/requests/project/ListProjects_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type ListProjectsReq struct { Page int64 `json:"page" query:"page" form:"page"` PerPage int64 `json:"per_page" query:"per_page" form:"per_page"` } func (model *ListProjectsReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "page": model.Page, "per_page": model.PerPage, } return fields } ================================================ FILE: app/requests/project/UpdateProject_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type UpdateProjectReq struct { Id int64 `json:"id" query:"id" form:"id"` Uuid string `json:"uuid" query:"uuid" form:"uuid"` Name string `json:"name" query:"name" form:"name"` CreatorId int64 `json:"creator_id" query:"creator_id" form:"creator_id"` GroupId int64 `json:"group_id" query:"group_id" form:"group_id"` KeyId int64 `json:"key_id" query:"key_id" form:"key_id"` RepoAddress string `json:"repo_address" query:"repo_address" form:"repo_address"` ProjectPath string `json:"project_path" query:"project_path" form:"project_path"` DefaultBranch string `json:"default_branch" query:"default_branch" form:"default_branch"` Settings string `json:"settings" query:"settings" form:"settings"` } func (model *UpdateProjectReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "id": model.Id, "uuid": model.Uuid, "name": model.Name, "creator_id": model.CreatorId, "group_id": model.GroupId, "key_id": model.KeyId, "repo_address": model.RepoAddress, "project_path": model.ProjectPath, "default_branch": model.DefaultBranch, "settings": model.Settings, } return fields } ================================================ FILE: app/requests/user/LoginByWxCode_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import ( "github.com/goal-web/contracts" ) type LoginByWxCodeReq struct { Code string `json:"code" query:"code" form:"code"` } func (model *LoginByWxCodeReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "code": model.Code, } return fields } ================================================ FILE: app/requests/user/LoginByWxInfo_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import ( "github.com/goal-web/contracts" ) type LoginByWxInfoReq struct { Iv string `json:"iv" query:"iv" form:"iv"` SessionKey string `json:"sessionKey" query:"sessionKey" form:"sessionKey"` EncryptedData string `json:"encryptedData" query:"encryptedData" form:"encryptedData"` } func (model *LoginByWxInfoReq) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ "iv": model.Iv, "sessionKey": model.SessionKey, "encryptedData": model.EncryptedData, } return fields } ================================================ FILE: app/response/utils.go ================================================ package response import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/app/enums" "github.com/goal-web/goal/app/results" ) func ParseReqErr(err error) any { return results.ResponseResult{ Message: err.Error(), Code: int32(enums.CodeParseReqErr), ErrMessage: enums.CodeParseReqErr.Message(), Data: nil, } } func InvalidReq(err error) any { return results.ResponseResult{ Message: err.Error(), Code: int32(enums.CodeParseReqErr), ErrMessage: enums.CodeParseReqErr.Message(), Data: nil, } } func BizErr(err error) any { return results.ResponseResult{ Message: err.Error(), Code: int32(enums.CodeBizErr), ErrMessage: enums.CodeBizErr.Message(), Data: nil, } } func Success(data any) any { result := results.ResponseResult{ Message: "", Code: int32(enums.CodeSuccess), ErrMessage: enums.CodeSuccess.Message(), } if fieldsProvider, ok := data.(contracts.FieldsProvider); ok { result.Data = fieldsProvider.ToFields() } else { result.Data = data } return result } ================================================ FILE: app/results/ResponseResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/common.proto // package results import ( "github.com/goal-web/contracts" ) type ResponseResult struct { Code int32 `json:"code" query:"code" form:"code"` ErrMessage string `json:"err_message" query:"err_message" form:"err_message"` Message string `json:"message" query:"message" form:"message"` Data any `json:"data" query:"data" form:"data"` } func (result *ResponseResult) ToFields() contracts.Fields { fields := contracts.Fields{ "code": result.Code, "err_message": result.ErrMessage, "message": result.Message, "data": result.Data, } return fields } ================================================ FILE: app/results/project/CreateProjectResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type CreateProjectResult struct { Code string `json:"code" query:"code" form:"code"` } func (result *CreateProjectResult) ToFields() contracts.Fields { fields := contracts.Fields{ "code": result.Code, } return fields } ================================================ FILE: app/results/project/DeleteProjectResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type DeleteProjectResult struct { Code string `json:"code" query:"code" form:"code"` } func (result *DeleteProjectResult) ToFields() contracts.Fields { fields := contracts.Fields{ "code": result.Code, } return fields } ================================================ FILE: app/results/project/GetProjectResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" models "github.com/goal-web/goal/app/models" ) type GetProjectResult struct { Project models.ProjectModel `json:"project" query:"project" form:"project"` } func (result *GetProjectResult) ToFields() contracts.Fields { fields := contracts.Fields{ "project": result.Project, } return fields } ================================================ FILE: app/results/project/ListProjectsResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" models "github.com/goal-web/goal/app/models" ) type ListProjectsResult struct { Total int64 `json:"total" query:"total" form:"total"` Projects []*models.ProjectModel `json:"projects" query:"projects" form:"projects"` } func (result *ListProjectsResult) ToFields() contracts.Fields { fields := contracts.Fields{ "total": result.Total, "projects": result.Projects, } projectsList := make([]contracts.Fields, len(result.Projects)) for i, item := range result.Projects { projectsList[i] = item.ToFields() } fields["projects"] = projectsList return fields } ================================================ FILE: app/results/project/UpdateProjectResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" ) type UpdateProjectResult struct { Code string `json:"code" query:"code" form:"code"` } func (result *UpdateProjectResult) ToFields() contracts.Fields { fields := contracts.Fields{ "code": result.Code, } return fields } ================================================ FILE: app/results/user/LoginByWxResult_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import ( "github.com/goal-web/contracts" models "github.com/goal-web/goal/app/models" ) type LoginByWxResult struct { Token string `json:"token" query:"token" form:"token"` User *models.UserModel `json:"user" query:"user" form:"user"` SessionKey string `json:"sessionKey" query:"sessionKey" form:"sessionKey"` } func (result *LoginByWxResult) ToFields() contracts.Fields { fields := contracts.Fields{ "token": result.Token, "user": result.User, "sessionKey": result.SessionKey, } return fields } ================================================ FILE: app/services/project/Project_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/Project.proto // package project import ( "github.com/goal-web/contracts" project "github.com/goal-web/goal/app/requests/project" project0 "github.com/goal-web/goal/app/results/project" ) var ProjectServiceDefine ProjectServiceStatic type ProjectServiceStatic struct { CreateProject func(req *project.CreateProjectReq, ctx contracts.Context) (*project0.CreateProjectResult, error) GetProject func(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error) ListProjects func(req *project.ListProjectsReq, ctx contracts.Context) (*project0.ListProjectsResult, error) UpdateProject func(req *project.UpdateProjectReq, ctx contracts.Context) (*project0.UpdateProjectResult, error) DeleteProject func(req *project.DeleteProjectReq, ctx contracts.Context) (*project0.DeleteProjectResult, error) } func ProjectServiceCreateProject(req *project.CreateProjectReq, ctx contracts.Context) (*project0.CreateProjectResult, error) { if ProjectServiceDefine.CreateProject != nil { return ProjectServiceDefine.CreateProject(req, ctx) } return nil, nil } func ProjectServiceGetProject(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error) { if ProjectServiceDefine.GetProject != nil { return ProjectServiceDefine.GetProject(req, ctx) } return nil, nil } func ProjectServiceListProjects(req *project.ListProjectsReq, ctx contracts.Context) (*project0.ListProjectsResult, error) { if ProjectServiceDefine.ListProjects != nil { return ProjectServiceDefine.ListProjects(req, ctx) } return nil, nil } func ProjectServiceUpdateProject(req *project.UpdateProjectReq, ctx contracts.Context) (*project0.UpdateProjectResult, error) { if ProjectServiceDefine.UpdateProject != nil { return ProjectServiceDefine.UpdateProject(req, ctx) } return nil, nil } func ProjectServiceDeleteProject(req *project.DeleteProjectReq, ctx contracts.Context) (*project0.DeleteProjectResult, error) { if ProjectServiceDefine.DeleteProject != nil { return ProjectServiceDefine.DeleteProject(req, ctx) } return nil, nil } ================================================ FILE: app/services/project/project.go ================================================ package project import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/app/requests/project" project0 "github.com/goal-web/goal/app/results/project" ) func init() { ProjectServiceDefine.GetProject = func(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error) { return &project0.GetProjectResult{ // 查询项目 }, nil } } ================================================ FILE: app/services/user/Auth_gen.go ================================================ // Code generated by goal-cli. DO NOT EDIT. // versions: // goal-cli v0.5.24 // go go1.24.0 // // updated_at: 2025-03-24 20:22:07 // source: pro/user.proto // package user import ( "github.com/goal-web/contracts" user "github.com/goal-web/goal/app/requests/user" user0 "github.com/goal-web/goal/app/results/user" ) var AuthServiceDefine AuthServiceStatic type AuthServiceStatic struct { LoginByWxAppCode func(req *user.LoginByWxCodeReq, ctx contracts.Context) (*user0.LoginByWxResult, error) LoginByWxAppInfo func(req *user.LoginByWxInfoReq, ctx contracts.Context) (*user0.LoginByWxResult, error) } func AuthServiceLoginByWxAppCode(req *user.LoginByWxCodeReq, ctx contracts.Context) (*user0.LoginByWxResult, error) { if AuthServiceDefine.LoginByWxAppCode != nil { return AuthServiceDefine.LoginByWxAppCode(req, ctx) } return nil, nil } func AuthServiceLoginByWxAppInfo(req *user.LoginByWxInfoReq, ctx contracts.Context) (*user0.LoginByWxResult, error) { if AuthServiceDefine.LoginByWxAppInfo != nil { return AuthServiceDefine.LoginByWxAppInfo(req, ctx) } return nil, nil } ================================================ FILE: app/websocket/demo.go ================================================ package websocket import ( "github.com/goal-web/contracts" "github.com/goal-web/supports/logs" ) type DemoController struct { } func (d DemoController) OnConnect(request contracts.HttpRequest, fd uint64) error { // todo: 绑定用户和 fd return nil } func (d DemoController) OnMessage(frame contracts.WebSocketFrame) { logs.Default().Info("received websocket message:" + frame.RawString()) } func (d DemoController) OnClose(fd uint64) { // todo: 解绑 fd } ================================================ FILE: bootstrap/console/main.go ================================================ package main import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/bootstrap/core" ) func main() { app := core.Application() app.Call(func(console3 contracts.Console, input contracts.ConsoleInput) { console3.Run(input) }) } ================================================ FILE: bootstrap/core/application.go ================================================ package core import ( "github.com/goal-web/application" "github.com/goal-web/bloomfilter" "github.com/goal-web/cache" "github.com/goal-web/config" "github.com/goal-web/console" "github.com/goal-web/console/scheduling" "github.com/goal-web/contracts" "github.com/goal-web/database" "github.com/goal-web/email" "github.com/goal-web/encryption" "github.com/goal-web/events" "github.com/goal-web/filesystem" "github.com/goal-web/goal/app/exceptions" "github.com/goal-web/goal/app/providers" config2 "github.com/goal-web/goal/config" "github.com/goal-web/hashing" "github.com/goal-web/http/sse" "github.com/goal-web/http/websocket" "github.com/goal-web/migration" "github.com/goal-web/queue" "github.com/goal-web/ratelimiter" "github.com/goal-web/redis" "github.com/goal-web/routing" "github.com/goal-web/serialization" "github.com/goal-web/supports/utils" "github.com/golang-module/carbon/v2" "os" ) type App struct { QueueWorker bool SchedulingWorker bool } func Application(c ...App) contracts.Application { env := config.NewToml(config.File("env.toml")) app := application.Singleton(env.GetBool("app.debug")) pwd, _ := os.Getwd() app.Instance("pwd", pwd) conf := utils.DefaultValue(c, App{}) // 设置异常处理器 app.Singleton("exceptions.handler", func() contracts.ExceptionHandler { return exceptions.NewHandler() }) app.RegisterServices( config.NewService(env, config2.GetConfigProviders()), hashing.NewService(), encryption.NewService(), filesystem.NewService(), serialization.NewService(), events.NewService(), providers.NewEvents(), redis.NewService(), cache.NewService(), bloomfilter.NewService(), ratelimiter.NewService(), database.NewService(), queue.NewService(conf.QueueWorker), email.NewService(), console.NewService(), scheduling.NewService(conf.SchedulingWorker), migration.NewService(), routing.NewService(), sse.NewService(), websocket.NewService(), ) app.RegisterServices( providers.NewApp(), ) app.Call(func(config contracts.Config, dispatcher contracts.EventDispatcher, console3 contracts.Console) { appConfig := config.Get("app").(application.Config) carbon.SetLocale(appConfig.Locale) carbon.SetTimezone(appConfig.Timezone) }) return app } ================================================ FILE: bootstrap/queue/main.go ================================================ package main import ( "github.com/goal-web/goal/bootstrap/core" "github.com/goal-web/supports/logs" ) func main() { app := core.Application(core.App{ QueueWorker: true, }) if errors := app.Start(); len(errors) > 0 { logs.WithField("errors", errors).Fatal("goal 异常!") } else { logs.Default().Info("goal 已关闭") } } ================================================ FILE: bootstrap/schedule/main.go ================================================ package main import ( "github.com/goal-web/goal/bootstrap/core" "github.com/goal-web/supports/logs" ) func main() { app := core.Application(core.App{ SchedulingWorker: true, }) if errors := app.Start(); len(errors) > 0 { logs.WithField("errors", errors).Fatal("goal 异常!") } else { logs.Default().Info("goal 已关闭") } } ================================================ FILE: config/README_cache_config.md ================================================ # 缓存配置说明 ## 概述 本文档说明了Goal Web框架中缓存组件的配置选项和使用方法。 ## 配置结构 缓存配置支持三种驱动: - **memory**: 内存缓存(RAM驱动) - **file**: 文件缓存 - **redis**: Redis缓存 ## 配置选项 ### 基本配置 ```go cache.Config{ Default: "memory", // 默认缓存驱动 Stores: map[string]contracts.Fields{ // 各种缓存驱动的配置 }, } ``` ### 环境变量 | 环境变量 | 默认值 | 说明 | |----------|--------|------| | `CACHE_DEFAULT` | `memory` | 默认缓存驱动 | | `CACHE_PREFIX` | `""` | 缓存键前缀 | | `CACHE_TTL` | `86400` | 默认缓存TTL(秒) | | `CACHE_FILE_PATH` | `./storage/cache` | 文件缓存路径 | | `CACHE_CONNECTION` | `default` | Redis连接名称 | ## 驱动配置 ### 1. 内存缓存 (memory) ```go "memory": { "driver": "ram", "prefix": env.GetString("cache.prefix"), "ttl": utils.IntOr(env.GetInt("cache.ttl"), 24*int(time.Hour)), } ``` **配置参数:** - `driver`: 固定为 "ram" - `prefix`: 缓存键前缀 - `ttl`: 默认过期时间(秒) **特点:** - 高性能,数据存储在内存中 - 应用重启后数据丢失 - 支持统计和监控功能 ### 2. 文件缓存 (file) ```go "file": { "driver": "file", "path": utils.StringOr(env.GetString("cache.file.path"), "./storage/cache"), "prefix": env.GetString("cache.prefix"), } ``` **配置参数:** - `driver`: 固定为 "file" - `path`: 缓存文件存储路径 - `prefix`: 缓存键前缀 **特点:** - 持久化存储,应用重启后数据保留 - 适合开发环境和小型应用 - 自动创建缓存目录 ### 3. Redis缓存 (redis) ```go "redis": { "driver": "redis", "connection": utils.StringOr(env.GetString("cache.connection"), "default"), "prefix": env.GetString("cache.prefix"), } ``` **配置参数:** - `driver`: 固定为 "redis" - `connection`: Redis连接名称 - `prefix`: 缓存键前缀 **特点:** - 高性能,支持分布式 - 持久化存储 - 支持复杂数据结构 ## 使用示例 ### 1. 基本使用 ```go // 获取默认缓存实例 cache := cache.Store() // 获取指定驱动缓存实例 memoryCache := cache.Store("memory") fileCache := cache.Store("file") redisCache := cache.Store("redis") ``` ### 2. 环境配置 ```bash # 设置环境变量 export CACHE_DEFAULT=memory export CACHE_PREFIX=myapp_ export CACHE_TTL=3600 export CACHE_FILE_PATH=/tmp/cache export CACHE_CONNECTION=redis1 ``` ### 3. 配置文件 ```toml # config.toml [cache] default = "memory" prefix = "myapp_" ttl = 3600 [cache.file] path = "/tmp/cache" [cache.redis] connection = "redis1" ``` ## 配置最佳实践 ### 1. 开发环境 ```go // 使用内存缓存,快速开发 cache.default = "memory" ``` ### 2. 测试环境 ```go // 使用文件缓存,便于调试 cache.default = "file" cache.file.path = "./test_cache" ``` ### 3. 生产环境 ```go // 使用Redis缓存,高性能和可靠性 cache.default = "redis" cache.connection = "production_redis" ``` ### 4. 混合使用 ```go // 不同类型的数据使用不同的缓存 userCache := cache.Store("memory") // 用户会话 configCache := cache.Store("file") // 配置数据 dataCache := cache.Store("redis") // 业务数据 ``` ## 性能考虑 ### 1. 内存缓存 - **优点**: 最高性能,零延迟 - **缺点**: 内存占用,重启丢失 - **适用**: 临时数据,会话缓存 ### 2. 文件缓存 - **优点**: 持久化,简单部署 - **缺点**: 磁盘I/O,性能中等 - **适用**: 配置缓存,开发环境 ### 3. Redis缓存 - **优点**: 高性能,分布式,持久化 - **缺点**: 需要额外服务,网络延迟 - **适用**: 生产环境,大数据量 ## 监控和调试 ### 1. 统计信息 ```go // 获取缓存统计(仅内存缓存支持) if memoryCache, ok := cache.Store("memory").(*drivers.Memory); ok { stats := memoryCache.GetStats() fmt.Printf("命中率: %.2f%%\n", stats["hit_rate"]) fmt.Printf("内存使用: %.2f MB\n", stats["memory_usage"].(map[string]any)["total_mb"]) } ``` ### 2. 键管理 ```go // 获取所有键(仅内存缓存支持) if memoryCache, ok := cache.Store("memory").(*drivers.Memory); ok { keys := memoryCache.GetKeys() fmt.Printf("当前有 %d 个缓存键\n", len(keys)) } ``` ### 3. 清理过期项 ```go // 手动清理过期项(仅内存缓存支持) if memoryCache, ok := cache.Store("memory").(*drivers.Memory); ok { cleaned := memoryCache.CleanupAllExpired() fmt.Printf("清理了 %d 个过期项\n", cleaned) } ``` ## 故障排除 ### 1. 常见问题 **问题**: 缓存不生效 **解决**: 检查驱动名称是否正确,确保缓存服务正常运行 **问题**: 内存使用过高 **解决**: 调整TTL设置,定期清理过期项 **问题**: 文件权限错误 **解决**: 确保缓存目录有写入权限 **问题**: Redis连接失败 **解决**: 检查Redis服务状态和连接配置 ### 2. 调试技巧 ```go // 启用调试日志 logs.SetLevel(logs.DebugLevel) // 检查缓存状态 stats := cache.GetStats() logs.Debug("Cache stats", stats) ``` ## 总结 缓存配置提供了灵活的选项来满足不同场景的需求: 1. **开发环境**: 使用内存缓存,快速迭代 2. **测试环境**: 使用文件缓存,便于调试 3. **生产环境**: 使用Redis缓存,高性能和可靠性 通过合理配置缓存驱动和参数,可以显著提升应用程序的性能和用户体验。 ================================================ FILE: config/app.go ================================================ package config import ( "github.com/goal-web/application" "github.com/goal-web/contracts" ) var configs = make(map[string]contracts.ConfigProvider) func GetConfigProviders() map[string]contracts.ConfigProvider { return configs } func init() { configs["app"] = func(env contracts.Env) any { return application.Config{ Name: env.GetString("app.name"), Debug: env.GetBool("app.debug"), Timezone: env.GetString("app.timezone"), Env: env.GetString("app.env"), Locale: env.GetString("app.locale"), Key: env.GetString("app.key"), } } } ================================================ FILE: config/auth.go ================================================ package config import ( "github.com/goal-web/auth" "github.com/goal-web/contracts" "github.com/goal-web/goal/app/models" "github.com/golang-jwt/jwt" "time" ) func init() { configs["auth"] = func(env contracts.Env) any { return auth.Config{ Defaults: auth.Defaults{ Guard: env.StringOptional("auth.default", "jwt"), User: env.StringOptional("auth.user", "db"), }, Guards: map[string]contracts.Fields{ "jwt": { "driver": "jwt", "secret": env.GetString("auth.jwt.secret"), "method": jwt.SigningMethodHS256, "lifetime": 60 * 60 * 24 * time.Second, "provider": "db", }, "session": { "driver": "session", "provider": "db", "session_key": env.StringOptional("auth.session.key", "auth_session"), }, }, Users: map[string]contracts.Fields{ "db": { "driver": "db", "provider": models.UserAuthProvider, }, }, } } } ================================================ FILE: config/bloomfilter.go ================================================ package config import ( "github.com/goal-web/bloomfilter" "github.com/goal-web/contracts" ) func init() { configs["bloomfilter"] = func(env contracts.Env) any { return bloomfilter.Config{ Default: "default", Filters: bloomfilter.Filters{ "default": contracts.Fields{ "driver": "file", // 将数据序列化到文件中,不支持分布式 "size": 100000, "k": .01, "filepath": "storage/bloomfilter/default", // 完整路径 }, "users": contracts.Fields{ "driver": "redis", // 通过 redis bitmap 存储,支持分布式 "size": 100000, "k": .01, "key": "bloomfilter:{name}", // {name} 表示该 filter 的key,这里是 users //"connection": "cache", // redis 连接 }, }, } } } ================================================ FILE: config/cache.go ================================================ package config import ( "time" "github.com/goal-web/cache" "github.com/goal-web/contracts" "github.com/goal-web/supports/utils" ) func init() { configs["cache"] = func(env contracts.Env) any { return cache.Config{ Default: utils.StringOr(env.GetString("cache.default"), "memory"), Stores: map[string]contracts.Fields{ "memory": { "driver": "ram", "prefix": env.GetString("cache.prefix"), "ttl": utils.IntOr(env.GetInt("cache.ttl"), 24*int(time.Hour)), // 默认缓存生命周期 }, "file": { "driver": "file", "path": utils.StringOr(env.GetString("cache.file.path"), "./storage/cache"), "prefix": env.GetString("cache.prefix"), }, "redis": { "driver": "redis", "connection": utils.StringOr(env.GetString("cache.connection"), "default"), "prefix": env.GetString("cache.prefix"), }, }, } } } ================================================ FILE: config/cache_example.toml ================================================ # 缓存配置示例 # Cache Configuration Example # 默认缓存驱动 cache.default = "memory" # 缓存键前缀 cache.prefix = "goal_" # 默认缓存TTL(秒) cache.ttl = 86400 # 文件缓存配置 cache.file.path = "./storage/cache" # Redis缓存配置 cache.connection = "default" # 环境变量示例 # CACHE_DEFAULT=memory # CACHE_PREFIX=goal_ # CACHE_TTL=86400 # CACHE_FILE_PATH=./storage/cache # CACHE_CONNECTION=default ================================================ FILE: config/database.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/database" "strings" ) func init() { configs["database"] = func(env contracts.Env) any { return database.Config{ Default: env.StringOptional("db.connection", "mysql"), Connections: map[string]contracts.Fields{ "sqlite": { "driver": "sqlite", "database": env.GetString("db.sqlite.database"), }, "mysql": { "driver": "mysql", "host": env.GetString("db.host"), "port": env.GetString("db.port"), "database": env.GetString("db.database"), "username": env.GetString("db.username"), "password": env.GetString("db.password"), "unix_socket": env.GetString("db.unix_socket"), "charset": env.StringOptional("db.charset", "utf8mb4"), "collation": env.StringOptional("db.collation", "utf8mb4_unicode_ci"), "prefix": env.GetString("db.prefix"), "strict": env.GetBool("db.struct"), "max_connections": env.GetInt("db.max_connections"), "max_idles": env.GetInt("db.max_idles"), "other": "&parseTime=true&multiStatements=true", }, "pgsql": { "driver": "postgres", "host": env.GetString("db.pgsql.host"), "port": env.GetString("db.pgsql.port"), "database": env.GetString("db.pgsql.database"), "username": env.GetString("db.pgsql.username"), "password": env.GetString("db.pgsql.password"), "charset": env.StringOptional("db.pgsql.charset", "utf8mb4"), "prefix": env.GetString("db.pgsql.prefix"), "schema": env.StringOptional("db.pgsql.schema", "public"), "sslmode": env.StringOptional("db.pgsql.sslmode", "disable"), "max_connections": env.GetInt("db.pgsql.max_connections"), "max_idles": env.GetInt("db.pgsql.max_idles"), }, "clickhouse": { "driver": "clickhouse", "dsn": env.GetString("db.clickhouse.dsn"), // see https://github.com/ClickHouse/clickhouse-go#dsn "max_connections": env.GetInt("db.clickhouse.max_connections"), "max_idles": env.GetInt("db.clickhouse.max_idles"), "address": strings.Split(env.GetString("db.clickhouse.address"), ","), "database": env.GetString("db.clickhouse.database"), "username": env.GetString("db.clickhouse.username"), "password": env.GetString("db.clickhouse.password"), "debug": env.GetString("db.clickhouse.debug"), }, }, } } } ================================================ FILE: config/encryption.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/encryption" ) func init() { configs["encryption"] = func(env contracts.Env) any { return encryption.Config{ Default: "AES", Drivers: map[string]contracts.EncryptDriver{}, } } } ================================================ FILE: config/filesystem.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/filesystem" "os" ) func init() { configs["filesystem"] = func(env contracts.Env) any { return filesystem.Config{ Default: env.StringOptional("filesystem.disk", "public"), Disks: map[string]contracts.Fields{ "public": { "driver": "local", "root": env.StringOptional("filesystem.root", "storage/app/public"), "perm": os.ModePerm, }, "qiniu": { "driver": "qiniu", "ttl": 3600, // 私有 url 有效期,单位秒 "private": env.GetBool("qiniu.private"), "domain": env.GetBool("qiniu.domain"), // example: https://image.example.com" "bucket": env.GetString("qiniu.bucket"), "access_key": env.GetString("qiniu.access.key"), "secret_key": env.GetString("qiniu.secret.key"), }, }, } } } ================================================ FILE: config/http.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/http" ) func init() { configs["http"] = func(env contracts.Env) any { config := http.Config{ Host: env.GetString("http.host"), Port: env.GetString("http.port"), StaticDirectories: map[string]string{ //"/": "public", }, } if env.GetString("app.env") == "local" { config.StaticDirectories["/"] = "public" } return config } } ================================================ FILE: config/mail.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/email" ) func init() { configs["mail"] = func(env contracts.Env) any { return email.Config{ Default: "default", Mailers: map[string]contracts.Fields{ "default": { "driver": "mailer", //"tls": &tls.Config{InsecureSkipVerify: true}, "from": env.GetString("mail.from"), "host": env.GetString("mail.host"), "port": env.GetString("mail.port"), "username": env.GetString("mail.username"), "password": env.GetString("mail.password"), }, }, } } } ================================================ FILE: config/queue.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/queue" "github.com/nsqio/go-nsq" "strings" ) func init() { configs["queue"] = func(env contracts.Env) any { return queue.Config{ Defaults: queue.Defaults{ Connection: env.StringOptional("queue.connection", "default"), Queue: env.StringOptional("queue.default", "default"), }, Connections: map[string]contracts.Fields{ "default": { "driver": "kafka", "delay": "delay_queue", // 延迟队列名 "brokers": strings.Split(env.GetString("queue.kafka.brokers"), ","), //"dialer": &kafka.Dialer{}, // 自定义 kafka.Dialer "queue": []string{ "default", "slow", "high", }, }, "nsq": { "driver": "nsq", "address": env.GetString("queue.nsq.address"), "lookup_addresses": strings.Split(env.GetString("queue.nsq.lookup_addresses"), ","), "config": &nsq.Config{}, // 自定义 nsq 设置 "queue": []string{ "default", "slow", "high", }, }, "sync": {"driver": "sync"}, "empty": {"driver": "empty"}, "goroutine": {"driver": "goroutine"}, }, Failed: queue.FailedJobs{ Database: env.StringOptional("db.connection", "mysql"), Table: "failed_jobs", }, Workers: map[string]queue.Workers{ // 相当于 laravel 的 horizon 配置 "local": { // 本地环境 "default": { // 工作组 Connection: env.StringOptional("queue.connection", "default"), // 指定连接 Tries: 3, // 最大尝试次数 Queue: []string{"default", "slow", "high"}, // 处理指定队列 Processes: 10, // 十个协程(工人) }, }, "production": { // 生产环境 }, }, } } } ================================================ FILE: config/redis.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/redis" "github.com/goal-web/supports/utils" ) func init() { configs["redis"] = func(env contracts.Env) any { return redis.Config{ Default: utils.StringOr(env.GetString("redis.default"), "default"), Stores: map[string]contracts.Fields{ "default": { "network": env.GetString("redis.network"), "host": env.GetString("redis.host"), "port": env.GetString("redis.port"), "username": env.GetString("redis.username"), "password": env.GetString("redis.password"), "db": env.GetInt64("redis.db"), "retries": env.GetInt64("redis.retries"), }, "cache": { "network": env.GetString("redis.cache.network"), "host": env.GetString("redis.cache.host"), "port": env.GetString("redis.cache.port"), "username": env.GetString("redis.cache.username"), "password": env.GetString("redis.cache.password"), "db": env.GetInt64("redis.cache.db"), "retries": env.GetInt64("redis.cache.retries"), }, }, } } } ================================================ FILE: config/serialization.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/app/jobs" "github.com/goal-web/serialization" ) func init() { configs["serialization"] = func(env contracts.Env) any { return serialization.Config{ Default: "json", // 支持:json、gob、xml。 Class: []contracts.Class[any]{ // 需要序列化的类 jobs.DemoClass, }, } } } ================================================ FILE: config/session.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/session" "time" ) func init() { configs["session"] = func(env contracts.Env) any { return session.Config{ Driver: "redis", // 目前支持 cookie、redis Encrypt: true, Domain: env.GetString("session.domain"), Lifetime: time.Duration(env.GetInt("session.lifetime")), Connection: "default", // database、redis 用到 Key: "goal_session:%s", // redis 驱动所用到的 key Table: "sessions", // database 用到 Name: env.StringOptional("session.name", "goal"), } } } ================================================ FILE: config/views.go ================================================ package config import ( "github.com/goal-web/contracts" "github.com/goal-web/views" ) func init() { configs["views"] = func(env contracts.Env) any { return views.Config{ Path: env.StringOptional("views.path", "views"), } } } ================================================ FILE: config/websocket.go ================================================ package config import ( websocket2 "github.com/fasthttp/websocket" "github.com/goal-web/contracts" "github.com/goal-web/http/websocket" ) func init() { configs["websocket"] = func(env contracts.Env) any { return websocket.Config{ Upgrader: websocket2.FastHTTPUpgrader{ HandshakeTimeout: 5, //ReadBufferSize: 0, //WriteBufferSize: 0, //WriteBufferPool: nil, //Subprotocols: nil, //Error: nil, //CheckOrigin: nil, //EnableCompression: false, }, } } } ================================================ FILE: database/.gitignore ================================================ ================================================ FILE: database/migrations/2024_05_09_141932_create_articles.down.sql ================================================ drop table if exists articles ================================================ FILE: database/migrations/2024_05_09_141932_create_articles.sql ================================================ CREATE TABLE IF NOT EXISTS articles ( `id` INT UNSIGNED AUTO_INCREMENT, title varchar(20) not null, created_at timestamp, updated_at timestamp, PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; ================================================ FILE: env.toml ================================================ [app] name = "goal" key = "dQcxsKvBZKNfWivwnhKlDwvseguknBZPEiiDRQlIatjKLLpbzK" env = "local" debug = true [http] host = "0.0.0.0" port = "8009" [queue] connection = "goroutine" kafka.brokers = "localhost:9092" nsq.address = "localhost:49156" [db] connection = "mysql" host = "127.0.0.1" port = "3306" database = "goal" username = "root" password = "root" [db.sqlite] database = "database/database.sqlite" [db.pgsql] host = "localhost" port = "55433" database = "postgres" username = "postgres" password = "123456" [redis] host = "hsy" port = "6379" password = "123456" [redis.cache] host = "hsy" port = "6379" db = 1 # 缓存配置 [cache] driver = "redis" connection = "cache" prefix = "redis_" # 哈希配置 [hashing] driver = "bcrypt" cost = "14" salt = "goal" # 自定义哈希 [hashing.hashers] md5.driver = "md5" md5.salt = "goal" # 文件系统配置 [filesystem] disk = "public" root = "storage/app/public" perm = "0777" [filesystem.qiniu] private = "false" bucket = "aa" domain = "https://xxx.xxx.com" access_key = "" secret_key = "" # session 配置 [session] id = "goal" name = "goal_session:" ================================================ FILE: go.mod ================================================ module github.com/goal-web/goal go 1.25.0 replace github.com/goal-web/goal-cli => ../goal-cli require ( github.com/alicebob/miniredis/v2 v2.34.0 github.com/fasthttp/websocket v1.5.10 github.com/go-redis/redis/v8 v8.11.4 github.com/goal-web/application v0.5.2 github.com/goal-web/auth v0.5.3 github.com/goal-web/bloomfilter v0.5.2 github.com/goal-web/cache v0.5.2 github.com/goal-web/collection v0.5.2 github.com/goal-web/config v0.5.4 github.com/goal-web/console v0.5.4 github.com/goal-web/contracts v0.5.3 github.com/goal-web/database v0.5.3 github.com/goal-web/email v0.5.2 github.com/goal-web/encryption v0.5.2 github.com/goal-web/events v0.5.2 github.com/goal-web/filesystem v0.5.2 github.com/goal-web/goal-cli v0.5.42 github.com/goal-web/hashing v0.5.2 github.com/goal-web/http v0.5.11 github.com/goal-web/migration v0.5.6 github.com/goal-web/queue v0.5.2 github.com/goal-web/ratelimiter v0.5.2 github.com/goal-web/redis v0.5.2 github.com/goal-web/routing v0.5.2 github.com/goal-web/serialization v0.5.2 github.com/goal-web/session v0.5.2 github.com/goal-web/supports v0.5.7 github.com/goal-web/validation v0.5.2 github.com/goal-web/views v0.5.2 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-module/carbon/v2 v2.3.12 github.com/google/uuid v1.6.0 github.com/gookit/goutil v0.6.18 github.com/nsqio/go-nsq v1.1.0 github.com/spf13/cast v1.7.1 ) require ( github.com/BurntSushi/toml v1.4.0 // indirect github.com/joho/godotenv v1.5.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( github.com/ClickHouse/clickhouse-go/v2 v2.0.9 // indirect github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/apex/log v1.9.0 // indirect github.com/bits-and-blooms/bitset v1.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emicklei/proto v1.13.2 // indirect github.com/flosch/pongo2/v6 v6.0.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/goal-web/container v0.5.3 // indirect github.com/goal-web/pipeline v0.5.2 // indirect github.com/goal-web/querybuilder v0.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 // indirect github.com/jmoiron/sqlx v1.3.4 // indirect github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.4 // indirect github.com/mattn/go-sqlite3 v1.14.10 // indirect github.com/modood/table v0.0.0-20220527013332-8d47e76dad33 // indirect github.com/paulmach/orb v0.4.0 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/qbhy/parallel v1.4.0 // indirect github.com/qiniu/go-sdk/v7 v7.11.1 // indirect github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect github.com/segmentio/kafka-go v0.4.27 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/gopher-lua v1.1.1 // indirect go.opentelemetry.io/otel v1.3.0 // indirect go.opentelemetry.io/otel/trace v1.3.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect ) ================================================ FILE: go.sum ================================================ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/ClickHouse/clickhouse-go v1.5.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/ClickHouse/clickhouse-go/v2 v2.0.9 h1:JKtF6JlROrcdZRMoQUTv6fW8CBSL9FiBKylXXQx5YnY= github.com/ClickHouse/clickhouse-go/v2 v2.0.9/go.mod h1:FfiBHxYkESSf1DQxROQ1kOP2XtI4Fy8XDVPasZSkI+k= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY= github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4= github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU= github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/goal-web/application v0.5.2 h1:bDatyicAwuz4kNCKg+T47kNOtfXETlaRGEcPyWcM2AE= github.com/goal-web/application v0.5.2/go.mod h1:JVFX9zGWI9uG2ur1jlH87pWSG3hbatWGDyEHYj3FkHo= github.com/goal-web/auth v0.5.3 h1:i2UdvuY79TAwIqDHLI5KhBXZLTDncGVHDWPoQCqt6Vk= github.com/goal-web/auth v0.5.3/go.mod h1:y4ytkPR47ZQFJx26l0kVkbw0YXhCnWPkPMe+wEMbwJ0= github.com/goal-web/bloomfilter v0.5.2 h1:r4bdTOM3lXeb7qgrZI9SYI6I1ehBrB9l+kuf88g71dE= github.com/goal-web/bloomfilter v0.5.2/go.mod h1:uczJ+qBurMla6+nGhuR/Ezk3X4aydRFCqismyJ7SGDo= github.com/goal-web/cache v0.5.2 h1:gmUVwfOzzNMe53bXb4sTnAjdbmip1/uHe6wSw3gI0/Y= github.com/goal-web/cache v0.5.2/go.mod h1:RdZd3TeiJnhGzwrWACZPeZjqbBHR5vHjgtix2KpNOwA= github.com/goal-web/collection v0.5.2 h1:lPZbHeV4juiAh/NWp5FkG8+Wjb4ouu7IoQN8SNhtvq0= github.com/goal-web/collection v0.5.2/go.mod h1:dwO/vxDW4hLKzkHtDNXdgdgDWV8D+MHVXHKYy/nEKfQ= github.com/goal-web/config v0.5.4 h1:2w9bkpnXEuKA8V/2x21fAewWidyLNoUZWUoL8lLmJGo= github.com/goal-web/config v0.5.4/go.mod h1:L7qzwZnE547rioTSlhxZ2WyEYeqkboAiDoRk1G/dY2s= github.com/goal-web/console v0.5.4 h1:G7GvqgbpGV+iMOStz5s5sX1Cj8N+JpU+Nn+t4VaBUfw= github.com/goal-web/console v0.5.4/go.mod h1:8/MEDbVCMm1my5IYDS/6yMGlDXCsg8gLsy39pzfmEvo= github.com/goal-web/container v0.5.3 h1:pSz+ARibpOKXbGKLN8Yw/LbKfLSq5MdOwp9xlWHDsQs= github.com/goal-web/container v0.5.3/go.mod h1:RbzqAvWBKywaljql2JY1uoYzx1XJLjlDf7SIYiKbVlw= github.com/goal-web/contracts v0.5.3 h1:/W8n1B/GoKtXWwElrVR5RbbVSKRPkGVuJsLoSkbNJaw= github.com/goal-web/contracts v0.5.3/go.mod h1:mDFF5dx3G3newdB4qvfOWMnwWkGxQuzbymiNSKcdlzM= github.com/goal-web/database v0.5.3 h1:BoJ3juFknn0H9CBzDKpjix7Q3ejQOa3snwKXbXJlcBY= github.com/goal-web/database v0.5.3/go.mod h1:2R/b0mjO2xNImP0/v3gT/FL2eOceY6cDHZgFiFYxrds= github.com/goal-web/email v0.5.2 h1:MjWr2o8gwHekmH0J0DYeKNozkcavKjmRtJfcOf9LcsI= github.com/goal-web/email v0.5.2/go.mod h1:sI8eznbLhejS7j7/ZZehBTXFYiB2gVqQP3+Zx/I7ST4= github.com/goal-web/encryption v0.5.2 h1:YkCiLOt0ZLPjZfPpCyvPDR+HJy9kfIYHYPRKY3k9R5s= github.com/goal-web/encryption v0.5.2/go.mod h1:lzshlcMozyd3K39GBoKQhmZmJkjveQ0bNCiuyEsuqsM= github.com/goal-web/events v0.5.2 h1:Z+uHCp/axjjcoeEIZMb3Ug0g7MY70FZ2/qMurdY3GEY= github.com/goal-web/events v0.5.2/go.mod h1:33AiZ3h+HgXv2tEmbjLGob9t89wwFOdLfYGcN6PkwsA= github.com/goal-web/filesystem v0.5.2 h1:yXJDaEq8c6pAyRYdCcLcPaIqdhJ4SWH9+bSgsOZ26XA= github.com/goal-web/filesystem v0.5.2/go.mod h1:3VaOj8fzMnCh2EY28xUGhphRBmxbzKnSoaHfdOJgqvQ= github.com/goal-web/hashing v0.5.2 h1:QN3LetMqiJsTWT6Lo52GPD0FBaJ3c8+D7bIOVBs5VjY= github.com/goal-web/hashing v0.5.2/go.mod h1:Ft7MTHZSzppWPbtF8JNhtU0XLv5i2NEwYVpuDWc3c+M= github.com/goal-web/http v0.5.11 h1:7AuCNQ85Gmg8RN3pYC6P5kojD+iQ6v7+695ycMgsQec= github.com/goal-web/http v0.5.11/go.mod h1:+3RXhErKxuutSmxuIUaL52/7WVg0oCc10hJcDcgPCzY= github.com/goal-web/migration v0.5.6 h1:xNPirTwGIbgmY4e3dfeUmeKoh8i6FxTpZ9QeQL5CupU= github.com/goal-web/migration v0.5.6/go.mod h1:iGbpVpwPHQJde/I8//09HcHkKUovB8qQJmxgEyzvnNA= github.com/goal-web/pipeline v0.5.2 h1:aEpGmulH5CzOXqnSAZr7J43D4yy3Wi8quAY6t5ejseg= github.com/goal-web/pipeline v0.5.2/go.mod h1:9JPnhTvotfXdcdhH98oMjQmvuPa9WKye0TI8xb+y8HY= github.com/goal-web/querybuilder v0.5.4 h1:e6VGrM6Em+n6femrwIqCjpvzZ/uh1BwsfZHWysctz/s= github.com/goal-web/querybuilder v0.5.4/go.mod h1:v8Z8nnrriyq70QX7W5zGgxhSoz98DB/cnmN+tJQNyn0= github.com/goal-web/queue v0.5.2 h1:o/7V1B/lyHR4aGR4nqZaRWMQs84aDWnpR5AXx8X68WE= github.com/goal-web/queue v0.5.2/go.mod h1:Jr9dXUcY34T4/5g1F1CLZFPT9d0o42wB58hNfYekgjs= github.com/goal-web/ratelimiter v0.5.2 h1:S1gDxpZdvmQsdlULVafoK5dqhG74bNZ2R0nhkqcdhgs= github.com/goal-web/ratelimiter v0.5.2/go.mod h1:8j/SxH51dJSg7n7GYkvoGaiRfOv9EW2VNfwLDzQLwTY= github.com/goal-web/redis v0.5.2 h1:lBz/avfsDkp1pnubaYW+wFGrWN6wm7j/edsUYOBPqdg= github.com/goal-web/redis v0.5.2/go.mod h1:UWlrR1lkdbweOCiKzTOAGMcvCdwTZG0dNwKYOcVu3BQ= github.com/goal-web/routing v0.5.2 h1:i86o3vmu45xPaYQNYpx3utPST4L9Cx5iou8QVfYqRZA= github.com/goal-web/routing v0.5.2/go.mod h1:rtLq7/7qHmOAgNNikEF0HdMeEHqn5Rvt4WjPLag1Rzg= github.com/goal-web/serialization v0.5.2 h1:SipUuA7AF65FprNF271x7Isr6Yg1H/z4vSkDuovtOVE= github.com/goal-web/serialization v0.5.2/go.mod h1:7D5zjCADeHBXxFU4olxYhYaNRX1B/IgBGtY1MyS/mcg= github.com/goal-web/session v0.5.2 h1:juOXuFW/dOIRsa8YqsLEnBQ+NlFXIos/NN6lHlTqs2Y= github.com/goal-web/session v0.5.2/go.mod h1:WR7c7K+vvX5CqPhIg5Qwdt7GYDpnunaSEOg0xUlJQaA= github.com/goal-web/supports v0.5.7 h1:j0c0ZY5IJyiozGyp9fq0hy6Qkh4AMCP/GRSwDEQaOzE= github.com/goal-web/supports v0.5.7/go.mod h1:TViRmtPhjFfQ1YqOKBfxej8vdFkYwbzWe2uvhgGO2Zg= github.com/goal-web/validation v0.5.2 h1:3ufzNB30gqa4TqcZhFH/I3JWVxsSKCVhjvJgxZ5MMKQ= github.com/goal-web/validation v0.5.2/go.mod h1:UvlpuogwjQqngAqVAkSxHSEoxqWINolaXM1RLjkopao= github.com/goal-web/views v0.5.2 h1:euAKBqEgumpiGcNVQms8ROsZrg2Tze69qYrTsTOn9R8= github.com/goal-web/views v0.5.2/go.mod h1:yCo/xoXkBFKd8hUvVWaTcFO2jpxMO6LqTn/j6pAaR+4= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k= github.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI= 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.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.2/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/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.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/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw= github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY= github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 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.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/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/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.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.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM= github.com/modood/table v0.0.0-20220527013332-8d47e76dad33 h1:T5IbS9C1G2zeHb6eBy6OfIvj5tfQB23kGFpewCJuGDg= github.com/modood/table v0.0.0-20220527013332-8d47e76dad33/go.mod h1:41qyXVI5QH9/ObyPj27CGCVau5v/njfc3Gjj7yzr0HQ= github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE= github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A= github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.13/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/qbhy/parallel v1.4.0 h1:RvdjXbxIRNMG2lA6gkaEOgVhr7JbNy4BljabsD+u9JI= github.com/qbhy/parallel v1.4.0/go.mod h1:gjKS0IACnz3SWXkeEOUvPPZZxpeQAOW47jT4cpWPvqU= github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= github.com/qiniu/go-sdk/v7 v7.11.1 h1:/LZ9rvFS4p6SnszhGv11FNB1+n4OZvBCwFg7opH5Ovs= github.com/qiniu/go-sdk/v7 v7.11.1/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w= github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjKhAM4= github.com/segmentio/kafka-go v0.4.27/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.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/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 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/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY= go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/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-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.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= 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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/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.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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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/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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 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= 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-20190902080502-41f04d3bba15/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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.3.0/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.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= ================================================ FILE: main.go ================================================ package main import ( "fmt" "syscall" "github.com/goal-web/contracts" "github.com/goal-web/goal/app/controllers" "github.com/goal-web/goal/bootstrap/core" "github.com/goal-web/goal/routes" "github.com/goal-web/http" "github.com/goal-web/http/sse" "github.com/goal-web/http/websocket" "github.com/goal-web/session" "github.com/goal-web/supports/signal" "github.com/goal-web/views" ) func main() { a := "a" fmt.Println(a) app := core.Application(core.App{ QueueWorker: true, SchedulingWorker: true, }) app.RegisterServices( views.NewService(), http.NewService( routes.Api, routes.WebSocket, routes.Sse, controllers.Register, ), session.NewService(), sse.NewService(), websocket.NewService(), signal.NewService(syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT), ) app.Call(func(console3 contracts.Console, input contracts.ConsoleInput) { console3.Run(input) }) } ================================================ FILE: pro/Article.proto ================================================ syntax = "proto3"; //@table: articles //@timestamps message ArticleModel { uint32 id = 1; string title = 2; string created_at = 3; string updated_at = 4; } ================================================ FILE: pro/Project.proto ================================================ syntax = "proto3"; option go_package = "project"; //@timestamps //@table: projects message ProjectModel { int64 id = 1; string uuid = 2; string name = 3; int64 creator_id = 4; int64 group_id = 5; int64 key_id = 6; string repo_address = 7; string project_path = 8; string default_branch = 9; string settings = 10; string created_at = 11; string updated_at = 12; } //@controller:/project service ProjectService { rpc CreateProject(CreateProjectReq) returns (CreateProjectResult) {} //@method:Get rpc GetProject(GetProjectReq) returns (GetProjectResult) {} //@method:Get rpc ListProjects(ListProjectsReq) returns (ListProjectsResult) {} rpc UpdateProject(UpdateProjectReq) returns (UpdateProjectResult) {} rpc DeleteProject(DeleteProjectReq) returns (DeleteProjectResult) {} } message CreateProjectReq { string uuid = 1; string name = 2; int64 creator_id = 3; int64 group_id = 4; int64 key_id = 5; string repo_address = 6; string project_path = 7; string default_branch = 8; string settings = 9; } message CreateProjectResult { string code = 1; } message GetProjectReq { string id = 1; } message GetProjectResult { ProjectModel project = 1; } message ListProjectsReq { int64 page = 1; int64 per_page = 2; } message ListProjectsResult { int64 total = 1; //@ptr repeated ProjectModel projects = 2; } message UpdateProjectReq { int64 id = 1; string uuid = 2; string name = 3; int64 creator_id = 4; int64 group_id = 5; int64 key_id = 6; string repo_address = 7; string project_path = 8; string default_branch = 9; string settings = 10; } message UpdateProjectResult { string code = 1; } message DeleteProjectReq { string id = 1; } message DeleteProjectResult { string code = 1; } ================================================ FILE: pro/common.proto ================================================ syntax = "proto3"; option go_package = "."; enum Code { //@msg:成功 Success = 0; //@msg:参数解析失败 ParseReqErr = 10400; //@msg:未登录 Unauthorized = 10401; //@msg:没有权限 Forbidden = 100403; //@msg:找不到 NotFound = 100404; //@msg:业务错误 BizErr = 10201; } message ResponseResult { int32 code = 1; string err_message = 2; string message = 3; //@goType:any string data = 4; } ================================================ FILE: pro/goal-cli.go ================================================ package main import ( "flag" "fmt" "os" "path/filepath" "github.com/goal-web/goal-cli/app/gen" ) func main() { // 定义命令行参数 out := flag.String("out", "app", "output") // 输出目录 template := flag.String("template", "template.tmpl", "模板文件") // 模板文件 dir := flag.String("dir", "pro", "指定扫描的 proto 文件目录") // 要扫描的目录 mode := flag.String("mode", "pro", "pro 或者 SDK") flag.Parse() // 检查是否指定了 proto 文件目录 if *dir == "" { fmt.Println("请指定要扫描的 proto 文件目录, 使用 --dir 参数") os.Exit(1) } // 获取指定目录中的所有 proto 文件 protoFiles, err := scanProtoFiles(*dir) if err != nil { fmt.Printf("扫描目录 %s 中的 proto 文件失败: %v\n", *dir, err) os.Exit(1) } if *mode == "pro" { // 遍历所有找到的 proto 文件,依次调用 gen.Pro() for _, protoFile := range protoFiles { fmt.Printf("正在处理 proto 文件: %s\n", protoFile) gen.Pro(protoFile, *template, *out) } } else { // 遍历所有找到的 proto 文件,依次调用 gen.Pro() gen.SDK(protoFiles, *template, *out) } } // scanProtoFiles 扫描指定目录,返回所有的 .proto 文件路径 func scanProtoFiles(root string) ([]string, error) { var protoFiles []string // 使用 filepath.Walk 遍历目录,查找所有 .proto 文件 err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // 如果是 .proto 文件,则加入到列表中 if !info.IsDir() && filepath.Ext(path) == ".proto" { protoFiles = append(protoFiles, path) } return nil }) if err != nil { return nil, err } return protoFiles, nil } ================================================ FILE: pro/user.proto ================================================ syntax = "proto3"; option go_package = "user"; message WechatInfoData { string city = 1; int64 gender = 2; string open_id = 3; string country = 4; string language = 5; string nickname = 6; string province = 7; string avatar_url = 8; } // 用户注释 //@authenticatable //@table: users //@timestamps message UserModel { int64 id = 1; string name = 2; string avatar = 3; //@index //@goTag:db:"open_id;type:varchar(255);default 'xxasdasdsx'" string open_id = 4; //@ptr WechatInfoData wechat_info = 5; string channel = 6; //@hidden string password = 9; string created_at = 7; string updated_at = 8; } // 通过微信小程序的 code 登录 message LoginByWxCodeReq { //@gotag:validate:"required" string code = 1; } // 通过微信小程序的 code 登录 message LoginByWxInfoReq { //@gotag: validate:"required" string iv = 1; //@gotag: validate:"required" string sessionKey = 2; //@gotag: validate:"required" string encryptedData = 3; } message LoginByWxResult { //@gotag:json:"token,omitempty" string token = 1; //@ptr //@gotag:json:"user,omitempty" UserModel user = 2; //@gotag:json:"sessionKey,omitempty" string sessionKey = 3; } //@controller:/auth service AuthService { //@method:Post //@middleware:guest rpc LoginByWxAppCode(LoginByWxCodeReq) returns(LoginByWxResult); //@middleware:guest rpc LoginByWxAppInfo(LoginByWxInfoReq) returns(LoginByWxResult); } ================================================ FILE: routes/api.go ================================================ package routes import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/app/controllers" ) func Api(router contracts.HttpRouter) { router.Get("/wrk/{name}", func(request contracts.HttpRequest) any { return request.Param("name") }) router.Get("/", controllers.HelloWorld) router.Get("/view", func(views contracts.Views) any { return views.Render("view.html") }) } ================================================ FILE: routes/sse.go ================================================ package routes import ( "github.com/goal-web/contracts" sse2 "github.com/goal-web/goal/app/http/sse" "github.com/goal-web/http/sse" ) func Sse(router contracts.HttpRouter) { // 自定义 sse 控制器 router.Get(sse.New("/sse-demo", sse2.DemoController{})) // 默认 sse 控制器 router.Get(sse.Default()) router.Get("/send-sse", func(sse contracts.Sse, request contracts.HttpRequest) error { return sse.Send(uint64(request.GetInt64("fd")), request.GetString("msg")) }) router.Get("/close-sse", func(sse contracts.Sse, request contracts.HttpRequest) error { return sse.Close(uint64(request.GetInt64("fd"))) }) } ================================================ FILE: routes/ws.go ================================================ package routes import ( "fmt" "github.com/goal-web/contracts" websocket2 "github.com/goal-web/goal/app/websocket" "github.com/goal-web/http/websocket" ) func WebSocket(router contracts.HttpRouter) { router.Get("/ws-demo", websocket.New(websocket2.DemoController{})) router.Get("/ws", websocket.Default(func(frame contracts.WebSocketFrame) { fmt.Println("收到消息", frame.RawString(), frame.Connection().Fd()) _ = frame.Send("来自服务器的回复1") _ = frame.SendBytes([]byte("来自服务器的回复2")) })) } ================================================ FILE: sdk.tmpl ================================================ {{- define "request" -}} {{- range .Imports }} import {{ .Alias }} from "{{ .Pkg }}" {{- end }} export default interface {{ .Model.Name }} { {{- range .Fields }} {{ .JSONName }}{{ if hasComment .Comment "@nullable" }}?{{end}}: {{ tsType . }} {{- end }} } {{ end }} {{- define "model" -}} {{- range .Imports }} import {{ .Alias }} from "{{ .Pkg }}" {{- end }} export default interface {{ .Model.Name }} { {{- range .Fields }} {{ .JSONName }}{{ if hasComment .Comment "@nullable" }}?{{end}}: {{ tsType . }} {{- end }} } {{ end }} {{- define "result" -}} {{- range .Imports }} import {{ .Alias }} from "{{ .Pkg }}" {{- end }} export default interface {{ .Model.Name }} { {{- range .Fields }} {{ .JSONName }}{{ if hasComment .Comment "@nullable" }}?{{end}}: {{ tsType . }} {{- end }} } {{ end }} {{- define "enum" -}} {{- $enumName := .Name }} export enum {{ $enumName }} { {{- range .Values }} {{- $FieldName := sprintf "%s%s" $enumName .Name }} {{ toComments $FieldName .Comments }} {{ .Name }} = {{ .Value }}, {{- end }} } {{ end }} {{- define "data" -}} {{- range .Imports }} import {{ .Alias }} from "{{ .Pkg }}" {{- end }} export default interface {{ .Model.Name }} { {{- range .Fields }} {{ .JSONName }}{{ if hasComment .Comment "@nullable" }}?{{end}}: {{ tsType . }} {{- end }} } {{ end }} {{- define "controller" -}} import {alovaInstance, wrapParams} from "../index"; import {useRequest} from "alova/client"; import {RequestHookConfig} from "alova/client"; {{- range .Imports }} import {{ .Alias }} from "{{ .Pkg }}" {{- end }} {{- $serviceName := .Name }} {{- $prefix := .Prefix }} {{- $hasHook := hasComment .Comment "@hook" }} {{- range .Methods }} {{- $name := .Name }} {{- $req := .InputUsageName }} {{- $resp := .OutputUsageName }} {{- $path := .Path }} {{- $hook := or $hasHook (hasComment .Comment "@hook") }} {{- if eq (len .Method) 1 }} export function {{ .Name }}(req: {{ .InputUsageName }}) { return alovaInstance.{{ (index .Method 0) }}<{{ .OutputUsageName }}>("{{ $prefix }}{{ .Path }}", wrapParams('{{ index .Method 0 }}', req)) } {{- if $hook }} export function use{{ .Name }}(req: {{ .InputUsageName }}, config?: RequestHookConfig) { return useRequest({{ .Name }}(req), config) } {{- end }} {{- else }} {{- range .Method }} export function {{ . }}{{ $name }}(req: {{ $req }}) { return alovaInstance.{{ . }}<{{ $resp }}>("{{ $prefix }}{{ $path }}", wrapParams('{{ . }}', req)) } {{- if $hook }} export function use{{ . }}{{ $name }}(req: {{ .InputUsageName }}, config?: RequestHookConfig) { return useRequest({{ . }}{{ $name }}(req), config) } {{- end }} {{- end }} {{- end }} {{- end }} {{ end }} ================================================ FILE: server.conf ================================================ server { listen 80; server_name example.com; location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } location / { proxy_pass http://localhost:8008; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ================================================ FILE: storage/app/.gitignore ================================================ * !.gitignore !public ================================================ FILE: storage/framework/bloomfilter/.gitignore ================================================ .gitignore !.gitignore ================================================ FILE: storage/framework/cache/.gitignore ================================================ .gitignore !.gitignore ================================================ FILE: storage/framework/sessions/.gitignore ================================================ .gitignore !.gitignore ================================================ FILE: storage/logs/.gitignore ================================================ * !.gitignore ================================================ FILE: supervisor.conf ================================================ [program:goal-server] command=/opt/app/goal autostart=true autorestart=true user=root numprocs=1 redirect_stderr=true stdout_logfile=/opt/app/storage/logs/goal.log ================================================ FILE: template.tmpl ================================================ {{- define "model" -}} package {{ .Package }} import ( "encoding/json" "github.com/goal-web/supports/logs" "github.com/goal-web/contracts" "github.com/goal-web/database/table" "github.com/goal-web/migration/migrate" "github.com/goal-web/supports/utils" "github.com/goal-web/collection" "github.com/spf13/cast" "fmt" {{- if hasMsgComment .Model "@carbon" }} "github.com/golang-module/carbon/v2" {{- end }} {{- range .Imports }} {{ .Alias }} "{{ .Pkg }}" {{- end }} ) {{- $modelName := .Model.Name }} {{- $rawName := .Model.RawName }} {{- $tableName := .Model.TableName }} {{- $primaryKey := .Model.PrimaryKey }} var ( {{- range .Relations }} {{ $rawName }}{{ .Name }}Relation contracts.RelationType = "{{ .JSONName }}" {{- end }} ) {{ toComments .Model.Name .Model.Comments }} type {{ $modelName }} struct { {{- range .Fields }} {{- if hasComment .Comment "@belongsTo" }} {{- else }} {{ .Comments }} {{ .Name }} {{ goType . }} `{{ toTags . }}` {{- end }} {{- end }} _raw contracts.Fields _update contracts.Fields _append contracts.Fields _hidden map[string]struct{} _relation_loaded map[contracts.RelationType]struct{} {{- range .Relations }} _{{ .Name }} {{ goType . }} {{- end }} } {{- $define := join $rawName "Define" }} var {{ $define }} {{ $rawName }}Static type {{ $rawName }}Static struct { TableName string Hidden []string Indexes []string With []contracts.RelationType Appends map[string]func(model *{{ $modelName }}) any {{- range .Fields }} {{ .Name }}Getter func(model *{{ $modelName }}, raw {{ goType . }}) {{ goType . }} {{ .Name }}Setter func(model *{{ $modelName }}, raw {{ goType . }}) {{ goType . }} {{- end }} Saving func(model *{{ $modelName }}) contracts.Exception Saved func(model *{{ $modelName }}) Updating func(model *{{ $modelName }}, fields contracts.Fields) contracts.Exception Updated func(model *{{ $modelName }}, fields contracts.Fields) Deleting func(model *{{ $modelName }}) contracts.Exception Deleted func(model *{{ $modelName }}) PrimaryKeyGetter func(model *{{ $modelName }}) any } func {{ $rawName }}Migrator() migrate.Migrator { return func(executor contracts.SqlExecutor) contracts.Exception { return migrate.Migrate({{ $define }}.TableName, {{ $define }}.Indexes, {{ $modelName }}{}, executor) } } func init() { {{ $define }}.TableName = "{{ $tableName }}" {{ $define }}.Appends = make(map[string]func(model *{{ $modelName }}) any) {{- if hasMsgComment .Model "@hidden" }} {{ $define }}.Hidden = append( {{ $define }}.Hidden, {{- range .Fields }} {{- if hasComment .Comment "@hidden" }} "{{ .JSONName }}", {{- end }} {{- end }} ) {{- end }} {{- if hasMsgComment .Model "@with" }} {{ $define }}.With = append( {{ $define }}.With, {{- range .Relations }} {{- if hasComment .Comment "@with" }} {{ $rawName }}{{ .Name }}Relation, {{- end }} {{- end }} ) {{- end }} {{- if hasMsgComment .Model "@index" }} {{ $define }}.Indexes = append( {{ $define }}.Indexes, {{- range .Fields }} {{- if hasComment .Comment "@index" }} "index;{{ getIndexComment .Comment "@index" 0 (join .JSONName "_idx") }};{{ replace (getIndexComment .Comment "@index" 1 (join "(" .JSONName ")")) ";" "," }}", {{- end }} {{- end }} ) {{- end }} {{- if hasMsgComment .Model "@unique" }} {{ $define }}.Indexes = append( {{ $define }}.Indexes, {{- range .Fields }} {{- if hasComment .Comment "@unique" }} "unique index;{{ getIndexComment .Comment "@unique" 0 (join .JSONName "_idx") }};{{ replace (getIndexComment .Comment "@unique" 1 (join "(" .JSONName ")")) ";" "," }}", {{- end }} {{- end }} ) {{- end }} } func New{{ $modelName }}(fields contracts.Fields) *{{ $modelName }} { var model = {{ $modelName }}{ _raw: fields, } model.Set(fields) return &model } func {{ $modelName }}SingleRelationSetter[T any](key contracts.RelationType) func(item *{{ $modelName }}, value []any) { return func(item *{{ $modelName }}, values []any) { var value T if len(values) > 0 { value = values[0].(T) } item.Set(contracts.Fields{ string(key): value, }) } } func {{ $modelName }}MultiRelationSetter[T any](key contracts.RelationType) func(item *{{ $modelName }}, value []any) { return func(model *{{ $modelName }}, value []any) { var results []T for _, item := range value { results = append(results, item.(T)) } model.Set(contracts.Fields{ string(key): results }) } } func {{ $modelName }}LocalKeyGetter(key string) func(item *{{ $modelName }}) any { return func(item *{{ $modelName }}) any { return item.Get(key) } } func {{ $modelName }}RelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} for key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) { results[key] = collection.New(values).ToAnyArray() } return results } } func {{ $modelName }}ThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any { return func(keys []any) map[string][]any { var results = map[string][]any{} groupKey := fmt.Sprintf("%s.%s", midTable, firstKey) for key, values := range query(). AddSelect(fmt.Sprintf("(%s) as _group_key", groupKey)). WhereIn(groupKey, keys). Join(midTable, fmt.Sprintf("%s.%s", midTable, secondLocalKey), "=", fmt.Sprintf("%s.%s", query().GetTableName(), secondKey)). Get().GroupBy("_group_key") { results[key] = collection.New(values).ToAnyArray() } return results } } {{- $queryName := replace .Model.Name "Model" "Query" }} func {{ $queryName }}WithExecutor(executor contracts.SqlExecutor) *table.Table[{{ $modelName }}] { return {{ $queryName }}().SetExecutor(executor) } func {{ $queryName }}() *table.Table[{{ $modelName }}] { return table.NewQuery({{ $define }}.TableName, New{{ $modelName }}). SetPrimaryKey("{{ $primaryKey }}"). {{- if hasMsgComment .Model "@timestamps" }} SetCreatedTimeColumn("{{ getIndexComment .Model.Comment "@timestamps" 0 "created_at" }}"). SetUpdatedTimeColumn("{{ getIndexComment .Model.Comment "@timestamps" 1 "updated_at" }}"). {{- end }} {{- range $index, $item := .Relations }} {{- $relationType := join $rawName .Name "Relation" }} {{- $relationItemType := substring (goType .) 1 }} {{- $relationQuery := replace $relationItemType "Model" "Query"}} {{- if .Repeated }} {{- $relationItemType = substring (goType .) 2 }} {{- $relationQuery = substring $relationQuery 2 }} {{- end }} {{- if hasComment .Comment "@belongsTo" }} {{- $ownerKey := getIndexComment .Comment "@belongsTo" 0 "id" }} {{- $localKey := getIndexComment .Comment "@belongsTo" 1 (join .JSONName "_id") }} SetRelation( // belongsTo: {{ .Name }} {{ $rawName }}{{ .Name }}Relation, {{ $modelName }}LocalKeyGetter("{{ $localKey }}"), {{ $modelName }}RelationGetter({{ $relationQuery }}, "{{ $ownerKey }}"), {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}), ). {{- else if hasComment .Comment "@hasOneThrough" }} {{- $midTable := getIndexComment .Comment "@hasOneThrough" 0 "mid_table" }} {{- $firstKey := getIndexComment .Comment "@hasOneThrough" 1 (join (toLower $rawName) "_id") }} {{- $secondKey := getIndexComment .Comment "@hasOneThrough" 2 "id" }} {{- $localKey := getIndexComment .Comment "@hasOneThrough" 3 "id" }} {{- $secondLocalKey := getIndexComment .Comment "@hasOneThrough" 4 (join $midTable "_id") }} SetRelation( // hasOneThrough: {{ .Name }} {{ $rawName }}{{ .Name }}Relation, {{ $modelName }}LocalKeyGetter("{{ $localKey }}"), {{ $modelName }}ThroughRelationGetter({{ $relationQuery }}, "{{ $midTable }}", "{{ $firstKey }}", "{{ $secondKey }}", "{{ $secondLocalKey }}"), {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}), ). {{- else if hasComment .Comment "@hasOne" }} {{- $localKey := getIndexComment .Comment "@hasOne" 0 "id" }} {{- $foreignKey := getIndexComment .Comment "@hasOne" 1 (join (toLower $rawName) "_id") }} SetRelation( // hasOne: {{ .Name }} {{ $rawName }}{{ .Name }}Relation, {{ $modelName }}LocalKeyGetter("{{ $localKey }}"), {{ $modelName }}RelationGetter({{ $relationQuery }}, "{{ $foreignKey }}"), {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}), ). {{- else if or (hasComment .Comment "@hasManyThrough") (hasComment .Comment "@belongsToMany") }} {{- $relationName := "hasManyThrough" }} {{- if (hasComment .Comment "@belongsToMany") }} {{- $relationName = "belongsToMany" }} {{- end }} {{- $midTable := getIndexComment .Comment (join "@" $relationName) 0 "mid_table" }} {{- $firstKey := getIndexComment .Comment (join "@" $relationName) 1 (join (toLower $rawName) "_id") }} {{- $secondKey := getIndexComment .Comment (join "@" $relationName) 2 "id" }} {{- $localKey := getIndexComment .Comment (join "@" $relationName) 3 "id" }} {{- $secondLocalKey := getIndexComment .Comment (join "@" $relationName) 4 (join $midTable "_id") }} SetRelation( // {{- $relationName }}: {{ .Name }} {{ $rawName }}{{ .Name }}Relation, {{ $modelName }}LocalKeyGetter("{{ $localKey }}"), {{ $modelName }}ThroughRelationGetter({{ $relationQuery }}, "{{ $midTable }}", "{{ $firstKey }}", "{{ $secondKey }}", "{{ $secondLocalKey }}"), {{ $modelName }}MultiRelationSetter[{{ $relationItemType }}]({{ $relationType }}), ). {{- else if hasComment .Comment "@hasMany" }} {{- $relationItemType := substring (goType .) 2 }} {{- $relationQuery := replace (substring (goType .) 3) "Model" "Query"}} {{- $foreignKey := getIndexComment .Comment "@hasMany" 0 (join (toLower $rawName) "_id") }} {{- $localKey := getIndexComment .Comment "@hasMany" 1 "id" }} SetRelation( // hasMany: {{ .Name }} {{ $rawName }}{{ .Name }}Relation, {{ $modelName }}LocalKeyGetter("{{ $localKey }}"), {{ $modelName }}RelationGetter({{ $relationQuery }}, "{{ $foreignKey }}"), {{ $modelName }}MultiRelationSetter[{{ $relationItemType }}]({{ $relationType }}), ). {{- end }} {{- end }} SetWiths({{ $define }}.With...) } func (model *{{ $modelName }}) Hidden(fields ...string) *{{ $modelName }} { for _, field := range fields { if model._hidden == nil { model._hidden = map[string]struct{}{ field: struct{}{}, } } else { model._hidden[field] = struct{}{} } } return model } func (model *{{ $modelName }}) Exists() bool { return {{ .Model.RawName }}Query().Where("{{ $primaryKey }}", model.GetPrimaryKey()).Count() > 0 } func (model *{{ $modelName }}) Save() contracts.Exception { if model._update == nil { return nil } if {{ $define }}.Saving != nil { if err := {{ $define }}.Saving(model); err != nil { return err } } var err contracts.Exception var pk = model. GetPrimaryKey() if cast.ToUint64(pk) == 0 { pk, err = {{ .Model.RawName }}Query().Where("{{ $primaryKey }}", model.GetPrimaryKey()).InsertGetIdE(model._update) if err == nil { {{- range .Fields }} {{- if eq .JSONName $primaryKey }} model.Set{{.Name}}(cast.{{ convertFunc (goType .) }}(pk)) {{- end }} {{- end }} } } else { _, err = {{ .Model.RawName }}Query().Where("{{ $primaryKey }}", model.GetPrimaryKey()).UpdateE(model._update) } if err == nil { model._update = nil if {{ $define }}.Saved != nil { {{ $define }}.Saved(model) } } return err } func (model *{{ $modelName }}) Set(fields contracts.Fields) { for key, value := range fields { switch key { {{- range .Fields }} case "{{ .JSONName }}": switch v := value.(type) { case {{ goType . }}: model.Set{{ .Name }}(v) case func() {{ goType . }}: model.Set{{ .Name }}(v()) {{- $type := goType . }} {{- if ne $type "string"}} case string: {{- if eq $type "[]byte" }} model.Set{{ .Name }}([]byte(v)) {{else}} var vd {{ goType . }} err := json.Unmarshal([]byte(v), &vd) if err != nil { logs.Default().Warn("Failed to Parse field "+key) continue } model.Set{{ .Name }}(vd) {{end}} {{end}} {{- if ne $type "[]byte"}} case []byte: {{- if eq $type "string" }} model.Set{{ .Name }}(string(v)) {{else}} var vd {{ goType . }} err := json.Unmarshal(v, &vd) if err != nil { logs.Default().Warn("Failed to Parse field "+key) continue } model.Set{{ .Name }}(vd) {{end}} {{end}} {{- if isBasicType . }} default: model.Set{{ .Name }}(cast.{{ convertFunc (goType .) }}(v)) {{- end }} } {{- end }} {{- range .Relations }} {{- $relationType := join $rawName .Name "Relation" }} case string({{ $relationType }}): model.Set{{ .Name }}(value.({{ goType . }})) {{- end }} } } } func (model *{{ $modelName }}) Only(key ...string) contracts.Fields { var fields = make(contracts.Fields) for _, k := range key { {{- range .Fields }} if k == "{{ .JSONName }}" { fields[k] = model.Get{{ .Name }}() continue } {{- end }} if {{ $define }}.Appends[k] != nil { fields[k] = {{ $define }}.Appends[k](model) } } return fields } func (model *{{ $modelName }}) Get(key string) any { switch key { {{- range $index, $item := .Fields }} case "{{ .JSONName }}": return model.Get{{ .Name }}() {{- end }} } if value, exists := model._append[key]; exists { return value } if fn, exists := {{ $define }}.Appends[key]; exists { model._append[key] = fn(model) return model._append[key] } switch contracts.RelationType(key) { {{- range $index, $item := .Relations }} {{- $relationType := join $rawName .Name "Relation" }} case {{ $relationType }}: return model.{{ .Name }}() {{- end }} } return nil } func (model *{{ $modelName }}) Except(keys ...string) contracts.Fields { var excepts = map[string]struct{}{} for _, k := range keys { excepts[k] = struct{}{} } var fields = make(contracts.Fields) for key, value := range model.ToFields() { if _, ok := excepts[key]; ok { continue } fields[key] = value } return fields } func (model *{{ $modelName }}) ToFields() contracts.Fields { if model == nil { return nil } model.Hidden({{ $define }}.Hidden...) fields := contracts.Fields{} {{- range .Fields }} if _,exists := model._hidden["{{ .JSONName }}"]; !exists { fields["{{ .JSONName }}"] = model.Get{{ .Name }}() } {{- end }} for key := range {{ $define }}.Appends { value := model.Get(key) if fieldsProvider, ok := value.(contracts.FieldsProvider); ok { fields[key] = fieldsProvider.ToFields() } else { fields[key] = value } } for key := range model._relation_loaded { switch key { {{- range .Relations }} {{- $relationType := join $rawName .Name "Relation" }} case {{ $relationType }}: {{- if .Repeated }} var results []contracts.Fields for _, item := range model._{{ .Name }} { results = append(results, item.ToFields()) } fields[string(key)] = results {{- else }} fields[string(key)] = model._{{ .Name }}.ToFields() {{- end }} {{- end }} } } for key, value := range model._raw { _, hidden := model._hidden[key] if _, exists := fields[key]; !exists && !hidden { fields[key] = value } } return fields } func (model *{{ $modelName }}) Update(fields contracts.Fields) contracts.Exception { if {{ $define }}.Updating != nil { if err := {{ $define }}.Updating(model, fields); err != nil { return err } } if model._update != nil { utils.MergeFields(model._update, fields) } _, err := {{ .Model.RawName }}Query().Where("{{ $primaryKey }}", model.GetPrimaryKey()).UpdateE(fields) if err == nil { model.Set(fields) model._update = nil if {{ $define }}.Updated != nil { {{ $define }}.Updated(model, fields) } } return err } func (model *{{ $modelName }}) Refresh() contracts.Exception { fields, err := table.ArrayQuery("{{ $tableName }}").Where("{{ $primaryKey }}", model.GetPrimaryKey()).FirstE() if err != nil { return err } model.Set(*fields) return nil } func (model *{{ $modelName }}) Delete() contracts.Exception { if {{ $define }}.Deleting != nil { if err := {{ $define }}.Deleting(model); err != nil { return err } } _, err := {{ .Model.RawName }}Query().Where("{{ $primaryKey }}", model.GetPrimaryKey()).DeleteE() if err == nil && {{ $define }}.Deleted != nil { {{ $define }}.Deleted(model) } return err } func (model *{{ $modelName }}) GetPrimaryKey() any { if {{ $define }}.PrimaryKeyGetter != nil { return {{ $define }}.PrimaryKeyGetter(model) } return model.{{ toCamelCase $primaryKey }} } {{- if .Model.Authenticatable }} func (model *{{ $modelName }}) GetAuthenticatableKey() string { return fmt.Sprintf("%v", model.GetPrimaryKey()) } func {{ .Model.RawName }}AuthProvider(identify string) contracts.Authenticatable { return {{ .Model.RawName }}Query().Find(identify) } {{- end }} {{- range .Fields }} func (model *{{ $modelName }}) Get{{ .Name }}() {{ goType . }} { if {{ $define }}.{{ .Name }}Getter != nil { return {{ $define }}.{{ .Name }}Getter(model, model.{{ .Name }}) } return model.{{ .Name }} } func (model *{{ $modelName }}) Set{{ .Name }}(value {{ goType . }}) { if {{ $define }}.{{ .Name }}Setter != nil { value = {{ $define }}.{{ .Name }}Setter(model, value) } if model._update == nil { model._update = contracts.Fields{"{{ .JSONName }}": value} } else { model._update["{{ .JSONName }}"] = value } model.{{ .Name }} = value } {{- if hasComment .Comment "@carbon" }} func (model *{{ $modelName }}) Get{{ .Name }}Carbon() carbon.Carbon { return carbon.Parse(model.Get{{ .Name }}()) } {{- end }} {{- end }} {{- range .Relations }} {{- $relationType := join $rawName .Name "Relation" }} {{- $relationItemType := substring (goType .) 1 }} {{- $relationQueryType := substring (goType .) 1 }} {{- $throughName := "" }} {{- if .Repeated }} {{- $relationItemType = substring (goType .) 3 }} {{- $relationQueryType = substring (goType .) 3 }} {{- end }} {{- $relationQuery := replace $relationItemType "Model" "Query" }} {{- $foreignKey := "" }} {{- $localKey := "" }} {{- $localQuery := join .Name "Query" }} {{- if (hasComment .Comment "@belongsTo") }} {{- $throughName = "@belongsTo" }} {{- $foreignKey = getIndexComment .Comment "@belongsTo" 0 "id" }} {{ $localKey = getIndexComment .Comment "@belongsTo" 1 (join .JSONName "_id") }} {{- else if (hasComment .Comment "@hasOne") }} {{- $throughName = "@hasOne" }} {{- $localKey = getIndexComment .Comment "@hasOne" 0 "id" }} {{- $foreignKey = getIndexComment .Comment "@hasOne" 1 (join (toLower $rawName) "_id") }} {{- else if (hasComment .Comment "@hasMany") }} {{- $throughName = "@hasMany" }} {{- $relationQuery = replace $relationItemType "Model" "Query" }} {{- $foreignKey = getIndexComment .Comment "@hasMany" 0 (join .JSONName "_id") }} {{- $localKey = getIndexComment .Comment "@hasMany" 1 "id" }} {{- $relationQueryType = $relationItemType }} {{- end }} {{- if .Repeated }} // {{ $localQuery }} {{ $throughName }} func (model *{{ $modelName }}) {{ .Name }}() {{ goType . }} { _, exists := model._relation_loaded[{{ $relationType }}] if !exists { value := model.{{ $localQuery }}().Get().ToArray() model.Set{{ .Name }}(value) return value } return model._{{ .Name }} } {{- else }} // {{ $localQuery }} {{ $throughName }} func (model *{{ $modelName }}) {{ .Name }}() {{ goType . }} { _, exists := model._relation_loaded[{{ $relationType }}] if !exists { value := model.{{ $localQuery }}().First() model.Set{{ .Name }}(value) return value } return model._{{ .Name }} } {{- end }} {{- if or (hasComment .Comment "@hasManyThrough") (hasComment .Comment "@belongsToMany") (hasComment .Comment "@hasOneThrough") }} {{- $throughName := "@hasManyThrough" }} {{- if (hasComment .Comment "@belongsToMany") }} {{- $throughName = "@belongsToMany" }} {{- else if (hasComment .Comment "@hasOneThrough") }} {{- $throughName = "@hasOneThrough" }} {{- end }} {{- $midTable := getIndexComment .Comment $throughName 0 "mid_table" }} {{- $firstKey := getIndexComment .Comment $throughName 1 (join (toLower $rawName) "_id") }} {{- $secondKey := getIndexComment .Comment $throughName 2 "id" }} {{- $localKey := getIndexComment .Comment $throughName 3 "id" }} {{- $secondLocalKey := getIndexComment .Comment $throughName 4 (join $midTable "_id") }} // {{ $localQuery }} {{ $throughName }} func (model *{{ $modelName }}) {{ $localQuery }}() contracts.QueryBuilder[{{ $relationQueryType }}] { query := {{ $relationQuery }}() return query. Where("{{ $midTable }}.{{ $firstKey }}", model.Get("{{ $localKey }}")). Join("{{ $midTable }}", "{{ $midTable }}.{{ $secondLocalKey }}", "=", fmt.Sprintf("%s.{{ $secondKey }}", query.GetTableName())) } {{- else }} // {{ $localQuery }} {{ $throughName }} func (model *{{ $modelName }}) {{ $localQuery }}() contracts.QueryBuilder[{{ $relationQueryType }}] { return {{ $relationQuery }}().Where("{{ $foreignKey }}", model.Get("{{ $localKey }}")) } {{- end }} // {{ $localQuery }} {{ $throughName }} func (model *{{ $modelName }}) Set{{ .Name }}(value {{ goType . }}) { if model._relation_loaded == nil { model._relation_loaded = make(map[contracts.RelationType]struct{}) } model._relation_loaded[{{ $relationType }}] = struct{}{} model._{{ .Name }} = value } {{- end }} {{ end }} {{- define "data" -}} package {{ .Package }} import ( {{- range .Imports }} {{ .Alias }} "{{ .Pkg }}" {{- end }} ) type {{ .Model.Name }} struct { {{- range .Fields }} {{ .Name }} {{ goType . }} `{{ toTags . }}` {{- end }} } {{ end }} {{- define "request" -}} package {{ .Package }} import ( {{- range .Imports }} {{ .Alias }} "{{ .Pkg }}" {{- end }} "github.com/goal-web/contracts" ) type {{ .Model.Name }} struct { {{- range .Fields }} {{ .Name }} {{ goType . }} `{{ toTags . }}` {{- end }} } func (model *{{ .Model.Name }}) ToFields() contracts.Fields { if model == nil { return nil } fields := contracts.Fields{ {{- range .Fields }} "{{ .JSONName }}": model.{{ .Name }}, {{- end }} } return fields } {{ end }} {{- define "result" -}} package {{ .Package }} import ( "github.com/goal-web/contracts" {{- range .Imports }} {{ .Alias }} "{{ .Pkg }}" {{- end }} ) {{- $resultName := .Model.Name }} type {{ $resultName }} struct { {{- range .Fields }} {{ .Name }} {{ goType . }} `{{ toTags . }}` {{- end }} } func (result *{{ $resultName }}) ToFields() contracts.Fields { fields := contracts.Fields{ {{- range .Fields }} {{- if eq (fieldMsg .) nil }} "{{ .JSONName }}": result.{{ .Name }}, {{- else if and (ne .Repeated true) .IsModel }} "{{ .JSONName }}": result.{{ .Name }}.ToFields(), {{- else }} "{{ .JSONName }}": result.{{ .Name }}, {{- end }} {{- end }} } {{- range .Fields }} {{- if and .Repeated (ne (fieldMsg .) nil) (fieldMsg .).IsModel }} {{ .JSONName }}List := make([]contracts.Fields, len(result.{{ .Name }})) for i, item := range result.{{ .Name }} { {{ .JSONName }}List[i] = item.ToFields() } fields["{{ .JSONName }}"] = {{ .JSONName }}List {{- end }} {{- end }} return fields } {{ end }} {{- define "enum" -}} package {{ .Package }} {{- $enumName := .Name }} type {{ .Name }} int const ( {{- range .Values }} {{- $FieldName := sprintf "%s%s" $enumName .Name }} {{ toComments $FieldName .Comments }} {{ $enumName }}{{ .Name }} {{ $enumName }} = {{ .Value }} {{- end }} {{ $enumName }}Unknown {{ $enumName }} = -1000 ) func (item {{ $enumName }}) String() string { switch item { {{- range .Values }} case {{ $enumName }}{{ .Name }}: return "{{ .Name }}" {{- end }} default: return "Unknown" } } func (item {{ $enumName }}) Message() string { switch item { {{- range .Values }} case {{ $enumName }}{{ .Name }}: return "{{ .Message }}" {{- end }} default: return "Unknown" } } func Parse{{ $enumName }}FromString(msg string) {{ $enumName }} { switch msg { {{- range .Values }} case "{{ .Name }}": return {{ $enumName }}{{ .Name }} {{- end }} default: return {{ $enumName }}Unknown } } {{ end }} {{- define "service" -}} package {{ .Package }} import ( "github.com/goal-web/contracts" {{- range .Imports }} {{ .Alias }} "{{ .Pkg }}" {{- end }} ) {{- $serviceName := .Name }} {{- $define := join .Name "Define" }} var {{ $define }} {{ $serviceName }}Static type {{ $serviceName }}Static struct { {{- range .Methods }} {{ .Name }} func (req *{{ .InputUsageName }}, ctx contracts.Context) (*{{ .OutputUsageName }}, error) {{- end }} } {{- range .Methods }} func {{ $serviceName }}{{ .Name }}(req *{{ .InputUsageName }}, ctx contracts.Context) (*{{ .OutputUsageName }}, error) { if {{ $define }}.{{ .Name }} != nil { return {{ $define }}.{{ .Name }}(req, ctx) } return nil, nil } {{- end }} {{ end }} {{- define "controller" -}} package {{ .Package }} import ( "github.com/goal-web/contracts" "github.com/goal-web/validation" "{{ .ResponsePath }}" svc "{{ .ImportPath }}" {{- range .Imports }} {{- if notContains .Pkg "results" }} {{ .Alias }} "{{ .Pkg }}" {{ end -}} {{- end }} ) {{- $serviceName := .Name }} {{- $prefix := .Prefix }} func {{ .Name }}Router(router contracts.HttpRouter) { routeGroup := router.Group("{{ $prefix }}"{{ toMiddlewares .Middlewares }}) {{- range .Methods }} {{- $controllerMethod := sprintf "%s%s" $serviceName .Name }} {{- $path := .Path }} {{- $middlewares := .Middlewares }} {{- range .Method }} routeGroup.{{ . }}("{{ $path }}", {{ $controllerMethod }}{{ toMiddlewares $middlewares }}) {{- end }} {{- end }} } {{- $usageName := .UsageName }} {{- range .Methods }} func {{ $serviceName }}{{ .Name }}(request contracts.HttpRequest) any { var req {{ .InputUsageName }} if err:= request.Parse(&req); err != nil { return response.ParseReqErr(err) } if err := validation.Struct(req); err != nil { return response.InvalidReq(err) } resp, err := {{ $usageName }}{{ .Name }}(&req, request) if err != nil { return response.BizErr(err) } return response.Success(resp) } {{- end }} {{ end }} ================================================ FILE: tests/bootstrap.go ================================================ package tests import ( "github.com/goal-web/contracts" "github.com/goal-web/goal/bootstrap/core" ) func initApp() contracts.Application { app := core.Application(core.App{ QueueWorker: false, SchedulingWorker: false, }) return app } ================================================ FILE: tests/bootstrap_test.go ================================================ package tests import "testing" func TestBootstrap(t *testing.T) { initApp() } ================================================ FILE: tests/db_test.go ================================================ package tests import ( "testing" ) func TestModel(t *testing.T) { initApp() } ================================================ FILE: tests/env.toml ================================================ [app] name = "goal" key = "dQcxsKvBZKNfWivwnhKlDwvseguknBZPEiiDRQlIatjKLLpbzK" env = "local" debug = true [http] host = "0.0.0.0" port = "8009" [queue] connection = "goroutine" kafka.brokers = "localhost:9092" nsq.address = "localhost:49156" [db] connection = "mysql" host = "127.0.0.1" port = "3306" database = "goal" username = "root" password = "root" [db.sqlite] database = "database/database.sqlite" [db.pgsql] host = "localhost" port = "55433" database = "postgres" username = "postgres" password = "123456" [redis] host = "hsy" port = "6379" password = "123456" [redis.cache] host = "hsy" port = "6379" db = 1 # 缓存配置 [cache] driver = "redis" connection = "cache" prefix = "redis_" # 哈希配置 [hashing] driver = "bcrypt" cost = "14" salt = "goal" # 自定义哈希 [hashing.hashers] md5.driver = "md5" md5.salt = "goal" # 文件系统配置 [filesystem] disk = "public" root = "storage/app/public" perm = "0777" [filesystem.qiniu] private = "false" bucket = "aa" domain = "https://xxx.xxx.com" access_key = "" secret_key = "" # session 配置 [session] id = "goal" name = "goal_session:" ================================================ FILE: views/view.html ================================================ Document view example