[
  {
    "path": ".github/ISSUE_TEMPLATE.MD",
    "content": "<!-- Please answer these questions before submitting your issue. Thanks! -->\n\n<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！否则issue可能会被延期处理！ -->\n<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！否则issue可能会被延期处理！ -->\n<!-- 为高效处理您的疑问，如果觉得是BUG类问题，请您务必提供可复现该问题的最小可运行代码！否则issue可能会被延期处理！ -->\n<!-- 重要的事情说三遍！ -->\n\n### 1. What version of `Go` and system type/arch are you using?\n<!-- \nPlease paste the output of command `go version` from your terminal.\nWhat expect to see is like: `go 1.25.0, linux/amd64`\n-->\n\n\n### 2. What version of `Goal` are you using?\n<!-- You can find the Goal version from your `go.mod` -->\n\n\n### 3. Can this issue be re-produced with the latest release?\n\n\n\n### 4. What did you do?\n<!--\nIf possible, provide a copy of shortest codes for reproducing the error.\nA complete runnable program is best.\n-->\n\n\n\n### 5. What did you expect to see?\n\n\n\n### 6. What did you see instead?\n\n\n\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\ndatabase/*.sqlite\n*.pid\n\n/bin*\n\n\ngo.work\ngo.work.sum"
  },
  {
    "path": "Dockerfile",
    "content": "FROM golang:1.20 as builder\nLABEL maintainer=\"qbhy <qbhy0715@qq.com>\"\n\nWORKDIR /app\n\nCOPY . /app\nENV CGO_ENABLED=0\nENV GOOS=linux\nENV GOARCH=amd64\nENV GOPROXY=https://proxy.golang.com.cn,direct\nRUN go build -ldflags=\"-s -w\" -o app main.go\n\nFROM alpine\n\nWORKDIR /app\nCOPY --from=builder /app/app .\n\n# run\nENTRYPOINT [\"/app/app\"]"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 桥边红药\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "DOCKER_TAG=goal\n\ngen:\n\tgo run pro/goal-cli.go --template template.tmpl\n\nrun:\n\tgo run main.go run\n\nbuild:\n\tgo build -o ./bin -v ./\n\ntest:\n\tgo test -json ./tests\n\nimage:\n\tdocker build -t $(DOCKER_TAG) .\n\nmigrate:\n\tgo run bootstrap/console/main.go migrate\n\nmigrate-rollback:\n\tgo run bootstrap/console/main.go migrate:rollback\n\nmigrate-refresh:\n\tgo run bootstrap/console/main.go migrate:refresh\n\nmigrate-reset:\n\tgo run bootstrap/console/main.go migrate:reset\n\nmigrate-status:\n\tgo run bootstrap/console/main.go migrate:status\n\nmake-migration:\n\tgo run bootstrap/console/main.go make:migration $(NAME)\n"
  },
  {
    "path": "README.md",
    "content": "# Goal Framework\n[![codecov](https://codecov.io/gh/goal-web/goal/branch/master/graph/badge.svg)](https://codecov.io/gh/goal-web/goal)\n[![Go Report Card](https://goreportcard.com/badge/github.com/goal-web/goal)](https://goreportcard.com/report/github.com/goal-web/goal)\n[![GoDoc](https://pkg.go.dev/badge/github.com/goal-web/goal?status.svg)](https://pkg.go.dev/github.com/goal-web/goal?tab=doc)\n[![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)\n[![Sourcegraph](https://sourcegraph.com/github.com/goal-web/goal/-/badge.svg)](https://sourcegraph.com/github.com/goal-web/contracts?badge)\n[![Open Source Helpers](https://www.codetriage.com/goal-web/goal/badges/users.svg)](https://www.codetriage.com/goal-web/goal)\n[![Release](https://img.shields.io/github/release/goal-web/goal.svg?style=flat-square)](https://github.com/goal-web/goal/releases)\n[![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)\n\n## Star History\n![https://api.star-history.com/svg?repos=goal-web/goal&type=Date](https://api.star-history.com/svg?repos=goal-web/goal&type=Date)\n\n## About Goal Framework\n\nGoal 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:\n\n- [Simple and powerful middleware](https://github.com/goal-web/pipeline).\n- [Powerful dependency injection container](https://github.com/goal-web/container).\n- Multiple back-ends for [session](https://github.com/goal-web/session) and [cache](https://github.com/goal-web/cache) storage.\n- Expressive, intuitive [database](https://github.com/goal-web/database).\n- [Robust background job processing](https://github.com/goal-web/queue).\n\nGoal framework is accessible, powerful, and provides tools required for large, robust applications.\n\n## Learning Goal Framework\n* [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)\n* [Documents](https://github.com/goal-web/doc/blob/wiki/README.md)\n\n## Contributing\n\nThank 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).\n\n## License\n\nThe Goal framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT)."
  },
  {
    "path": "app/console/commands/runner.go",
    "content": "package commands\n\nimport (\n\t\"fmt\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/supports/commands\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"os\"\n)\n\ntype runner struct {\n\tcommands.Command\n\tapp contracts.Application\n}\n\nfunc Runner() (contracts.Command, contracts.CommandHandlerProvider) {\n\treturn commands.Base(\"run\", \"启动 goal\"),\n\t\tfunc(app contracts.Application) contracts.CommandHandler {\n\t\t\treturn &runner{app: app}\n\t\t}\n}\n\nfunc (runner *runner) Handle() any {\n\tpath, _ := os.Getwd()\n\tpidPath := path + \"/goal.pid\"\n\t// 写入 pid 文件\n\t_ = os.WriteFile(pidPath, []byte(fmt.Sprintf(\"%d\", os.Getpid())), os.ModePerm)\n\n\tif errors := runner.app.Start(); len(errors) > 0 {\n\t\tlogs.WithField(\"errors\", errors).Fatal(\"goal 启动异常!\")\n\t} else {\n\t\t_ = os.Remove(pidPath)\n\t\tlogs.Default().Info(\"goal 已关闭\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "app/console/kernel.go",
    "content": "package console\n\nimport (\n\t\"github.com/goal-web/config\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/console/commands\"\n\t\"github.com/goal-web/supports/logs\"\n)\n\nvar Commands = []contracts.CommandProvider{\n\tcommands.Runner,\n\tconfig.EncryptionCommand,\n}\n\nfunc Schedule(schedule contracts.Schedule) {\n\tschedule.Call(func() {\n\t\t//fmt.Println(\"打印 hello\")\n\t\tlogs.Default().Info(\"打印 hello\")\n\t}).EveryFiveSeconds()\n}\n"
  },
  {
    "path": "app/controllers/helloworld.go",
    "content": "package controllers\n\nimport (\n\t\"fmt\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/models\"\n\t\"github.com/gookit/goutil/dump\"\n)\n\nfunc HelloWorld() any {\n\tcreateProject()\n\tupdateProject()\n\tdump.P(23)\n\tprojects := getProjectList()\n\treturn contracts.Fields{\n\t\t\"data\": projects,\n\t}\n}\n\nfunc createProject() {\n\tfields := contracts.Fields{\n\t\t\"uuid\":           \"45\",\n\t\t\"name\":           \"your_project_name\",\n\t\t\"creator_id\":     1,\n\t\t\"group_id\":       1,\n\t\t\"key_id\":         1,\n\t\t\"repo_address\":   \"your_repo_address\",\n\t\t\"project_path\":   \"your_project_path\",\n\t\t\"default_branch\": \"main\",\n\t\t\"settings\":       \"{}\",\n\t}\n\tmodel := models.NewProjectModel(fields)\n\terr := model.Save()\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create project: %v\\n\", err)\n\t} else {\n\t\tfmt.Println(\"Project created successfully111\")\n\t}\n}\n\nfunc getProjectOne() any {\n\tquery := models.ProjectQuery()\n\tproject := query.Where(\"id\", 1).First() // 假设查询 id 为 1 的记录\n\tfmt.Printf(\"Project: %+v\\n\", project)\n\n\treturn project\n}\n\nfunc getProjectList() any {\n\tquery := models.ProjectQuery()\n\n\tprojects := query.Get().ToAnyArray() //\n\tdump.P(projects)\n\n\treturn projects\n}\n\nfunc updateProject() {\n\tquery := models.ProjectQuery()\n\tproject := query.Where(\"id\", 1).First() // 假设更新 id 为 1 的记录\n\n\tupdateFields := contracts.Fields{\n\t\t\"name\": \"updated_project_name11\",\n\t}\n\terr := project.Update(updateFields)\n\n\tdump.P(err)\n}\n\nfunc deleteProject() {\n\tquery := models.ProjectQuery()\n\tproject := query.Where(\"id\", 1).First() // 假设删除 id 为 1 的记录\n\n\t_ = project.Delete()\n\n}\n"
  },
  {
    "path": "app/controllers/kernel.go",
    "content": "package controllers\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/controllers/project\"\n\t\"github.com/goal-web/goal/app/controllers/user\"\n)\n\n// Register 注册路由函数\nfunc Register(router contracts.HttpRouter) {\n\tuser.AuthServiceRouter(router)\n\tproject.ProjectServiceRouter(router)\n\n\t// 在这里添加您的路由注册逻辑\n}\n"
  },
  {
    "path": "app/controllers/project/Project_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tproject \"github.com/goal-web/goal/app/requests/project\"\n\t\"github.com/goal-web/goal/app/response\"\n\tsvc \"github.com/goal-web/goal/app/services/project\"\n\t\"github.com/goal-web/validation\"\n)\n\nfunc ProjectServiceRouter(router contracts.HttpRouter) {\n\trouteGroup := router.Group(\"/project\")\n\trouteGroup.Post(\"/CreateProject\", ProjectServiceCreateProject)\n\trouteGroup.Get(\"/GetProject\", ProjectServiceGetProject)\n\trouteGroup.Get(\"/ListProjects\", ProjectServiceListProjects)\n\trouteGroup.Post(\"/UpdateProject\", ProjectServiceUpdateProject)\n\trouteGroup.Post(\"/DeleteProject\", ProjectServiceDeleteProject)\n}\nfunc ProjectServiceCreateProject(request contracts.HttpRequest) any {\n\tvar req project.CreateProjectReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.ProjectServiceCreateProject(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\nfunc ProjectServiceGetProject(request contracts.HttpRequest) any {\n\tvar req project.GetProjectReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.ProjectServiceGetProject(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\nfunc ProjectServiceListProjects(request contracts.HttpRequest) any {\n\tvar req project.ListProjectsReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.ProjectServiceListProjects(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\nfunc ProjectServiceUpdateProject(request contracts.HttpRequest) any {\n\tvar req project.UpdateProjectReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.ProjectServiceUpdateProject(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\nfunc ProjectServiceDeleteProject(request contracts.HttpRequest) any {\n\tvar req project.DeleteProjectReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.ProjectServiceDeleteProject(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\n"
  },
  {
    "path": "app/controllers/user/Auth_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tuser \"github.com/goal-web/goal/app/requests/user\"\n\t\"github.com/goal-web/goal/app/response\"\n\tsvc \"github.com/goal-web/goal/app/services/user\"\n\t\"github.com/goal-web/validation\"\n)\n\nfunc AuthServiceRouter(router contracts.HttpRouter) {\n\trouteGroup := router.Group(\"/auth\")\n\trouteGroup.Post(\"/LoginByWxAppCode\", AuthServiceLoginByWxAppCode, \"guest\")\n\trouteGroup.Post(\"/LoginByWxAppInfo\", AuthServiceLoginByWxAppInfo, \"guest\")\n}\nfunc AuthServiceLoginByWxAppCode(request contracts.HttpRequest) any {\n\tvar req user.LoginByWxCodeReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.AuthServiceLoginByWxAppCode(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\nfunc AuthServiceLoginByWxAppInfo(request contracts.HttpRequest) any {\n\tvar req user.LoginByWxInfoReq\n\n\tif err := request.Parse(&req); err != nil {\n\t\treturn response.ParseReqErr(err)\n\t}\n\n\tif err := validation.Struct(req); err != nil {\n\t\treturn response.InvalidReq(err)\n\t}\n\n\tresp, err := svc.AuthServiceLoginByWxAppInfo(&req, request)\n\tif err != nil {\n\t\treturn response.BizErr(err)\n\t}\n\n\treturn response.Success(resp)\n}\n"
  },
  {
    "path": "app/enums/Code_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/common.proto\n// \npackage enums\n\ntype Code int\n\nconst (\n\n\t// CodeSuccess\n\t// @msg:成功\n\tCodeSuccess Code = 0\n\n\t// CodeParseReqErr\n\t// @msg:参数解析失败\n\tCodeParseReqErr Code = 10400\n\n\t// CodeUnauthorized\n\t// @msg:未登录\n\tCodeUnauthorized Code = 10401\n\n\t// CodeForbidden\n\t// @msg:没有权限\n\tCodeForbidden Code = 100403\n\n\t// CodeNotFound\n\t// @msg:找不到\n\tCodeNotFound Code = 100404\n\n\t// CodeBizErr\n\t// @msg:业务错误\n\tCodeBizErr  Code = 10201\n\tCodeUnknown Code = -1000\n)\n\nfunc (item Code) String() string {\n\tswitch item {\n\tcase CodeSuccess:\n\t\treturn \"Success\"\n\tcase CodeParseReqErr:\n\t\treturn \"ParseReqErr\"\n\tcase CodeUnauthorized:\n\t\treturn \"Unauthorized\"\n\tcase CodeForbidden:\n\t\treturn \"Forbidden\"\n\tcase CodeNotFound:\n\t\treturn \"NotFound\"\n\tcase CodeBizErr:\n\t\treturn \"BizErr\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\nfunc (item Code) Message() string {\n\tswitch item {\n\tcase CodeSuccess:\n\t\treturn \"成功\"\n\tcase CodeParseReqErr:\n\t\treturn \"参数解析失败\"\n\tcase CodeUnauthorized:\n\t\treturn \"未登录\"\n\tcase CodeForbidden:\n\t\treturn \"没有权限\"\n\tcase CodeNotFound:\n\t\treturn \"找不到\"\n\tcase CodeBizErr:\n\t\treturn \"业务错误\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\nfunc ParseCodeFromString(msg string) Code {\n\tswitch msg {\n\tcase \"Success\":\n\t\treturn CodeSuccess\n\tcase \"ParseReqErr\":\n\t\treturn CodeParseReqErr\n\tcase \"Unauthorized\":\n\t\treturn CodeUnauthorized\n\tcase \"Forbidden\":\n\t\treturn CodeForbidden\n\tcase \"NotFound\":\n\t\treturn CodeNotFound\n\tcase \"BizErr\":\n\t\treturn CodeBizErr\n\tdefault:\n\t\treturn CodeUnknown\n\t}\n}\n"
  },
  {
    "path": "app/exceptions/handler.go",
    "content": "package exceptions\n\nimport (\n\t\"reflect\"\n\t\"runtime/debug\"\n\t\"strings\"\n\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/http\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"github.com/goal-web/validation\"\n)\n\ntype ExceptionHandler struct {\n\tdontReportExceptions []reflect.Type\n}\n\nfunc NewHandler() contracts.ExceptionHandler {\n\treturn &ExceptionHandler{utils.ToTypes([]contracts.Exception{})}\n}\n\nfunc (handler *ExceptionHandler) Handle(exception contracts.Exception) any {\n\tlogs.WithException(exception).Warn(\"报错了\")\n\tswitch e := exception.(type) {\n\tcase http.Exception: // http 支持在异常处理器返回响应\n\t\treturn handler.handleHttpException(e)\n\tcase *validation.Exception:\n\t\treturn handler.renderValidationException(e)\n\tdefault:\n\t\tdebug.PrintStack()\n\t}\n\n\tlogs.WithException(exception).\n\t\tWithField(\"exception\", reflect.TypeOf(exception).String()).\n\t\tError(\"ExceptionHandler\")\n\n\tif httpException, isHttpException := exception.(http.Exception); isHttpException {\n\t\tlogs.WithException(httpException).WithFields(contracts.Fields{}).Debug(\"http请求报错\")\n\t}\n\n\tif handler.ShouldReport(exception) {\n\t\thandler.Report(exception)\n\t}\n\n\treturn nil\n}\n\nfunc (handler *ExceptionHandler) handleHttpException(exception http.Exception) any {\n\n\tswitch e := exception.Exception.(type) {\n\tcase *validation.Exception:\n\t\treturn handler.renderValidationException(e)\n\tdefault:\n\t\tif !strings.Contains(exception.Error(), \"404\") {\n\t\t\tdebug.PrintStack()\n\t\t}\n\t\treturn contracts.Fields{\n\t\t\t\"path\":  exception.Request.Path(),\n\t\t\t\"error\": e.Error(),\n\t\t}\n\t}\n}\n\nfunc (handler *ExceptionHandler) renderValidationException(exception *validation.Exception) any {\n\treturn contracts.Fields{\n\t\t\"msg\":    exception.Error(),\n\t\t\"fields\": exception.Param,\n\t\t\"errors\": exception.Errors,\n\t}\n}\n\nfunc (handler *ExceptionHandler) Report(exception contracts.Exception) {\n}\nfunc (handler *ExceptionHandler) ShouldReport(exception contracts.Exception) bool {\n\treturn !utils.IsInstanceIn(exception, handler.dontReportExceptions...)\n}\n"
  },
  {
    "path": "app/http/middlewares/example.go",
    "content": "package middlewares\n\nimport (\n\t\"fmt\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/http\"\n)\n\nfunc Example(request contracts.HttpRequest, next contracts.Pipe) any {\n\tfmt.Println(\"controller before\")\n\n\tresult := next(request)\n\n\tfmt.Println(\"controller after\")\n\treturn http.NewJsonResponse(contracts.Fields{\n\t\t\"result\": result,\n\t}, 200)\n}\n"
  },
  {
    "path": "app/http/sse/demo.go",
    "content": "package sse\n\nimport (\n\t\"errors\"\n\t\"github.com/goal-web/contracts\"\n)\n\ntype DemoController struct {\n}\n\nfunc (d DemoController) OnConnect(request contracts.HttpRequest, fd uint64) error {\n\t// 伪代码\n\tif request.GetString(\"token\") != \"goal\" {\n\t\treturn errors.New(\"401\")\n\t}\n\n\t// todo: 绑定用户和 fd\n\n\treturn nil\n}\n\nfunc (d DemoController) OnClose(fd uint64) {\n\t// todo: 实现解绑\n}\n"
  },
  {
    "path": "app/jobs/demo.go",
    "content": "package jobs\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/queue\"\n\t\"github.com/goal-web/supports/class\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"time\"\n)\n\nvar DemoClass = class.Any(Demo{})\n\ntype Demo struct {\n\t*queue.Job\n\tInfo string `json:\"info\"`\n}\n\nfunc NewDemo(info string) contracts.Job {\n\treturn &Demo{\n\t\tJob: &queue.Job{\n\t\t\tUUID:       utils.RandStr(5),\n\t\t\tCreatedAt:  time.Now().Unix(),\n\t\t\tQueue:      \"default\",\n\t\t\tConnection: \"default\",\n\t\t\tTries:      0,\n\t\t\tMaxTries:   3,\n\t\t\tTimeout:    0,\n\t\t},\n\t\tInfo: info,\n\t}\n}\n\nfunc (demo *Demo) Handle() {\n\tlogs.Default().WithField(\"info\", demo.Info).Info(\"demo job\")\n}\n"
  },
  {
    "path": "app/listeners/debug_query.go",
    "content": "package listeners\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database/events\"\n\t\"github.com/goal-web/supports/logs\"\n)\n\ntype DebugQuery struct {\n}\n\nfunc (d DebugQuery) Handle(event contracts.Event) {\n\tif e, ok := event.(*events.QueryExecuted); ok {\n\t\tlogs.WithFields(contracts.Fields{\n\t\t\t\"sql\":        e.Sql,\n\t\t\t\"bindings\":   e.Bindings,\n\t\t\t\"connection\": e.Connection,\n\t\t\t\"time\":       e.Time,\n\t\t}).Debug(\"sql executed\")\n\t}\n}\n"
  },
  {
    "path": "app/models/Article_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Article.proto\n// \npackage models\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/goal-web/collection\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database/table\"\n\t\"github.com/goal-web/migration/migrate\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"github.com/spf13/cast\"\n)\n\nvar ()\n\n// ArticleModel\n// @timestamps\ntype ArticleModel struct {\n\tId uint32 `json:\"id\" query:\"id\" form:\"id\" db:\"id;type:INT UNSIGNED;not null;primary key;AUTO_INCREMENT;\"`\n\n\tTitle string `json:\"title\" query:\"title\" form:\"title\" db:\"title;type:VARCHAR(255);not null;\"`\n\n\tCreatedAt string `json:\"created_at\" query:\"created_at\" form:\"created_at\" db:\"created_at;type:timestamp;default CURRENT_TIMESTAMP;\"`\n\n\tUpdatedAt string `json:\"updated_at\" query:\"updated_at\" form:\"updated_at\" db:\"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;\"`\n\n\t_raw    contracts.Fields\n\t_update contracts.Fields\n\t_append contracts.Fields\n\t_hidden map[string]struct{}\n\n\t_relation_loaded map[contracts.RelationType]struct{}\n}\n\nvar ArticleDefine ArticleStatic\n\ntype ArticleStatic struct {\n\tTableName       string\n\tHidden          []string\n\tIndexes         []string\n\tWith            []contracts.RelationType\n\tAppends         map[string]func(model *ArticleModel) any\n\tIdGetter        func(model *ArticleModel, raw uint32) uint32\n\tIdSetter        func(model *ArticleModel, raw uint32) uint32\n\tTitleGetter     func(model *ArticleModel, raw string) string\n\tTitleSetter     func(model *ArticleModel, raw string) string\n\tCreatedAtGetter func(model *ArticleModel, raw string) string\n\tCreatedAtSetter func(model *ArticleModel, raw string) string\n\tUpdatedAtGetter func(model *ArticleModel, raw string) string\n\tUpdatedAtSetter func(model *ArticleModel, raw string) string\n\n\tSaving           func(model *ArticleModel) contracts.Exception\n\tSaved            func(model *ArticleModel)\n\tUpdating         func(model *ArticleModel, fields contracts.Fields) contracts.Exception\n\tUpdated          func(model *ArticleModel, fields contracts.Fields)\n\tDeleting         func(model *ArticleModel) contracts.Exception\n\tDeleted          func(model *ArticleModel)\n\tPrimaryKeyGetter func(model *ArticleModel) any\n}\n\nfunc ArticleMigrator() migrate.Migrator {\n\treturn func(executor contracts.SqlExecutor) contracts.Exception {\n\t\treturn migrate.Migrate(ArticleDefine.TableName, ArticleDefine.Indexes, ArticleModel{}, executor)\n\t}\n}\n\nfunc init() {\n\tArticleDefine.TableName = \"articles\"\n\tArticleDefine.Appends = make(map[string]func(model *ArticleModel) any)\n}\n\nfunc NewArticleModel(fields contracts.Fields) *ArticleModel {\n\tvar model = ArticleModel{\n\t\t_raw: fields,\n\t}\n\tmodel.Set(fields)\n\treturn &model\n}\n\nfunc ArticleModelSingleRelationSetter[T any](key contracts.RelationType) func(item *ArticleModel, value []any) {\n\treturn func(item *ArticleModel, values []any) {\n\t\tvar value T\n\t\tif len(values) > 0 {\n\t\t\tvalue = values[0].(T)\n\t\t}\n\t\titem.Set(contracts.Fields{\n\t\t\tstring(key): value,\n\t\t})\n\t}\n}\nfunc ArticleModelMultiRelationSetter[T any](key contracts.RelationType) func(item *ArticleModel, value []any) {\n\treturn func(model *ArticleModel, value []any) {\n\t\tvar results []T\n\t\tfor _, item := range value {\n\t\t\tresults = append(results, item.(T))\n\t\t}\n\t\tmodel.Set(contracts.Fields{string(key): results})\n\t}\n}\n\nfunc ArticleModelLocalKeyGetter(key string) func(item *ArticleModel) any {\n\treturn func(item *ArticleModel) any {\n\t\treturn item.Get(key)\n\t}\n}\n\nfunc ArticleModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tfor key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\n\nfunc ArticleModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tgroupKey := fmt.Sprintf(\"%s.%s\", midTable, firstKey)\n\t\tfor key, values := range query().\n\t\t\tAddSelect(fmt.Sprintf(\"(%s) as _group_key\", groupKey)).\n\t\t\tWhereIn(groupKey, keys).\n\t\t\tJoin(midTable, fmt.Sprintf(\"%s.%s\", midTable, secondLocalKey), \"=\", fmt.Sprintf(\"%s.%s\", query().GetTableName(), secondKey)).\n\t\t\tGet().GroupBy(\"_group_key\") {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\nfunc ArticleQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[ArticleModel] {\n\treturn ArticleQuery().SetExecutor(executor)\n}\n\nfunc ArticleQuery() *table.Table[ArticleModel] {\n\treturn table.NewQuery(ArticleDefine.TableName, NewArticleModel).\n\t\tSetPrimaryKey(\"id\").\n\t\tSetCreatedTimeColumn(\"created_at\").\n\t\tSetUpdatedTimeColumn(\"updated_at\").\n\t\tSetWiths(ArticleDefine.With...)\n}\n\nfunc (model *ArticleModel) Hidden(fields ...string) *ArticleModel {\n\tfor _, field := range fields {\n\t\tif model._hidden == nil {\n\t\t\tmodel._hidden = map[string]struct{}{\n\t\t\t\tfield: struct{}{},\n\t\t\t}\n\t\t} else {\n\t\t\tmodel._hidden[field] = struct{}{}\n\t\t}\n\n\t}\n\n\treturn model\n}\n\nfunc (model *ArticleModel) Exists() bool {\n\treturn ArticleQuery().Where(\"id\", model.GetPrimaryKey()).Count() > 0\n}\n\nfunc (model *ArticleModel) Save() contracts.Exception {\n\tif model._update == nil {\n\t\treturn nil\n\t}\n\tif ArticleDefine.Saving != nil {\n\t\tif err := ArticleDefine.Saving(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tvar err contracts.Exception\n\tvar pk = model.GetPrimaryKey()\n\tif cast.ToUint64(pk) == 0 {\n\t\tpk, err = ArticleQuery().Where(\"id\", model.GetPrimaryKey()).InsertGetIdE(model._update)\n\t\tif err == nil {\n\t\t\tmodel.SetId(cast.ToUint32(pk))\n\t\t}\n\t} else {\n\t\t_, err = ArticleQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(model._update)\n\t}\n\tif err == nil {\n\t\tmodel._update = nil\n\t\tif ArticleDefine.Saved != nil {\n\t\t\tArticleDefine.Saved(model)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *ArticleModel) Set(fields contracts.Fields) {\n\tfor key, value := range fields {\n\n\t\tswitch key {\n\t\tcase \"id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase uint32:\n\t\t\t\tmodel.SetId(v)\n\t\t\tcase func() uint32:\n\t\t\t\tmodel.SetId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd uint32\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd uint32\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetId(cast.ToUint32(v))\n\t\t\t}\n\t\tcase \"title\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetTitle(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetTitle(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetTitle(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetTitle(cast.ToString(v))\n\t\t\t}\n\t\tcase \"created_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetCreatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetCreatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetCreatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetCreatedAt(cast.ToString(v))\n\t\t\t}\n\t\tcase \"updated_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetUpdatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetUpdatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetUpdatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetUpdatedAt(cast.ToString(v))\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (model *ArticleModel) Only(key ...string) contracts.Fields {\n\tvar fields = make(contracts.Fields)\n\tfor _, k := range key {\n\t\tif k == \"id\" {\n\t\t\tfields[k] = model.GetId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"title\" {\n\t\t\tfields[k] = model.GetTitle()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"created_at\" {\n\t\t\tfields[k] = model.GetCreatedAt()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"updated_at\" {\n\t\t\tfields[k] = model.GetUpdatedAt()\n\t\t\tcontinue\n\t\t}\n\n\t\tif ArticleDefine.Appends[k] != nil {\n\t\t\tfields[k] = ArticleDefine.Appends[k](model)\n\t\t}\n\t}\n\treturn fields\n}\n\nfunc (model *ArticleModel) Get(key string) any {\n\tswitch key {\n\tcase \"id\":\n\t\treturn model.GetId()\n\tcase \"title\":\n\t\treturn model.GetTitle()\n\tcase \"created_at\":\n\t\treturn model.GetCreatedAt()\n\tcase \"updated_at\":\n\t\treturn model.GetUpdatedAt()\n\t}\n\n\tif value, exists := model._append[key]; exists {\n\t\treturn value\n\t}\n\n\tif fn, exists := ArticleDefine.Appends[key]; exists {\n\t\tmodel._append[key] = fn(model)\n\t\treturn model._append[key]\n\t}\n\n\tswitch contracts.RelationType(key) {\n\t}\n\n\treturn nil\n}\n\nfunc (model *ArticleModel) Except(keys ...string) contracts.Fields {\n\tvar excepts = map[string]struct{}{}\n\tfor _, k := range keys {\n\t\texcepts[k] = struct{}{}\n\t}\n\tvar fields = make(contracts.Fields)\n\tfor key, value := range model.ToFields() {\n\t\tif _, ok := excepts[key]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tfields[key] = value\n\t}\n\treturn fields\n}\n\nfunc (model *ArticleModel) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\n\tmodel.Hidden(ArticleDefine.Hidden...)\n\n\tfields := contracts.Fields{}\n\tif _, exists := model._hidden[\"id\"]; !exists {\n\t\tfields[\"id\"] = model.GetId()\n\t}\n\tif _, exists := model._hidden[\"title\"]; !exists {\n\t\tfields[\"title\"] = model.GetTitle()\n\t}\n\tif _, exists := model._hidden[\"created_at\"]; !exists {\n\t\tfields[\"created_at\"] = model.GetCreatedAt()\n\t}\n\tif _, exists := model._hidden[\"updated_at\"]; !exists {\n\t\tfields[\"updated_at\"] = model.GetUpdatedAt()\n\t}\n\n\tfor key := range ArticleDefine.Appends {\n\t\tvalue := model.Get(key)\n\t\tif fieldsProvider, ok := value.(contracts.FieldsProvider); ok {\n\t\t\tfields[key] = fieldsProvider.ToFields()\n\t\t} else {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\tfor key := range model._relation_loaded {\n\t\tswitch key {\n\t\t}\n\t}\n\n\tfor key, value := range model._raw {\n\t\t_, hidden := model._hidden[key]\n\t\tif _, exists := fields[key]; !exists && !hidden {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\treturn fields\n}\n\nfunc (model *ArticleModel) Update(fields contracts.Fields) contracts.Exception {\n\n\tif ArticleDefine.Updating != nil {\n\t\tif err := ArticleDefine.Updating(model, fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif model._update != nil {\n\t\tutils.MergeFields(model._update, fields)\n\t}\n\n\t_, err := ArticleQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(fields)\n\n\tif err == nil {\n\t\tmodel.Set(fields)\n\t\tmodel._update = nil\n\t\tif ArticleDefine.Updated != nil {\n\t\t\tArticleDefine.Updated(model, fields)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *ArticleModel) Refresh() contracts.Exception {\n\tfields, err := table.ArrayQuery(\"articles\").Where(\"id\", model.GetPrimaryKey()).FirstE()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmodel.Set(*fields)\n\treturn nil\n}\n\nfunc (model *ArticleModel) Delete() contracts.Exception {\n\n\tif ArticleDefine.Deleting != nil {\n\t\tif err := ArticleDefine.Deleting(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t_, err := ArticleQuery().Where(\"id\", model.GetPrimaryKey()).DeleteE()\n\tif err == nil && ArticleDefine.Deleted != nil {\n\t\tArticleDefine.Deleted(model)\n\t}\n\n\treturn err\n}\n\nfunc (model *ArticleModel) GetPrimaryKey() any {\n\tif ArticleDefine.PrimaryKeyGetter != nil {\n\t\treturn ArticleDefine.PrimaryKeyGetter(model)\n\t}\n\n\treturn model.Id\n}\n\nfunc (model *ArticleModel) GetId() uint32 {\n\tif ArticleDefine.IdGetter != nil {\n\t\treturn ArticleDefine.IdGetter(model, model.Id)\n\t}\n\treturn model.Id\n}\n\nfunc (model *ArticleModel) SetId(value uint32) {\n\tif ArticleDefine.IdSetter != nil {\n\t\tvalue = ArticleDefine.IdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"id\": value}\n\t} else {\n\t\tmodel._update[\"id\"] = value\n\t}\n\tmodel.Id = value\n}\n\nfunc (model *ArticleModel) GetTitle() string {\n\tif ArticleDefine.TitleGetter != nil {\n\t\treturn ArticleDefine.TitleGetter(model, model.Title)\n\t}\n\treturn model.Title\n}\n\nfunc (model *ArticleModel) SetTitle(value string) {\n\tif ArticleDefine.TitleSetter != nil {\n\t\tvalue = ArticleDefine.TitleSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"title\": value}\n\t} else {\n\t\tmodel._update[\"title\"] = value\n\t}\n\tmodel.Title = value\n}\n\nfunc (model *ArticleModel) GetCreatedAt() string {\n\tif ArticleDefine.CreatedAtGetter != nil {\n\t\treturn ArticleDefine.CreatedAtGetter(model, model.CreatedAt)\n\t}\n\treturn model.CreatedAt\n}\n\nfunc (model *ArticleModel) SetCreatedAt(value string) {\n\tif ArticleDefine.CreatedAtSetter != nil {\n\t\tvalue = ArticleDefine.CreatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"created_at\": value}\n\t} else {\n\t\tmodel._update[\"created_at\"] = value\n\t}\n\tmodel.CreatedAt = value\n}\n\nfunc (model *ArticleModel) GetUpdatedAt() string {\n\tif ArticleDefine.UpdatedAtGetter != nil {\n\t\treturn ArticleDefine.UpdatedAtGetter(model, model.UpdatedAt)\n\t}\n\treturn model.UpdatedAt\n}\n\nfunc (model *ArticleModel) SetUpdatedAt(value string) {\n\tif ArticleDefine.UpdatedAtSetter != nil {\n\t\tvalue = ArticleDefine.UpdatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"updated_at\": value}\n\t} else {\n\t\tmodel._update[\"updated_at\"] = value\n\t}\n\tmodel.UpdatedAt = value\n}\n"
  },
  {
    "path": "app/models/Project_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage models\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/goal-web/collection\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database/table\"\n\t\"github.com/goal-web/migration/migrate\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"github.com/spf13/cast\"\n)\n\nvar ()\n\n// ProjectModel\n// @timestamps\ntype ProjectModel struct {\n\tId int64 `json:\"id\" query:\"id\" form:\"id\" db:\"id;type:BIGINT;not null;primary key;AUTO_INCREMENT;\"`\n\n\tUuid string `json:\"uuid\" query:\"uuid\" form:\"uuid\" db:\"uuid;type:VARCHAR(255);not null;\"`\n\n\tName string `json:\"name\" query:\"name\" form:\"name\" db:\"name;type:VARCHAR(255);not null;\"`\n\n\tCreatorId int64 `json:\"creator_id\" query:\"creator_id\" form:\"creator_id\" db:\"creator_id;type:BIGINT;not null;\"`\n\n\tGroupId int64 `json:\"group_id\" query:\"group_id\" form:\"group_id\" db:\"group_id;type:BIGINT;not null;\"`\n\n\tKeyId int64 `json:\"key_id\" query:\"key_id\" form:\"key_id\" db:\"key_id;type:BIGINT;not null;\"`\n\n\tRepoAddress string `json:\"repo_address\" query:\"repo_address\" form:\"repo_address\" db:\"repo_address;type:VARCHAR(255);not null;\"`\n\n\tProjectPath string `json:\"project_path\" query:\"project_path\" form:\"project_path\" db:\"project_path;type:VARCHAR(255);not null;\"`\n\n\tDefaultBranch string `json:\"default_branch\" query:\"default_branch\" form:\"default_branch\" db:\"default_branch;type:VARCHAR(255);not null;\"`\n\n\tSettings string `json:\"settings\" query:\"settings\" form:\"settings\" db:\"settings;type:VARCHAR(255);not null;\"`\n\n\tCreatedAt string `json:\"created_at\" query:\"created_at\" form:\"created_at\" db:\"created_at;type:timestamp;default CURRENT_TIMESTAMP;\"`\n\n\tUpdatedAt string `json:\"updated_at\" query:\"updated_at\" form:\"updated_at\" db:\"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;\"`\n\n\t_raw    contracts.Fields\n\t_update contracts.Fields\n\t_append contracts.Fields\n\t_hidden map[string]struct{}\n\n\t_relation_loaded map[contracts.RelationType]struct{}\n}\n\nvar ProjectDefine ProjectStatic\n\ntype ProjectStatic struct {\n\tTableName           string\n\tHidden              []string\n\tIndexes             []string\n\tWith                []contracts.RelationType\n\tAppends             map[string]func(model *ProjectModel) any\n\tIdGetter            func(model *ProjectModel, raw int64) int64\n\tIdSetter            func(model *ProjectModel, raw int64) int64\n\tUuidGetter          func(model *ProjectModel, raw string) string\n\tUuidSetter          func(model *ProjectModel, raw string) string\n\tNameGetter          func(model *ProjectModel, raw string) string\n\tNameSetter          func(model *ProjectModel, raw string) string\n\tCreatorIdGetter     func(model *ProjectModel, raw int64) int64\n\tCreatorIdSetter     func(model *ProjectModel, raw int64) int64\n\tGroupIdGetter       func(model *ProjectModel, raw int64) int64\n\tGroupIdSetter       func(model *ProjectModel, raw int64) int64\n\tKeyIdGetter         func(model *ProjectModel, raw int64) int64\n\tKeyIdSetter         func(model *ProjectModel, raw int64) int64\n\tRepoAddressGetter   func(model *ProjectModel, raw string) string\n\tRepoAddressSetter   func(model *ProjectModel, raw string) string\n\tProjectPathGetter   func(model *ProjectModel, raw string) string\n\tProjectPathSetter   func(model *ProjectModel, raw string) string\n\tDefaultBranchGetter func(model *ProjectModel, raw string) string\n\tDefaultBranchSetter func(model *ProjectModel, raw string) string\n\tSettingsGetter      func(model *ProjectModel, raw string) string\n\tSettingsSetter      func(model *ProjectModel, raw string) string\n\tCreatedAtGetter     func(model *ProjectModel, raw string) string\n\tCreatedAtSetter     func(model *ProjectModel, raw string) string\n\tUpdatedAtGetter     func(model *ProjectModel, raw string) string\n\tUpdatedAtSetter     func(model *ProjectModel, raw string) string\n\n\tSaving           func(model *ProjectModel) contracts.Exception\n\tSaved            func(model *ProjectModel)\n\tUpdating         func(model *ProjectModel, fields contracts.Fields) contracts.Exception\n\tUpdated          func(model *ProjectModel, fields contracts.Fields)\n\tDeleting         func(model *ProjectModel) contracts.Exception\n\tDeleted          func(model *ProjectModel)\n\tPrimaryKeyGetter func(model *ProjectModel) any\n}\n\nfunc ProjectMigrator() migrate.Migrator {\n\treturn func(executor contracts.SqlExecutor) contracts.Exception {\n\t\treturn migrate.Migrate(ProjectDefine.TableName, ProjectDefine.Indexes, ProjectModel{}, executor)\n\t}\n}\n\nfunc init() {\n\tProjectDefine.TableName = \"projects\"\n\tProjectDefine.Appends = make(map[string]func(model *ProjectModel) any)\n}\n\nfunc NewProjectModel(fields contracts.Fields) *ProjectModel {\n\tvar model = ProjectModel{\n\t\t_raw: fields,\n\t}\n\tmodel.Set(fields)\n\treturn &model\n}\n\nfunc ProjectModelSingleRelationSetter[T any](key contracts.RelationType) func(item *ProjectModel, value []any) {\n\treturn func(item *ProjectModel, values []any) {\n\t\tvar value T\n\t\tif len(values) > 0 {\n\t\t\tvalue = values[0].(T)\n\t\t}\n\t\titem.Set(contracts.Fields{\n\t\t\tstring(key): value,\n\t\t})\n\t}\n}\nfunc ProjectModelMultiRelationSetter[T any](key contracts.RelationType) func(item *ProjectModel, value []any) {\n\treturn func(model *ProjectModel, value []any) {\n\t\tvar results []T\n\t\tfor _, item := range value {\n\t\t\tresults = append(results, item.(T))\n\t\t}\n\t\tmodel.Set(contracts.Fields{string(key): results})\n\t}\n}\n\nfunc ProjectModelLocalKeyGetter(key string) func(item *ProjectModel) any {\n\treturn func(item *ProjectModel) any {\n\t\treturn item.Get(key)\n\t}\n}\n\nfunc ProjectModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tfor key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\n\nfunc ProjectModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tgroupKey := fmt.Sprintf(\"%s.%s\", midTable, firstKey)\n\t\tfor key, values := range query().\n\t\t\tAddSelect(fmt.Sprintf(\"(%s) as _group_key\", groupKey)).\n\t\t\tWhereIn(groupKey, keys).\n\t\t\tJoin(midTable, fmt.Sprintf(\"%s.%s\", midTable, secondLocalKey), \"=\", fmt.Sprintf(\"%s.%s\", query().GetTableName(), secondKey)).\n\t\t\tGet().GroupBy(\"_group_key\") {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\nfunc ProjectQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[ProjectModel] {\n\treturn ProjectQuery().SetExecutor(executor)\n}\n\nfunc ProjectQuery() *table.Table[ProjectModel] {\n\treturn table.NewQuery(ProjectDefine.TableName, NewProjectModel).\n\t\tSetPrimaryKey(\"id\").\n\t\tSetCreatedTimeColumn(\"created_at\").\n\t\tSetUpdatedTimeColumn(\"updated_at\").\n\t\tSetWiths(ProjectDefine.With...)\n}\n\nfunc (model *ProjectModel) Hidden(fields ...string) *ProjectModel {\n\tfor _, field := range fields {\n\t\tif model._hidden == nil {\n\t\t\tmodel._hidden = map[string]struct{}{\n\t\t\t\tfield: struct{}{},\n\t\t\t}\n\t\t} else {\n\t\t\tmodel._hidden[field] = struct{}{}\n\t\t}\n\n\t}\n\n\treturn model\n}\n\nfunc (model *ProjectModel) Exists() bool {\n\treturn ProjectQuery().Where(\"id\", model.GetPrimaryKey()).Count() > 0\n}\n\nfunc (model *ProjectModel) Save() contracts.Exception {\n\tif model._update == nil {\n\t\treturn nil\n\t}\n\tif ProjectDefine.Saving != nil {\n\t\tif err := ProjectDefine.Saving(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tvar err contracts.Exception\n\tvar pk = model.GetPrimaryKey()\n\tif cast.ToUint64(pk) == 0 {\n\t\tpk, err = ProjectQuery().Where(\"id\", model.GetPrimaryKey()).InsertGetIdE(model._update)\n\t\tif err == nil {\n\t\t\tmodel.SetId(cast.ToInt64(pk))\n\t\t}\n\t} else {\n\t\t_, err = ProjectQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(model._update)\n\t}\n\tif err == nil {\n\t\tmodel._update = nil\n\t\tif ProjectDefine.Saved != nil {\n\t\t\tProjectDefine.Saved(model)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *ProjectModel) Set(fields contracts.Fields) {\n\tfor key, value := range fields {\n\n\t\tswitch key {\n\t\tcase \"id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase int64:\n\t\t\t\tmodel.SetId(v)\n\t\t\tcase func() int64:\n\t\t\t\tmodel.SetId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetId(cast.ToInt64(v))\n\t\t\t}\n\t\tcase \"uuid\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetUuid(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetUuid(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetUuid(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetUuid(cast.ToString(v))\n\t\t\t}\n\t\tcase \"name\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetName(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetName(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetName(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetName(cast.ToString(v))\n\t\t\t}\n\t\tcase \"creator_id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase int64:\n\t\t\t\tmodel.SetCreatorId(v)\n\t\t\tcase func() int64:\n\t\t\t\tmodel.SetCreatorId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetCreatorId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetCreatorId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetCreatorId(cast.ToInt64(v))\n\t\t\t}\n\t\tcase \"group_id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase int64:\n\t\t\t\tmodel.SetGroupId(v)\n\t\t\tcase func() int64:\n\t\t\t\tmodel.SetGroupId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetGroupId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetGroupId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetGroupId(cast.ToInt64(v))\n\t\t\t}\n\t\tcase \"key_id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase int64:\n\t\t\t\tmodel.SetKeyId(v)\n\t\t\tcase func() int64:\n\t\t\t\tmodel.SetKeyId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetKeyId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetKeyId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetKeyId(cast.ToInt64(v))\n\t\t\t}\n\t\tcase \"repo_address\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetRepoAddress(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetRepoAddress(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetRepoAddress(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetRepoAddress(cast.ToString(v))\n\t\t\t}\n\t\tcase \"project_path\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetProjectPath(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetProjectPath(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetProjectPath(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetProjectPath(cast.ToString(v))\n\t\t\t}\n\t\tcase \"default_branch\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetDefaultBranch(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetDefaultBranch(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetDefaultBranch(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetDefaultBranch(cast.ToString(v))\n\t\t\t}\n\t\tcase \"settings\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetSettings(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetSettings(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetSettings(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetSettings(cast.ToString(v))\n\t\t\t}\n\t\tcase \"created_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetCreatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetCreatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetCreatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetCreatedAt(cast.ToString(v))\n\t\t\t}\n\t\tcase \"updated_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetUpdatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetUpdatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetUpdatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetUpdatedAt(cast.ToString(v))\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (model *ProjectModel) Only(key ...string) contracts.Fields {\n\tvar fields = make(contracts.Fields)\n\tfor _, k := range key {\n\t\tif k == \"id\" {\n\t\t\tfields[k] = model.GetId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"uuid\" {\n\t\t\tfields[k] = model.GetUuid()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"name\" {\n\t\t\tfields[k] = model.GetName()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"creator_id\" {\n\t\t\tfields[k] = model.GetCreatorId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"group_id\" {\n\t\t\tfields[k] = model.GetGroupId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"key_id\" {\n\t\t\tfields[k] = model.GetKeyId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"repo_address\" {\n\t\t\tfields[k] = model.GetRepoAddress()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"project_path\" {\n\t\t\tfields[k] = model.GetProjectPath()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"default_branch\" {\n\t\t\tfields[k] = model.GetDefaultBranch()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"settings\" {\n\t\t\tfields[k] = model.GetSettings()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"created_at\" {\n\t\t\tfields[k] = model.GetCreatedAt()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"updated_at\" {\n\t\t\tfields[k] = model.GetUpdatedAt()\n\t\t\tcontinue\n\t\t}\n\n\t\tif ProjectDefine.Appends[k] != nil {\n\t\t\tfields[k] = ProjectDefine.Appends[k](model)\n\t\t}\n\t}\n\treturn fields\n}\n\nfunc (model *ProjectModel) Get(key string) any {\n\tswitch key {\n\tcase \"id\":\n\t\treturn model.GetId()\n\tcase \"uuid\":\n\t\treturn model.GetUuid()\n\tcase \"name\":\n\t\treturn model.GetName()\n\tcase \"creator_id\":\n\t\treturn model.GetCreatorId()\n\tcase \"group_id\":\n\t\treturn model.GetGroupId()\n\tcase \"key_id\":\n\t\treturn model.GetKeyId()\n\tcase \"repo_address\":\n\t\treturn model.GetRepoAddress()\n\tcase \"project_path\":\n\t\treturn model.GetProjectPath()\n\tcase \"default_branch\":\n\t\treturn model.GetDefaultBranch()\n\tcase \"settings\":\n\t\treturn model.GetSettings()\n\tcase \"created_at\":\n\t\treturn model.GetCreatedAt()\n\tcase \"updated_at\":\n\t\treturn model.GetUpdatedAt()\n\t}\n\n\tif value, exists := model._append[key]; exists {\n\t\treturn value\n\t}\n\n\tif fn, exists := ProjectDefine.Appends[key]; exists {\n\t\tmodel._append[key] = fn(model)\n\t\treturn model._append[key]\n\t}\n\n\tswitch contracts.RelationType(key) {\n\t}\n\n\treturn nil\n}\n\nfunc (model *ProjectModel) Except(keys ...string) contracts.Fields {\n\tvar excepts = map[string]struct{}{}\n\tfor _, k := range keys {\n\t\texcepts[k] = struct{}{}\n\t}\n\tvar fields = make(contracts.Fields)\n\tfor key, value := range model.ToFields() {\n\t\tif _, ok := excepts[key]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tfields[key] = value\n\t}\n\treturn fields\n}\n\nfunc (model *ProjectModel) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\n\tmodel.Hidden(ProjectDefine.Hidden...)\n\n\tfields := contracts.Fields{}\n\tif _, exists := model._hidden[\"id\"]; !exists {\n\t\tfields[\"id\"] = model.GetId()\n\t}\n\tif _, exists := model._hidden[\"uuid\"]; !exists {\n\t\tfields[\"uuid\"] = model.GetUuid()\n\t}\n\tif _, exists := model._hidden[\"name\"]; !exists {\n\t\tfields[\"name\"] = model.GetName()\n\t}\n\tif _, exists := model._hidden[\"creator_id\"]; !exists {\n\t\tfields[\"creator_id\"] = model.GetCreatorId()\n\t}\n\tif _, exists := model._hidden[\"group_id\"]; !exists {\n\t\tfields[\"group_id\"] = model.GetGroupId()\n\t}\n\tif _, exists := model._hidden[\"key_id\"]; !exists {\n\t\tfields[\"key_id\"] = model.GetKeyId()\n\t}\n\tif _, exists := model._hidden[\"repo_address\"]; !exists {\n\t\tfields[\"repo_address\"] = model.GetRepoAddress()\n\t}\n\tif _, exists := model._hidden[\"project_path\"]; !exists {\n\t\tfields[\"project_path\"] = model.GetProjectPath()\n\t}\n\tif _, exists := model._hidden[\"default_branch\"]; !exists {\n\t\tfields[\"default_branch\"] = model.GetDefaultBranch()\n\t}\n\tif _, exists := model._hidden[\"settings\"]; !exists {\n\t\tfields[\"settings\"] = model.GetSettings()\n\t}\n\tif _, exists := model._hidden[\"created_at\"]; !exists {\n\t\tfields[\"created_at\"] = model.GetCreatedAt()\n\t}\n\tif _, exists := model._hidden[\"updated_at\"]; !exists {\n\t\tfields[\"updated_at\"] = model.GetUpdatedAt()\n\t}\n\n\tfor key := range ProjectDefine.Appends {\n\t\tvalue := model.Get(key)\n\t\tif fieldsProvider, ok := value.(contracts.FieldsProvider); ok {\n\t\t\tfields[key] = fieldsProvider.ToFields()\n\t\t} else {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\tfor key := range model._relation_loaded {\n\t\tswitch key {\n\t\t}\n\t}\n\n\tfor key, value := range model._raw {\n\t\t_, hidden := model._hidden[key]\n\t\tif _, exists := fields[key]; !exists && !hidden {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\treturn fields\n}\n\nfunc (model *ProjectModel) Update(fields contracts.Fields) contracts.Exception {\n\n\tif ProjectDefine.Updating != nil {\n\t\tif err := ProjectDefine.Updating(model, fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif model._update != nil {\n\t\tutils.MergeFields(model._update, fields)\n\t}\n\n\t_, err := ProjectQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(fields)\n\n\tif err == nil {\n\t\tmodel.Set(fields)\n\t\tmodel._update = nil\n\t\tif ProjectDefine.Updated != nil {\n\t\t\tProjectDefine.Updated(model, fields)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *ProjectModel) Refresh() contracts.Exception {\n\tfields, err := table.ArrayQuery(\"projects\").Where(\"id\", model.GetPrimaryKey()).FirstE()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmodel.Set(*fields)\n\treturn nil\n}\n\nfunc (model *ProjectModel) Delete() contracts.Exception {\n\n\tif ProjectDefine.Deleting != nil {\n\t\tif err := ProjectDefine.Deleting(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t_, err := ProjectQuery().Where(\"id\", model.GetPrimaryKey()).DeleteE()\n\tif err == nil && ProjectDefine.Deleted != nil {\n\t\tProjectDefine.Deleted(model)\n\t}\n\n\treturn err\n}\n\nfunc (model *ProjectModel) GetPrimaryKey() any {\n\tif ProjectDefine.PrimaryKeyGetter != nil {\n\t\treturn ProjectDefine.PrimaryKeyGetter(model)\n\t}\n\n\treturn model.Id\n}\n\nfunc (model *ProjectModel) GetId() int64 {\n\tif ProjectDefine.IdGetter != nil {\n\t\treturn ProjectDefine.IdGetter(model, model.Id)\n\t}\n\treturn model.Id\n}\n\nfunc (model *ProjectModel) SetId(value int64) {\n\tif ProjectDefine.IdSetter != nil {\n\t\tvalue = ProjectDefine.IdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"id\": value}\n\t} else {\n\t\tmodel._update[\"id\"] = value\n\t}\n\tmodel.Id = value\n}\n\nfunc (model *ProjectModel) GetUuid() string {\n\tif ProjectDefine.UuidGetter != nil {\n\t\treturn ProjectDefine.UuidGetter(model, model.Uuid)\n\t}\n\treturn model.Uuid\n}\n\nfunc (model *ProjectModel) SetUuid(value string) {\n\tif ProjectDefine.UuidSetter != nil {\n\t\tvalue = ProjectDefine.UuidSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"uuid\": value}\n\t} else {\n\t\tmodel._update[\"uuid\"] = value\n\t}\n\tmodel.Uuid = value\n}\n\nfunc (model *ProjectModel) GetName() string {\n\tif ProjectDefine.NameGetter != nil {\n\t\treturn ProjectDefine.NameGetter(model, model.Name)\n\t}\n\treturn model.Name\n}\n\nfunc (model *ProjectModel) SetName(value string) {\n\tif ProjectDefine.NameSetter != nil {\n\t\tvalue = ProjectDefine.NameSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"name\": value}\n\t} else {\n\t\tmodel._update[\"name\"] = value\n\t}\n\tmodel.Name = value\n}\n\nfunc (model *ProjectModel) GetCreatorId() int64 {\n\tif ProjectDefine.CreatorIdGetter != nil {\n\t\treturn ProjectDefine.CreatorIdGetter(model, model.CreatorId)\n\t}\n\treturn model.CreatorId\n}\n\nfunc (model *ProjectModel) SetCreatorId(value int64) {\n\tif ProjectDefine.CreatorIdSetter != nil {\n\t\tvalue = ProjectDefine.CreatorIdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"creator_id\": value}\n\t} else {\n\t\tmodel._update[\"creator_id\"] = value\n\t}\n\tmodel.CreatorId = value\n}\n\nfunc (model *ProjectModel) GetGroupId() int64 {\n\tif ProjectDefine.GroupIdGetter != nil {\n\t\treturn ProjectDefine.GroupIdGetter(model, model.GroupId)\n\t}\n\treturn model.GroupId\n}\n\nfunc (model *ProjectModel) SetGroupId(value int64) {\n\tif ProjectDefine.GroupIdSetter != nil {\n\t\tvalue = ProjectDefine.GroupIdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"group_id\": value}\n\t} else {\n\t\tmodel._update[\"group_id\"] = value\n\t}\n\tmodel.GroupId = value\n}\n\nfunc (model *ProjectModel) GetKeyId() int64 {\n\tif ProjectDefine.KeyIdGetter != nil {\n\t\treturn ProjectDefine.KeyIdGetter(model, model.KeyId)\n\t}\n\treturn model.KeyId\n}\n\nfunc (model *ProjectModel) SetKeyId(value int64) {\n\tif ProjectDefine.KeyIdSetter != nil {\n\t\tvalue = ProjectDefine.KeyIdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"key_id\": value}\n\t} else {\n\t\tmodel._update[\"key_id\"] = value\n\t}\n\tmodel.KeyId = value\n}\n\nfunc (model *ProjectModel) GetRepoAddress() string {\n\tif ProjectDefine.RepoAddressGetter != nil {\n\t\treturn ProjectDefine.RepoAddressGetter(model, model.RepoAddress)\n\t}\n\treturn model.RepoAddress\n}\n\nfunc (model *ProjectModel) SetRepoAddress(value string) {\n\tif ProjectDefine.RepoAddressSetter != nil {\n\t\tvalue = ProjectDefine.RepoAddressSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"repo_address\": value}\n\t} else {\n\t\tmodel._update[\"repo_address\"] = value\n\t}\n\tmodel.RepoAddress = value\n}\n\nfunc (model *ProjectModel) GetProjectPath() string {\n\tif ProjectDefine.ProjectPathGetter != nil {\n\t\treturn ProjectDefine.ProjectPathGetter(model, model.ProjectPath)\n\t}\n\treturn model.ProjectPath\n}\n\nfunc (model *ProjectModel) SetProjectPath(value string) {\n\tif ProjectDefine.ProjectPathSetter != nil {\n\t\tvalue = ProjectDefine.ProjectPathSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"project_path\": value}\n\t} else {\n\t\tmodel._update[\"project_path\"] = value\n\t}\n\tmodel.ProjectPath = value\n}\n\nfunc (model *ProjectModel) GetDefaultBranch() string {\n\tif ProjectDefine.DefaultBranchGetter != nil {\n\t\treturn ProjectDefine.DefaultBranchGetter(model, model.DefaultBranch)\n\t}\n\treturn model.DefaultBranch\n}\n\nfunc (model *ProjectModel) SetDefaultBranch(value string) {\n\tif ProjectDefine.DefaultBranchSetter != nil {\n\t\tvalue = ProjectDefine.DefaultBranchSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"default_branch\": value}\n\t} else {\n\t\tmodel._update[\"default_branch\"] = value\n\t}\n\tmodel.DefaultBranch = value\n}\n\nfunc (model *ProjectModel) GetSettings() string {\n\tif ProjectDefine.SettingsGetter != nil {\n\t\treturn ProjectDefine.SettingsGetter(model, model.Settings)\n\t}\n\treturn model.Settings\n}\n\nfunc (model *ProjectModel) SetSettings(value string) {\n\tif ProjectDefine.SettingsSetter != nil {\n\t\tvalue = ProjectDefine.SettingsSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"settings\": value}\n\t} else {\n\t\tmodel._update[\"settings\"] = value\n\t}\n\tmodel.Settings = value\n}\n\nfunc (model *ProjectModel) GetCreatedAt() string {\n\tif ProjectDefine.CreatedAtGetter != nil {\n\t\treturn ProjectDefine.CreatedAtGetter(model, model.CreatedAt)\n\t}\n\treturn model.CreatedAt\n}\n\nfunc (model *ProjectModel) SetCreatedAt(value string) {\n\tif ProjectDefine.CreatedAtSetter != nil {\n\t\tvalue = ProjectDefine.CreatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"created_at\": value}\n\t} else {\n\t\tmodel._update[\"created_at\"] = value\n\t}\n\tmodel.CreatedAt = value\n}\n\nfunc (model *ProjectModel) GetUpdatedAt() string {\n\tif ProjectDefine.UpdatedAtGetter != nil {\n\t\treturn ProjectDefine.UpdatedAtGetter(model, model.UpdatedAt)\n\t}\n\treturn model.UpdatedAt\n}\n\nfunc (model *ProjectModel) SetUpdatedAt(value string) {\n\tif ProjectDefine.UpdatedAtSetter != nil {\n\t\tvalue = ProjectDefine.UpdatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"updated_at\": value}\n\t} else {\n\t\tmodel._update[\"updated_at\"] = value\n\t}\n\tmodel.UpdatedAt = value\n}\n"
  },
  {
    "path": "app/models/User_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage models\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/goal-web/collection\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database/table\"\n\tuser \"github.com/goal-web/goal/app/models/user\"\n\t\"github.com/goal-web/migration/migrate\"\n\t\"github.com/goal-web/supports/logs\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"github.com/spf13/cast\"\n)\n\nvar ()\n\n// UserModel\n// 用户注释\n// @authenticatable\n// @timestamps\ntype UserModel struct {\n\tId int64 `json:\"id\" query:\"id\" form:\"id\" db:\"id;type:BIGINT;not null;primary key;AUTO_INCREMENT;\"`\n\n\tName string `json:\"name\" query:\"name\" form:\"name\" db:\"name;type:VARCHAR(255);not null;\"`\n\n\tAvatar string `json:\"avatar\" query:\"avatar\" form:\"avatar\" db:\"avatar;type:VARCHAR(255);not null;\"`\n\t//@index\n\t//@goTag:db:\"open_id;type:varchar(255);default 'xxasdasdsx'\"\n\tOpenId string `db:\"open_id;type:varchar(255);default 'xxasdasdsx'\" json:\"open_id\" query:\"open_id\" form:\"open_id\"`\n\n\tWechatInfo *user.WechatInfoData `json:\"wechat_info\" query:\"wechat_info\" form:\"wechat_info\" db:\"wechat_info;type:json;not null;\"`\n\n\tChannel string `json:\"channel\" query:\"channel\" form:\"channel\" db:\"channel;type:VARCHAR(255);not null;\"`\n\t//@hidden\n\tPassword string `json:\"password\" query:\"password\" form:\"password\" db:\"password;type:VARCHAR(255);not null;\"`\n\n\tCreatedAt string `json:\"created_at\" query:\"created_at\" form:\"created_at\" db:\"created_at;type:timestamp;default CURRENT_TIMESTAMP;\"`\n\n\tUpdatedAt string `json:\"updated_at\" query:\"updated_at\" form:\"updated_at\" db:\"updated_at;type:timestamp;DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;\"`\n\n\t_raw    contracts.Fields\n\t_update contracts.Fields\n\t_append contracts.Fields\n\t_hidden map[string]struct{}\n\n\t_relation_loaded map[contracts.RelationType]struct{}\n}\n\nvar UserDefine UserStatic\n\ntype UserStatic struct {\n\tTableName        string\n\tHidden           []string\n\tIndexes          []string\n\tWith             []contracts.RelationType\n\tAppends          map[string]func(model *UserModel) any\n\tIdGetter         func(model *UserModel, raw int64) int64\n\tIdSetter         func(model *UserModel, raw int64) int64\n\tNameGetter       func(model *UserModel, raw string) string\n\tNameSetter       func(model *UserModel, raw string) string\n\tAvatarGetter     func(model *UserModel, raw string) string\n\tAvatarSetter     func(model *UserModel, raw string) string\n\tOpenIdGetter     func(model *UserModel, raw string) string\n\tOpenIdSetter     func(model *UserModel, raw string) string\n\tWechatInfoGetter func(model *UserModel, raw *user.WechatInfoData) *user.WechatInfoData\n\tWechatInfoSetter func(model *UserModel, raw *user.WechatInfoData) *user.WechatInfoData\n\tChannelGetter    func(model *UserModel, raw string) string\n\tChannelSetter    func(model *UserModel, raw string) string\n\tPasswordGetter   func(model *UserModel, raw string) string\n\tPasswordSetter   func(model *UserModel, raw string) string\n\tCreatedAtGetter  func(model *UserModel, raw string) string\n\tCreatedAtSetter  func(model *UserModel, raw string) string\n\tUpdatedAtGetter  func(model *UserModel, raw string) string\n\tUpdatedAtSetter  func(model *UserModel, raw string) string\n\n\tSaving           func(model *UserModel) contracts.Exception\n\tSaved            func(model *UserModel)\n\tUpdating         func(model *UserModel, fields contracts.Fields) contracts.Exception\n\tUpdated          func(model *UserModel, fields contracts.Fields)\n\tDeleting         func(model *UserModel) contracts.Exception\n\tDeleted          func(model *UserModel)\n\tPrimaryKeyGetter func(model *UserModel) any\n}\n\nfunc UserMigrator() migrate.Migrator {\n\treturn func(executor contracts.SqlExecutor) contracts.Exception {\n\t\treturn migrate.Migrate(UserDefine.TableName, UserDefine.Indexes, UserModel{}, executor)\n\t}\n}\n\nfunc init() {\n\tUserDefine.TableName = \"users\"\n\tUserDefine.Appends = make(map[string]func(model *UserModel) any)\n\tUserDefine.Hidden = append(\n\t\tUserDefine.Hidden,\n\t\t\"password\",\n\t)\n\tUserDefine.Indexes = append(\n\t\tUserDefine.Indexes,\n\t\t\"index;open_id_idx;(open_id)\",\n\t)\n}\n\nfunc NewUserModel(fields contracts.Fields) *UserModel {\n\tvar model = UserModel{\n\t\t_raw: fields,\n\t}\n\tmodel.Set(fields)\n\treturn &model\n}\n\nfunc UserModelSingleRelationSetter[T any](key contracts.RelationType) func(item *UserModel, value []any) {\n\treturn func(item *UserModel, values []any) {\n\t\tvar value T\n\t\tif len(values) > 0 {\n\t\t\tvalue = values[0].(T)\n\t\t}\n\t\titem.Set(contracts.Fields{\n\t\t\tstring(key): value,\n\t\t})\n\t}\n}\nfunc UserModelMultiRelationSetter[T any](key contracts.RelationType) func(item *UserModel, value []any) {\n\treturn func(model *UserModel, value []any) {\n\t\tvar results []T\n\t\tfor _, item := range value {\n\t\t\tresults = append(results, item.(T))\n\t\t}\n\t\tmodel.Set(contracts.Fields{string(key): results})\n\t}\n}\n\nfunc UserModelLocalKeyGetter(key string) func(item *UserModel) any {\n\treturn func(item *UserModel) any {\n\t\treturn item.Get(key)\n\t}\n}\n\nfunc UserModelRelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tfor key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\n\nfunc UserModelThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any {\n\treturn func(keys []any) map[string][]any {\n\t\tvar results = map[string][]any{}\n\t\tgroupKey := fmt.Sprintf(\"%s.%s\", midTable, firstKey)\n\t\tfor key, values := range query().\n\t\t\tAddSelect(fmt.Sprintf(\"(%s) as _group_key\", groupKey)).\n\t\t\tWhereIn(groupKey, keys).\n\t\t\tJoin(midTable, fmt.Sprintf(\"%s.%s\", midTable, secondLocalKey), \"=\", fmt.Sprintf(\"%s.%s\", query().GetTableName(), secondKey)).\n\t\t\tGet().GroupBy(\"_group_key\") {\n\t\t\tresults[key] = collection.New(values).ToAnyArray()\n\t\t}\n\t\treturn results\n\t}\n}\nfunc UserQueryWithExecutor(executor contracts.SqlExecutor) *table.Table[UserModel] {\n\treturn UserQuery().SetExecutor(executor)\n}\n\nfunc UserQuery() *table.Table[UserModel] {\n\treturn table.NewQuery(UserDefine.TableName, NewUserModel).\n\t\tSetPrimaryKey(\"id\").\n\t\tSetCreatedTimeColumn(\"created_at\").\n\t\tSetUpdatedTimeColumn(\"updated_at\").\n\t\tSetWiths(UserDefine.With...)\n}\n\nfunc (model *UserModel) Hidden(fields ...string) *UserModel {\n\tfor _, field := range fields {\n\t\tif model._hidden == nil {\n\t\t\tmodel._hidden = map[string]struct{}{\n\t\t\t\tfield: struct{}{},\n\t\t\t}\n\t\t} else {\n\t\t\tmodel._hidden[field] = struct{}{}\n\t\t}\n\n\t}\n\n\treturn model\n}\n\nfunc (model *UserModel) Exists() bool {\n\treturn UserQuery().Where(\"id\", model.GetPrimaryKey()).Count() > 0\n}\n\nfunc (model *UserModel) Save() contracts.Exception {\n\tif model._update == nil {\n\t\treturn nil\n\t}\n\tif UserDefine.Saving != nil {\n\t\tif err := UserDefine.Saving(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tvar err contracts.Exception\n\tvar pk = model.GetPrimaryKey()\n\tif cast.ToUint64(pk) == 0 {\n\t\tpk, err = UserQuery().Where(\"id\", model.GetPrimaryKey()).InsertGetIdE(model._update)\n\t\tif err == nil {\n\t\t\tmodel.SetId(cast.ToInt64(pk))\n\t\t}\n\t} else {\n\t\t_, err = UserQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(model._update)\n\t}\n\tif err == nil {\n\t\tmodel._update = nil\n\t\tif UserDefine.Saved != nil {\n\t\t\tUserDefine.Saved(model)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *UserModel) Set(fields contracts.Fields) {\n\tfor key, value := range fields {\n\n\t\tswitch key {\n\t\tcase \"id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase int64:\n\t\t\t\tmodel.SetId(v)\n\t\t\tcase func() int64:\n\t\t\t\tmodel.SetId(v())\n\t\t\tcase string:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd int64\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetId(vd)\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetId(cast.ToInt64(v))\n\t\t\t}\n\t\tcase \"name\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetName(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetName(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetName(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetName(cast.ToString(v))\n\t\t\t}\n\t\tcase \"avatar\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetAvatar(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetAvatar(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetAvatar(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetAvatar(cast.ToString(v))\n\t\t\t}\n\t\tcase \"open_id\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetOpenId(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetOpenId(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetOpenId(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetOpenId(cast.ToString(v))\n\t\t\t}\n\t\tcase \"wechat_info\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase *user.WechatInfoData:\n\t\t\t\tmodel.SetWechatInfo(v)\n\t\t\tcase func() *user.WechatInfoData:\n\t\t\t\tmodel.SetWechatInfo(v())\n\t\t\tcase string:\n\t\t\t\tvar vd *user.WechatInfoData\n\t\t\t\terr := json.Unmarshal([]byte(v), &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetWechatInfo(vd)\n\n\t\t\tcase []byte:\n\t\t\t\tvar vd *user.WechatInfoData\n\t\t\t\terr := json.Unmarshal(v, &vd)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogs.Default().Warn(\"Failed to Parse field \" + key)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tmodel.SetWechatInfo(vd)\n\n\t\t\t}\n\t\tcase \"channel\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetChannel(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetChannel(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetChannel(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetChannel(cast.ToString(v))\n\t\t\t}\n\t\tcase \"password\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetPassword(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetPassword(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetPassword(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetPassword(cast.ToString(v))\n\t\t\t}\n\t\tcase \"created_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetCreatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetCreatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetCreatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetCreatedAt(cast.ToString(v))\n\t\t\t}\n\t\tcase \"updated_at\":\n\t\t\tswitch v := value.(type) {\n\t\t\tcase string:\n\t\t\t\tmodel.SetUpdatedAt(v)\n\t\t\tcase func() string:\n\t\t\t\tmodel.SetUpdatedAt(v())\n\t\t\tcase []byte:\n\t\t\t\tmodel.SetUpdatedAt(string(v))\n\n\t\t\tdefault:\n\t\t\t\tmodel.SetUpdatedAt(cast.ToString(v))\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (model *UserModel) Only(key ...string) contracts.Fields {\n\tvar fields = make(contracts.Fields)\n\tfor _, k := range key {\n\t\tif k == \"id\" {\n\t\t\tfields[k] = model.GetId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"name\" {\n\t\t\tfields[k] = model.GetName()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"avatar\" {\n\t\t\tfields[k] = model.GetAvatar()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"open_id\" {\n\t\t\tfields[k] = model.GetOpenId()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"wechat_info\" {\n\t\t\tfields[k] = model.GetWechatInfo()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"channel\" {\n\t\t\tfields[k] = model.GetChannel()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"password\" {\n\t\t\tfields[k] = model.GetPassword()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"created_at\" {\n\t\t\tfields[k] = model.GetCreatedAt()\n\t\t\tcontinue\n\t\t}\n\t\tif k == \"updated_at\" {\n\t\t\tfields[k] = model.GetUpdatedAt()\n\t\t\tcontinue\n\t\t}\n\n\t\tif UserDefine.Appends[k] != nil {\n\t\t\tfields[k] = UserDefine.Appends[k](model)\n\t\t}\n\t}\n\treturn fields\n}\n\nfunc (model *UserModel) Get(key string) any {\n\tswitch key {\n\tcase \"id\":\n\t\treturn model.GetId()\n\tcase \"name\":\n\t\treturn model.GetName()\n\tcase \"avatar\":\n\t\treturn model.GetAvatar()\n\tcase \"open_id\":\n\t\treturn model.GetOpenId()\n\tcase \"wechat_info\":\n\t\treturn model.GetWechatInfo()\n\tcase \"channel\":\n\t\treturn model.GetChannel()\n\tcase \"password\":\n\t\treturn model.GetPassword()\n\tcase \"created_at\":\n\t\treturn model.GetCreatedAt()\n\tcase \"updated_at\":\n\t\treturn model.GetUpdatedAt()\n\t}\n\n\tif value, exists := model._append[key]; exists {\n\t\treturn value\n\t}\n\n\tif fn, exists := UserDefine.Appends[key]; exists {\n\t\tmodel._append[key] = fn(model)\n\t\treturn model._append[key]\n\t}\n\n\tswitch contracts.RelationType(key) {\n\t}\n\n\treturn nil\n}\n\nfunc (model *UserModel) Except(keys ...string) contracts.Fields {\n\tvar excepts = map[string]struct{}{}\n\tfor _, k := range keys {\n\t\texcepts[k] = struct{}{}\n\t}\n\tvar fields = make(contracts.Fields)\n\tfor key, value := range model.ToFields() {\n\t\tif _, ok := excepts[key]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tfields[key] = value\n\t}\n\treturn fields\n}\n\nfunc (model *UserModel) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\n\tmodel.Hidden(UserDefine.Hidden...)\n\n\tfields := contracts.Fields{}\n\tif _, exists := model._hidden[\"id\"]; !exists {\n\t\tfields[\"id\"] = model.GetId()\n\t}\n\tif _, exists := model._hidden[\"name\"]; !exists {\n\t\tfields[\"name\"] = model.GetName()\n\t}\n\tif _, exists := model._hidden[\"avatar\"]; !exists {\n\t\tfields[\"avatar\"] = model.GetAvatar()\n\t}\n\tif _, exists := model._hidden[\"open_id\"]; !exists {\n\t\tfields[\"open_id\"] = model.GetOpenId()\n\t}\n\tif _, exists := model._hidden[\"wechat_info\"]; !exists {\n\t\tfields[\"wechat_info\"] = model.GetWechatInfo()\n\t}\n\tif _, exists := model._hidden[\"channel\"]; !exists {\n\t\tfields[\"channel\"] = model.GetChannel()\n\t}\n\tif _, exists := model._hidden[\"password\"]; !exists {\n\t\tfields[\"password\"] = model.GetPassword()\n\t}\n\tif _, exists := model._hidden[\"created_at\"]; !exists {\n\t\tfields[\"created_at\"] = model.GetCreatedAt()\n\t}\n\tif _, exists := model._hidden[\"updated_at\"]; !exists {\n\t\tfields[\"updated_at\"] = model.GetUpdatedAt()\n\t}\n\n\tfor key := range UserDefine.Appends {\n\t\tvalue := model.Get(key)\n\t\tif fieldsProvider, ok := value.(contracts.FieldsProvider); ok {\n\t\t\tfields[key] = fieldsProvider.ToFields()\n\t\t} else {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\tfor key := range model._relation_loaded {\n\t\tswitch key {\n\t\t}\n\t}\n\n\tfor key, value := range model._raw {\n\t\t_, hidden := model._hidden[key]\n\t\tif _, exists := fields[key]; !exists && !hidden {\n\t\t\tfields[key] = value\n\t\t}\n\t}\n\n\treturn fields\n}\n\nfunc (model *UserModel) Update(fields contracts.Fields) contracts.Exception {\n\n\tif UserDefine.Updating != nil {\n\t\tif err := UserDefine.Updating(model, fields); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif model._update != nil {\n\t\tutils.MergeFields(model._update, fields)\n\t}\n\n\t_, err := UserQuery().Where(\"id\", model.GetPrimaryKey()).UpdateE(fields)\n\n\tif err == nil {\n\t\tmodel.Set(fields)\n\t\tmodel._update = nil\n\t\tif UserDefine.Updated != nil {\n\t\t\tUserDefine.Updated(model, fields)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (model *UserModel) Refresh() contracts.Exception {\n\tfields, err := table.ArrayQuery(\"users\").Where(\"id\", model.GetPrimaryKey()).FirstE()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmodel.Set(*fields)\n\treturn nil\n}\n\nfunc (model *UserModel) Delete() contracts.Exception {\n\n\tif UserDefine.Deleting != nil {\n\t\tif err := UserDefine.Deleting(model); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t_, err := UserQuery().Where(\"id\", model.GetPrimaryKey()).DeleteE()\n\tif err == nil && UserDefine.Deleted != nil {\n\t\tUserDefine.Deleted(model)\n\t}\n\n\treturn err\n}\n\nfunc (model *UserModel) GetPrimaryKey() any {\n\tif UserDefine.PrimaryKeyGetter != nil {\n\t\treturn UserDefine.PrimaryKeyGetter(model)\n\t}\n\n\treturn model.Id\n}\nfunc (model *UserModel) GetAuthenticatableKey() string {\n\treturn fmt.Sprintf(\"%v\", model.GetPrimaryKey())\n}\n\nfunc UserAuthProvider(identify string) contracts.Authenticatable {\n\treturn UserQuery().Find(identify)\n}\n\nfunc (model *UserModel) GetId() int64 {\n\tif UserDefine.IdGetter != nil {\n\t\treturn UserDefine.IdGetter(model, model.Id)\n\t}\n\treturn model.Id\n}\n\nfunc (model *UserModel) SetId(value int64) {\n\tif UserDefine.IdSetter != nil {\n\t\tvalue = UserDefine.IdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"id\": value}\n\t} else {\n\t\tmodel._update[\"id\"] = value\n\t}\n\tmodel.Id = value\n}\n\nfunc (model *UserModel) GetName() string {\n\tif UserDefine.NameGetter != nil {\n\t\treturn UserDefine.NameGetter(model, model.Name)\n\t}\n\treturn model.Name\n}\n\nfunc (model *UserModel) SetName(value string) {\n\tif UserDefine.NameSetter != nil {\n\t\tvalue = UserDefine.NameSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"name\": value}\n\t} else {\n\t\tmodel._update[\"name\"] = value\n\t}\n\tmodel.Name = value\n}\n\nfunc (model *UserModel) GetAvatar() string {\n\tif UserDefine.AvatarGetter != nil {\n\t\treturn UserDefine.AvatarGetter(model, model.Avatar)\n\t}\n\treturn model.Avatar\n}\n\nfunc (model *UserModel) SetAvatar(value string) {\n\tif UserDefine.AvatarSetter != nil {\n\t\tvalue = UserDefine.AvatarSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"avatar\": value}\n\t} else {\n\t\tmodel._update[\"avatar\"] = value\n\t}\n\tmodel.Avatar = value\n}\n\nfunc (model *UserModel) GetOpenId() string {\n\tif UserDefine.OpenIdGetter != nil {\n\t\treturn UserDefine.OpenIdGetter(model, model.OpenId)\n\t}\n\treturn model.OpenId\n}\n\nfunc (model *UserModel) SetOpenId(value string) {\n\tif UserDefine.OpenIdSetter != nil {\n\t\tvalue = UserDefine.OpenIdSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"open_id\": value}\n\t} else {\n\t\tmodel._update[\"open_id\"] = value\n\t}\n\tmodel.OpenId = value\n}\n\nfunc (model *UserModel) GetWechatInfo() *user.WechatInfoData {\n\tif UserDefine.WechatInfoGetter != nil {\n\t\treturn UserDefine.WechatInfoGetter(model, model.WechatInfo)\n\t}\n\treturn model.WechatInfo\n}\n\nfunc (model *UserModel) SetWechatInfo(value *user.WechatInfoData) {\n\tif UserDefine.WechatInfoSetter != nil {\n\t\tvalue = UserDefine.WechatInfoSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"wechat_info\": value}\n\t} else {\n\t\tmodel._update[\"wechat_info\"] = value\n\t}\n\tmodel.WechatInfo = value\n}\n\nfunc (model *UserModel) GetChannel() string {\n\tif UserDefine.ChannelGetter != nil {\n\t\treturn UserDefine.ChannelGetter(model, model.Channel)\n\t}\n\treturn model.Channel\n}\n\nfunc (model *UserModel) SetChannel(value string) {\n\tif UserDefine.ChannelSetter != nil {\n\t\tvalue = UserDefine.ChannelSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"channel\": value}\n\t} else {\n\t\tmodel._update[\"channel\"] = value\n\t}\n\tmodel.Channel = value\n}\n\nfunc (model *UserModel) GetPassword() string {\n\tif UserDefine.PasswordGetter != nil {\n\t\treturn UserDefine.PasswordGetter(model, model.Password)\n\t}\n\treturn model.Password\n}\n\nfunc (model *UserModel) SetPassword(value string) {\n\tif UserDefine.PasswordSetter != nil {\n\t\tvalue = UserDefine.PasswordSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"password\": value}\n\t} else {\n\t\tmodel._update[\"password\"] = value\n\t}\n\tmodel.Password = value\n}\n\nfunc (model *UserModel) GetCreatedAt() string {\n\tif UserDefine.CreatedAtGetter != nil {\n\t\treturn UserDefine.CreatedAtGetter(model, model.CreatedAt)\n\t}\n\treturn model.CreatedAt\n}\n\nfunc (model *UserModel) SetCreatedAt(value string) {\n\tif UserDefine.CreatedAtSetter != nil {\n\t\tvalue = UserDefine.CreatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"created_at\": value}\n\t} else {\n\t\tmodel._update[\"created_at\"] = value\n\t}\n\tmodel.CreatedAt = value\n}\n\nfunc (model *UserModel) GetUpdatedAt() string {\n\tif UserDefine.UpdatedAtGetter != nil {\n\t\treturn UserDefine.UpdatedAtGetter(model, model.UpdatedAt)\n\t}\n\treturn model.UpdatedAt\n}\n\nfunc (model *UserModel) SetUpdatedAt(value string) {\n\tif UserDefine.UpdatedAtSetter != nil {\n\t\tvalue = UserDefine.UpdatedAtSetter(model, value)\n\t}\n\n\tif model._update == nil {\n\t\tmodel._update = contracts.Fields{\"updated_at\": value}\n\t} else {\n\t\tmodel._update[\"updated_at\"] = value\n\t}\n\tmodel.UpdatedAt = value\n}\n"
  },
  {
    "path": "app/models/project/GetProjectRessult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:21:38\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\tmodels \"github.com/goal-web/goal/app/models\"\n)\n\ntype GetProjectRessult struct {\n\tProject models.ProjectModel `json:\"project\" query:\"project\" form:\"project\"`\n}\n"
  },
  {
    "path": "app/models/project.go",
    "content": "package models\n\nfunc init() {\n\tProjectDefine.Appends = map[string]func(model *ProjectModel) any{\n\t\t\"id-plus-1\": func(model *ProjectModel) any {\n\t\t\treturn model.Id + 0\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "app/models/user/WechatInfoData_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport ()\n\ntype WechatInfoData struct {\n\tCity      string `json:\"city\" query:\"city\" form:\"city\"`\n\tGender    int64  `json:\"gender\" query:\"gender\" form:\"gender\"`\n\tOpenId    string `json:\"open_id\" query:\"open_id\" form:\"open_id\"`\n\tCountry   string `json:\"country\" query:\"country\" form:\"country\"`\n\tLanguage  string `json:\"language\" query:\"language\" form:\"language\"`\n\tNickname  string `json:\"nickname\" query:\"nickname\" form:\"nickname\"`\n\tProvince  string `json:\"province\" query:\"province\" form:\"province\"`\n\tAvatarUrl string `json:\"avatar_url\" query:\"avatar_url\" form:\"avatar_url\"`\n}\n"
  },
  {
    "path": "app/providers/app.go",
    "content": "package providers\n\nimport (\n\t\"github.com/goal-web/application\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/console\"\n\t\"github.com/goal-web/goal/app/models\"\n\t\"github.com/goal-web/migration/migrate\"\n\t\"github.com/golang-module/carbon/v2\"\n)\n\ntype appServiceProvider struct {\n\tserviceProviders []contracts.ServiceProvider\n}\n\nfunc NewApp() contracts.ServiceProvider {\n\treturn &appServiceProvider{\n\t\tserviceProviders: []contracts.ServiceProvider{\n\t\t\tNewConsoleService(\n\t\t\t\tconsole.Commands,\n\t\t\t\tconsole.Schedule,\n\t\t\t),\n\t\t},\n\t}\n}\n\nfunc (app appServiceProvider) Register(instance contracts.Application) {\n\tinstance.RegisterServices(app.serviceProviders...)\n\n\tinstance.Call(func(config contracts.Config, dispatcher contracts.EventDispatcher, factory contracts.DBFactory) {\n\t\tappConfig := config.Get(\"app\").(application.Config)\n\t\tcarbon.SetLocale(appConfig.Locale)\n\t\tcarbon.SetTimezone(appConfig.Timezone)\n\t\tinstance.Instance(\"app.env\", appConfig.Env)\n\n\t\tmigrate.Auto(\n\t\t\tfactory,\n\t\t\tmodels.UserMigrator(),\n\t\t\tmodels.ProjectMigrator(),\n\t\t)\n\t})\n}\n\nfunc (app appServiceProvider) Start() error {\n\treturn nil\n}\n\nfunc (app appServiceProvider) Stop() {\n}\n"
  },
  {
    "path": "app/providers/console.go",
    "content": "package providers\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype Console struct {\n\tCommands []contracts.CommandProvider\n\tSchedule func(schedule contracts.Schedule)\n}\n\nfunc NewConsoleService(commands []contracts.CommandProvider, schedule func(schedule2 contracts.Schedule)) contracts.ServiceProvider {\n\treturn Console{\n\t\tCommands: commands,\n\t\tSchedule: schedule,\n\t}\n}\n\nfunc (c Console) Register(application contracts.Application) {\n\tapplication.Call(func(console contracts.Console, schedule contracts.Schedule) {\n\t\tfor _, provider := range c.Commands {\n\t\t\tconsole.RegisterCommand(provider)\n\t\t}\n\n\t\tc.Schedule(schedule)\n\t})\n}\n\nfunc (c Console) Start() error {\n\treturn nil\n}\n\nfunc (c Console) Stop() {\n}\n"
  },
  {
    "path": "app/providers/events.go",
    "content": "package providers\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tevents2 \"github.com/goal-web/database/events\"\n\t\"github.com/goal-web/goal/app/listeners\"\n)\n\ntype EventsServiceProvider struct {\n\tlisteners map[contracts.Event][]contracts.EventListener\n}\n\nfunc NewEvents() contracts.ServiceProvider {\n\treturn &EventsServiceProvider{\n\t\tlisteners: map[contracts.Event][]contracts.EventListener{\n\t\t\t&events2.QueryExecuted{}: {listeners.DebugQuery{}},\n\t\t},\n\t}\n}\n\nfunc (provider EventsServiceProvider) Stop() {\n\n}\n\nfunc (provider EventsServiceProvider) Start() error {\n\treturn nil\n}\n\nfunc (provider EventsServiceProvider) Register(container contracts.Application) {\n\tcontainer.Call(func(dispatcher contracts.EventDispatcher) {\n\t\tfor event, items := range provider.listeners {\n\t\t\tfor _, listener := range items {\n\t\t\t\tdispatcher.Register(event.Event(), listener)\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "app/requests/project/CreateProject_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype CreateProjectReq struct {\n\tUuid          string `json:\"uuid\" query:\"uuid\" form:\"uuid\"`\n\tName          string `json:\"name\" query:\"name\" form:\"name\"`\n\tCreatorId     int64  `json:\"creator_id\" query:\"creator_id\" form:\"creator_id\"`\n\tGroupId       int64  `json:\"group_id\" query:\"group_id\" form:\"group_id\"`\n\tKeyId         int64  `json:\"key_id\" query:\"key_id\" form:\"key_id\"`\n\tRepoAddress   string `json:\"repo_address\" query:\"repo_address\" form:\"repo_address\"`\n\tProjectPath   string `json:\"project_path\" query:\"project_path\" form:\"project_path\"`\n\tDefaultBranch string `json:\"default_branch\" query:\"default_branch\" form:\"default_branch\"`\n\tSettings      string `json:\"settings\" query:\"settings\" form:\"settings\"`\n}\n\nfunc (model *CreateProjectReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"uuid\":           model.Uuid,\n\t\t\"name\":           model.Name,\n\t\t\"creator_id\":     model.CreatorId,\n\t\t\"group_id\":       model.GroupId,\n\t\t\"key_id\":         model.KeyId,\n\t\t\"repo_address\":   model.RepoAddress,\n\t\t\"project_path\":   model.ProjectPath,\n\t\t\"default_branch\": model.DefaultBranch,\n\t\t\"settings\":       model.Settings,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/project/DeleteProject_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype DeleteProjectReq struct {\n\tId string `json:\"id\" query:\"id\" form:\"id\"`\n}\n\nfunc (model *DeleteProjectReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"id\": model.Id,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/project/GetProject_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype GetProjectReq struct {\n\tId string `json:\"id\" query:\"id\" form:\"id\"`\n}\n\nfunc (model *GetProjectReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"id\": model.Id,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/project/ListProjects_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype ListProjectsReq struct {\n\tPage    int64 `json:\"page\" query:\"page\" form:\"page\"`\n\tPerPage int64 `json:\"per_page\" query:\"per_page\" form:\"per_page\"`\n}\n\nfunc (model *ListProjectsReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"page\":     model.Page,\n\t\t\"per_page\": model.PerPage,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/project/UpdateProject_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype UpdateProjectReq struct {\n\tId            int64  `json:\"id\" query:\"id\" form:\"id\"`\n\tUuid          string `json:\"uuid\" query:\"uuid\" form:\"uuid\"`\n\tName          string `json:\"name\" query:\"name\" form:\"name\"`\n\tCreatorId     int64  `json:\"creator_id\" query:\"creator_id\" form:\"creator_id\"`\n\tGroupId       int64  `json:\"group_id\" query:\"group_id\" form:\"group_id\"`\n\tKeyId         int64  `json:\"key_id\" query:\"key_id\" form:\"key_id\"`\n\tRepoAddress   string `json:\"repo_address\" query:\"repo_address\" form:\"repo_address\"`\n\tProjectPath   string `json:\"project_path\" query:\"project_path\" form:\"project_path\"`\n\tDefaultBranch string `json:\"default_branch\" query:\"default_branch\" form:\"default_branch\"`\n\tSettings      string `json:\"settings\" query:\"settings\" form:\"settings\"`\n}\n\nfunc (model *UpdateProjectReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"id\":             model.Id,\n\t\t\"uuid\":           model.Uuid,\n\t\t\"name\":           model.Name,\n\t\t\"creator_id\":     model.CreatorId,\n\t\t\"group_id\":       model.GroupId,\n\t\t\"key_id\":         model.KeyId,\n\t\t\"repo_address\":   model.RepoAddress,\n\t\t\"project_path\":   model.ProjectPath,\n\t\t\"default_branch\": model.DefaultBranch,\n\t\t\"settings\":       model.Settings,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/user/LoginByWxCode_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype LoginByWxCodeReq struct {\n\tCode string `json:\"code\" query:\"code\" form:\"code\"`\n}\n\nfunc (model *LoginByWxCodeReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"code\": model.Code,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/requests/user/LoginByWxInfo_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype LoginByWxInfoReq struct {\n\tIv            string `json:\"iv\" query:\"iv\" form:\"iv\"`\n\tSessionKey    string `json:\"sessionKey\" query:\"sessionKey\" form:\"sessionKey\"`\n\tEncryptedData string `json:\"encryptedData\" query:\"encryptedData\" form:\"encryptedData\"`\n}\n\nfunc (model *LoginByWxInfoReq) ToFields() contracts.Fields {\n\tif model == nil {\n\t\treturn nil\n\t}\n\tfields := contracts.Fields{\n\t\t\"iv\":            model.Iv,\n\t\t\"sessionKey\":    model.SessionKey,\n\t\t\"encryptedData\": model.EncryptedData,\n\t}\n\treturn fields\n}\n"
  },
  {
    "path": "app/response/utils.go",
    "content": "package response\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/enums\"\n\t\"github.com/goal-web/goal/app/results\"\n)\n\nfunc ParseReqErr(err error) any {\n\treturn results.ResponseResult{\n\t\tMessage:    err.Error(),\n\t\tCode:       int32(enums.CodeParseReqErr),\n\t\tErrMessage: enums.CodeParseReqErr.Message(),\n\t\tData:       nil,\n\t}\n}\n\nfunc InvalidReq(err error) any {\n\treturn results.ResponseResult{\n\t\tMessage:    err.Error(),\n\t\tCode:       int32(enums.CodeParseReqErr),\n\t\tErrMessage: enums.CodeParseReqErr.Message(),\n\t\tData:       nil,\n\t}\n}\n\nfunc BizErr(err error) any {\n\treturn results.ResponseResult{\n\t\tMessage:    err.Error(),\n\t\tCode:       int32(enums.CodeBizErr),\n\t\tErrMessage: enums.CodeBizErr.Message(),\n\t\tData:       nil,\n\t}\n}\n\nfunc Success(data any) any {\n\tresult := results.ResponseResult{\n\t\tMessage:    \"\",\n\t\tCode:       int32(enums.CodeSuccess),\n\t\tErrMessage: enums.CodeSuccess.Message(),\n\t}\n\n\tif fieldsProvider, ok := data.(contracts.FieldsProvider); ok {\n\t\tresult.Data = fieldsProvider.ToFields()\n\t} else {\n\t\tresult.Data = data\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "app/results/ResponseResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/common.proto\n// \npackage results\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype ResponseResult struct {\n\tCode       int32  `json:\"code\" query:\"code\" form:\"code\"`\n\tErrMessage string `json:\"err_message\" query:\"err_message\" form:\"err_message\"`\n\tMessage    string `json:\"message\" query:\"message\" form:\"message\"`\n\tData       any    `json:\"data\" query:\"data\" form:\"data\"`\n}\n\nfunc (result *ResponseResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"code\":        result.Code,\n\t\t\"err_message\": result.ErrMessage,\n\t\t\"message\":     result.Message,\n\t\t\"data\":        result.Data,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/project/CreateProjectResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype CreateProjectResult struct {\n\tCode string `json:\"code\" query:\"code\" form:\"code\"`\n}\n\nfunc (result *CreateProjectResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"code\": result.Code,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/project/DeleteProjectResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype DeleteProjectResult struct {\n\tCode string `json:\"code\" query:\"code\" form:\"code\"`\n}\n\nfunc (result *DeleteProjectResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"code\": result.Code,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/project/GetProjectResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tmodels \"github.com/goal-web/goal/app/models\"\n)\n\ntype GetProjectResult struct {\n\tProject models.ProjectModel `json:\"project\" query:\"project\" form:\"project\"`\n}\n\nfunc (result *GetProjectResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"project\": result.Project,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/project/ListProjectsResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tmodels \"github.com/goal-web/goal/app/models\"\n)\n\ntype ListProjectsResult struct {\n\tTotal    int64                  `json:\"total\" query:\"total\" form:\"total\"`\n\tProjects []*models.ProjectModel `json:\"projects\" query:\"projects\" form:\"projects\"`\n}\n\nfunc (result *ListProjectsResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"total\":    result.Total,\n\t\t\"projects\": result.Projects,\n\t}\n\tprojectsList := make([]contracts.Fields, len(result.Projects))\n\tfor i, item := range result.Projects {\n\t\tprojectsList[i] = item.ToFields()\n\t}\n\tfields[\"projects\"] = projectsList\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/project/UpdateProjectResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n)\n\ntype UpdateProjectResult struct {\n\tCode string `json:\"code\" query:\"code\" form:\"code\"`\n}\n\nfunc (result *UpdateProjectResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"code\": result.Code,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/results/user/LoginByWxResult_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tmodels \"github.com/goal-web/goal/app/models\"\n)\n\ntype LoginByWxResult struct {\n\tToken      string            `json:\"token\" query:\"token\" form:\"token\"`\n\tUser       *models.UserModel `json:\"user\" query:\"user\" form:\"user\"`\n\tSessionKey string            `json:\"sessionKey\" query:\"sessionKey\" form:\"sessionKey\"`\n}\n\nfunc (result *LoginByWxResult) ToFields() contracts.Fields {\n\n\tfields := contracts.Fields{\n\t\t\"token\":      result.Token,\n\t\t\"user\":       result.User,\n\t\t\"sessionKey\": result.SessionKey,\n\t}\n\n\treturn fields\n}\n"
  },
  {
    "path": "app/services/project/Project_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/Project.proto\n// \npackage project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tproject \"github.com/goal-web/goal/app/requests/project\"\n\tproject0 \"github.com/goal-web/goal/app/results/project\"\n)\n\nvar ProjectServiceDefine ProjectServiceStatic\n\ntype ProjectServiceStatic struct {\n\tCreateProject func(req *project.CreateProjectReq, ctx contracts.Context) (*project0.CreateProjectResult, error)\n\tGetProject    func(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error)\n\tListProjects  func(req *project.ListProjectsReq, ctx contracts.Context) (*project0.ListProjectsResult, error)\n\tUpdateProject func(req *project.UpdateProjectReq, ctx contracts.Context) (*project0.UpdateProjectResult, error)\n\tDeleteProject func(req *project.DeleteProjectReq, ctx contracts.Context) (*project0.DeleteProjectResult, error)\n}\n\nfunc ProjectServiceCreateProject(req *project.CreateProjectReq, ctx contracts.Context) (*project0.CreateProjectResult, error) {\n\tif ProjectServiceDefine.CreateProject != nil {\n\t\treturn ProjectServiceDefine.CreateProject(req, ctx)\n\t}\n\treturn nil, nil\n}\n\nfunc ProjectServiceGetProject(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error) {\n\tif ProjectServiceDefine.GetProject != nil {\n\t\treturn ProjectServiceDefine.GetProject(req, ctx)\n\t}\n\treturn nil, nil\n}\n\nfunc ProjectServiceListProjects(req *project.ListProjectsReq, ctx contracts.Context) (*project0.ListProjectsResult, error) {\n\tif ProjectServiceDefine.ListProjects != nil {\n\t\treturn ProjectServiceDefine.ListProjects(req, ctx)\n\t}\n\treturn nil, nil\n}\n\nfunc ProjectServiceUpdateProject(req *project.UpdateProjectReq, ctx contracts.Context) (*project0.UpdateProjectResult, error) {\n\tif ProjectServiceDefine.UpdateProject != nil {\n\t\treturn ProjectServiceDefine.UpdateProject(req, ctx)\n\t}\n\treturn nil, nil\n}\n\nfunc ProjectServiceDeleteProject(req *project.DeleteProjectReq, ctx contracts.Context) (*project0.DeleteProjectResult, error) {\n\tif ProjectServiceDefine.DeleteProject != nil {\n\t\treturn ProjectServiceDefine.DeleteProject(req, ctx)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "app/services/project/project.go",
    "content": "package project\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/requests/project\"\n\tproject0 \"github.com/goal-web/goal/app/results/project\"\n)\n\nfunc init() {\n\n\tProjectServiceDefine.GetProject = func(req *project.GetProjectReq, ctx contracts.Context) (*project0.GetProjectResult, error) {\n\t\treturn &project0.GetProjectResult{\n\t\t\t// 查询项目\n\t\t}, nil\n\n\t}\n\n}\n"
  },
  {
    "path": "app/services/user/Auth_gen.go",
    "content": "// Code generated by goal-cli. DO NOT EDIT.\n// versions:\n// \tgoal-cli v0.5.24\n// \tgo       go1.24.0\n//\n// updated_at: 2025-03-24 20:22:07\n// source: pro/user.proto\n// \npackage user\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tuser \"github.com/goal-web/goal/app/requests/user\"\n\tuser0 \"github.com/goal-web/goal/app/results/user\"\n)\n\nvar AuthServiceDefine AuthServiceStatic\n\ntype AuthServiceStatic struct {\n\tLoginByWxAppCode func(req *user.LoginByWxCodeReq, ctx contracts.Context) (*user0.LoginByWxResult, error)\n\tLoginByWxAppInfo func(req *user.LoginByWxInfoReq, ctx contracts.Context) (*user0.LoginByWxResult, error)\n}\n\nfunc AuthServiceLoginByWxAppCode(req *user.LoginByWxCodeReq, ctx contracts.Context) (*user0.LoginByWxResult, error) {\n\tif AuthServiceDefine.LoginByWxAppCode != nil {\n\t\treturn AuthServiceDefine.LoginByWxAppCode(req, ctx)\n\t}\n\treturn nil, nil\n}\n\nfunc AuthServiceLoginByWxAppInfo(req *user.LoginByWxInfoReq, ctx contracts.Context) (*user0.LoginByWxResult, error) {\n\tif AuthServiceDefine.LoginByWxAppInfo != nil {\n\t\treturn AuthServiceDefine.LoginByWxAppInfo(req, ctx)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "app/websocket/demo.go",
    "content": "package websocket\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/supports/logs\"\n)\n\ntype DemoController struct {\n}\n\nfunc (d DemoController) OnConnect(request contracts.HttpRequest, fd uint64) error {\n\t// todo: 绑定用户和 fd\n\treturn nil\n}\n\nfunc (d DemoController) OnMessage(frame contracts.WebSocketFrame) {\n\tlogs.Default().Info(\"received websocket message:\" + frame.RawString())\n}\n\nfunc (d DemoController) OnClose(fd uint64) {\n\t// todo: 解绑 fd\n}\n"
  },
  {
    "path": "bootstrap/console/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/bootstrap/core\"\n)\n\nfunc main() {\n\tapp := core.Application()\n\n\tapp.Call(func(console3 contracts.Console, input contracts.ConsoleInput) {\n\t\tconsole3.Run(input)\n\t})\n}\n"
  },
  {
    "path": "bootstrap/core/application.go",
    "content": "package core\n\nimport (\n\t\"github.com/goal-web/application\"\n\t\"github.com/goal-web/bloomfilter\"\n\t\"github.com/goal-web/cache\"\n\t\"github.com/goal-web/config\"\n\t\"github.com/goal-web/console\"\n\t\"github.com/goal-web/console/scheduling\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database\"\n\t\"github.com/goal-web/email\"\n\t\"github.com/goal-web/encryption\"\n\t\"github.com/goal-web/events\"\n\t\"github.com/goal-web/filesystem\"\n\t\"github.com/goal-web/goal/app/exceptions\"\n\t\"github.com/goal-web/goal/app/providers\"\n\tconfig2 \"github.com/goal-web/goal/config\"\n\t\"github.com/goal-web/hashing\"\n\t\"github.com/goal-web/http/sse\"\n\t\"github.com/goal-web/http/websocket\"\n\t\"github.com/goal-web/migration\"\n\t\"github.com/goal-web/queue\"\n\t\"github.com/goal-web/ratelimiter\"\n\t\"github.com/goal-web/redis\"\n\t\"github.com/goal-web/routing\"\n\t\"github.com/goal-web/serialization\"\n\t\"github.com/goal-web/supports/utils\"\n\t\"github.com/golang-module/carbon/v2\"\n\t\"os\"\n)\n\ntype App struct {\n\tQueueWorker      bool\n\tSchedulingWorker bool\n}\n\nfunc Application(c ...App) contracts.Application {\n\tenv := config.NewToml(config.File(\"env.toml\"))\n\tapp := application.Singleton(env.GetBool(\"app.debug\"))\n\tpwd, _ := os.Getwd()\n\tapp.Instance(\"pwd\", pwd)\n\n\tconf := utils.DefaultValue(c, App{})\n\t// 设置异常处理器\n\tapp.Singleton(\"exceptions.handler\", func() contracts.ExceptionHandler {\n\t\treturn exceptions.NewHandler()\n\t})\n\n\tapp.RegisterServices(\n\t\tconfig.NewService(env, config2.GetConfigProviders()),\n\t\thashing.NewService(),\n\t\tencryption.NewService(),\n\t\tfilesystem.NewService(),\n\t\tserialization.NewService(),\n\t\tevents.NewService(),\n\t\tproviders.NewEvents(),\n\t\tredis.NewService(),\n\t\tcache.NewService(),\n\t\tbloomfilter.NewService(),\n\t\tratelimiter.NewService(),\n\t\tdatabase.NewService(),\n\t\tqueue.NewService(conf.QueueWorker),\n\t\temail.NewService(),\n\t\tconsole.NewService(),\n\t\tscheduling.NewService(conf.SchedulingWorker),\n\t\tmigration.NewService(),\n\t\trouting.NewService(),\n\t\tsse.NewService(),\n\t\twebsocket.NewService(),\n\t)\n\n\tapp.RegisterServices(\n\t\tproviders.NewApp(),\n\t)\n\n\tapp.Call(func(config contracts.Config, dispatcher contracts.EventDispatcher, console3 contracts.Console) {\n\t\tappConfig := config.Get(\"app\").(application.Config)\n\t\tcarbon.SetLocale(appConfig.Locale)\n\t\tcarbon.SetTimezone(appConfig.Timezone)\n\t})\n\n\treturn app\n}\n"
  },
  {
    "path": "bootstrap/queue/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/goal-web/goal/bootstrap/core\"\n\t\"github.com/goal-web/supports/logs\"\n)\n\nfunc main() {\n\tapp := core.Application(core.App{\n\t\tQueueWorker: true,\n\t})\n\n\tif errors := app.Start(); len(errors) > 0 {\n\t\tlogs.WithField(\"errors\", errors).Fatal(\"goal 异常!\")\n\t} else {\n\t\tlogs.Default().Info(\"goal 已关闭\")\n\t}\n}\n"
  },
  {
    "path": "bootstrap/schedule/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/goal-web/goal/bootstrap/core\"\n\t\"github.com/goal-web/supports/logs\"\n)\n\nfunc main() {\n\tapp := core.Application(core.App{\n\t\tSchedulingWorker: true,\n\t})\n\n\tif errors := app.Start(); len(errors) > 0 {\n\t\tlogs.WithField(\"errors\", errors).Fatal(\"goal 异常!\")\n\t} else {\n\t\tlogs.Default().Info(\"goal 已关闭\")\n\t}\n}\n"
  },
  {
    "path": "config/README_cache_config.md",
    "content": "# 缓存配置说明\n\n## 概述\n\n本文档说明了Goal Web框架中缓存组件的配置选项和使用方法。\n\n## 配置结构\n\n缓存配置支持三种驱动：\n- **memory**: 内存缓存（RAM驱动）\n- **file**: 文件缓存\n- **redis**: Redis缓存\n\n## 配置选项\n\n### 基本配置\n\n```go\ncache.Config{\n    Default: \"memory\",  // 默认缓存驱动\n    Stores: map[string]contracts.Fields{\n        // 各种缓存驱动的配置\n    },\n}\n```\n\n### 环境变量\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `CACHE_DEFAULT` | `memory` | 默认缓存驱动 |\n| `CACHE_PREFIX` | `\"\"` | 缓存键前缀 |\n| `CACHE_TTL` | `86400` | 默认缓存TTL（秒） |\n| `CACHE_FILE_PATH` | `./storage/cache` | 文件缓存路径 |\n| `CACHE_CONNECTION` | `default` | Redis连接名称 |\n\n## 驱动配置\n\n### 1. 内存缓存 (memory)\n\n```go\n\"memory\": {\n    \"driver\": \"ram\",\n    \"prefix\": env.GetString(\"cache.prefix\"),\n    \"ttl\":    utils.IntOr(env.GetInt(\"cache.ttl\"), 24*int(time.Hour)),\n}\n```\n\n**配置参数：**\n- `driver`: 固定为 \"ram\"\n- `prefix`: 缓存键前缀\n- `ttl`: 默认过期时间（秒）\n\n**特点：**\n- 高性能，数据存储在内存中\n- 应用重启后数据丢失\n- 支持统计和监控功能\n\n### 2. 文件缓存 (file)\n\n```go\n\"file\": {\n    \"driver\": \"file\",\n    \"path\":   utils.StringOr(env.GetString(\"cache.file.path\"), \"./storage/cache\"),\n    \"prefix\": env.GetString(\"cache.prefix\"),\n}\n```\n\n**配置参数：**\n- `driver`: 固定为 \"file\"\n- `path`: 缓存文件存储路径\n- `prefix`: 缓存键前缀\n\n**特点：**\n- 持久化存储，应用重启后数据保留\n- 适合开发环境和小型应用\n- 自动创建缓存目录\n\n### 3. Redis缓存 (redis)\n\n```go\n\"redis\": {\n    \"driver\":     \"redis\",\n    \"connection\": utils.StringOr(env.GetString(\"cache.connection\"), \"default\"),\n    \"prefix\":     env.GetString(\"cache.prefix\"),\n}\n```\n\n**配置参数：**\n- `driver`: 固定为 \"redis\"\n- `connection`: Redis连接名称\n- `prefix`: 缓存键前缀\n\n**特点：**\n- 高性能，支持分布式\n- 持久化存储\n- 支持复杂数据结构\n\n## 使用示例\n\n### 1. 基本使用\n\n```go\n// 获取默认缓存实例\ncache := cache.Store()\n\n// 获取指定驱动缓存实例\nmemoryCache := cache.Store(\"memory\")\nfileCache := cache.Store(\"file\")\nredisCache := cache.Store(\"redis\")\n```\n\n### 2. 环境配置\n\n```bash\n# 设置环境变量\nexport CACHE_DEFAULT=memory\nexport CACHE_PREFIX=myapp_\nexport CACHE_TTL=3600\nexport CACHE_FILE_PATH=/tmp/cache\nexport CACHE_CONNECTION=redis1\n```\n\n### 3. 配置文件\n\n```toml\n# config.toml\n[cache]\ndefault = \"memory\"\nprefix = \"myapp_\"\nttl = 3600\n\n[cache.file]\npath = \"/tmp/cache\"\n\n[cache.redis]\nconnection = \"redis1\"\n```\n\n## 配置最佳实践\n\n### 1. 开发环境\n```go\n// 使用内存缓存，快速开发\ncache.default = \"memory\"\n```\n\n### 2. 测试环境\n```go\n// 使用文件缓存，便于调试\ncache.default = \"file\"\ncache.file.path = \"./test_cache\"\n```\n\n### 3. 生产环境\n```go\n// 使用Redis缓存，高性能和可靠性\ncache.default = \"redis\"\ncache.connection = \"production_redis\"\n```\n\n### 4. 混合使用\n```go\n// 不同类型的数据使用不同的缓存\nuserCache := cache.Store(\"memory\")    // 用户会话\nconfigCache := cache.Store(\"file\")    // 配置数据\ndataCache := cache.Store(\"redis\")     // 业务数据\n```\n\n## 性能考虑\n\n### 1. 内存缓存\n- **优点**: 最高性能，零延迟\n- **缺点**: 内存占用，重启丢失\n- **适用**: 临时数据，会话缓存\n\n### 2. 文件缓存\n- **优点**: 持久化，简单部署\n- **缺点**: 磁盘I/O，性能中等\n- **适用**: 配置缓存，开发环境\n\n### 3. Redis缓存\n- **优点**: 高性能，分布式，持久化\n- **缺点**: 需要额外服务，网络延迟\n- **适用**: 生产环境，大数据量\n\n## 监控和调试\n\n### 1. 统计信息\n```go\n// 获取缓存统计（仅内存缓存支持）\nif memoryCache, ok := cache.Store(\"memory\").(*drivers.Memory); ok {\n    stats := memoryCache.GetStats()\n    fmt.Printf(\"命中率: %.2f%%\\n\", stats[\"hit_rate\"])\n    fmt.Printf(\"内存使用: %.2f MB\\n\", stats[\"memory_usage\"].(map[string]any)[\"total_mb\"])\n}\n```\n\n### 2. 键管理\n```go\n// 获取所有键（仅内存缓存支持）\nif memoryCache, ok := cache.Store(\"memory\").(*drivers.Memory); ok {\n    keys := memoryCache.GetKeys()\n    fmt.Printf(\"当前有 %d 个缓存键\\n\", len(keys))\n}\n```\n\n### 3. 清理过期项\n```go\n// 手动清理过期项（仅内存缓存支持）\nif memoryCache, ok := cache.Store(\"memory\").(*drivers.Memory); ok {\n    cleaned := memoryCache.CleanupAllExpired()\n    fmt.Printf(\"清理了 %d 个过期项\\n\", cleaned)\n}\n```\n\n## 故障排除\n\n### 1. 常见问题\n\n**问题**: 缓存不生效\n**解决**: 检查驱动名称是否正确，确保缓存服务正常运行\n\n**问题**: 内存使用过高\n**解决**: 调整TTL设置，定期清理过期项\n\n**问题**: 文件权限错误\n**解决**: 确保缓存目录有写入权限\n\n**问题**: Redis连接失败\n**解决**: 检查Redis服务状态和连接配置\n\n### 2. 调试技巧\n\n```go\n// 启用调试日志\nlogs.SetLevel(logs.DebugLevel)\n\n// 检查缓存状态\nstats := cache.GetStats()\nlogs.Debug(\"Cache stats\", stats)\n```\n\n## 总结\n\n缓存配置提供了灵活的选项来满足不同场景的需求：\n\n1. **开发环境**: 使用内存缓存，快速迭代\n2. **测试环境**: 使用文件缓存，便于调试\n3. **生产环境**: 使用Redis缓存，高性能和可靠性\n\n通过合理配置缓存驱动和参数，可以显著提升应用程序的性能和用户体验。\n\n\n"
  },
  {
    "path": "config/app.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/application\"\n\t\"github.com/goal-web/contracts\"\n)\n\nvar configs = make(map[string]contracts.ConfigProvider)\n\nfunc GetConfigProviders() map[string]contracts.ConfigProvider {\n\treturn configs\n}\n\nfunc init() {\n\tconfigs[\"app\"] = func(env contracts.Env) any {\n\t\treturn application.Config{\n\t\t\tName:     env.GetString(\"app.name\"),\n\t\t\tDebug:    env.GetBool(\"app.debug\"),\n\t\t\tTimezone: env.GetString(\"app.timezone\"),\n\t\t\tEnv:      env.GetString(\"app.env\"),\n\t\t\tLocale:   env.GetString(\"app.locale\"),\n\t\t\tKey:      env.GetString(\"app.key\"),\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/auth.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/auth\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/models\"\n\t\"github.com/golang-jwt/jwt\"\n\t\"time\"\n)\n\nfunc init() {\n\tconfigs[\"auth\"] = func(env contracts.Env) any {\n\t\treturn auth.Config{\n\t\t\tDefaults: auth.Defaults{\n\t\t\t\tGuard: env.StringOptional(\"auth.default\", \"jwt\"),\n\t\t\t\tUser:  env.StringOptional(\"auth.user\", \"db\"),\n\t\t\t},\n\t\t\tGuards: map[string]contracts.Fields{\n\t\t\t\t\"jwt\": {\n\t\t\t\t\t\"driver\":   \"jwt\",\n\t\t\t\t\t\"secret\":   env.GetString(\"auth.jwt.secret\"),\n\t\t\t\t\t\"method\":   jwt.SigningMethodHS256,\n\t\t\t\t\t\"lifetime\": 60 * 60 * 24 * time.Second,\n\t\t\t\t\t\"provider\": \"db\",\n\t\t\t\t},\n\t\t\t\t\"session\": {\n\t\t\t\t\t\"driver\":      \"session\",\n\t\t\t\t\t\"provider\":    \"db\",\n\t\t\t\t\t\"session_key\": env.StringOptional(\"auth.session.key\", \"auth_session\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tUsers: map[string]contracts.Fields{\n\t\t\t\t\"db\": {\n\t\t\t\t\t\"driver\":   \"db\",\n\t\t\t\t\t\"provider\": models.UserAuthProvider,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/bloomfilter.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/bloomfilter\"\n\t\"github.com/goal-web/contracts\"\n)\n\nfunc init() {\n\tconfigs[\"bloomfilter\"] = func(env contracts.Env) any {\n\t\treturn bloomfilter.Config{\n\t\t\tDefault: \"default\",\n\t\t\tFilters: bloomfilter.Filters{\n\t\t\t\t\"default\": contracts.Fields{\n\t\t\t\t\t\"driver\":   \"file\", // 将数据序列化到文件中，不支持分布式\n\t\t\t\t\t\"size\":     100000,\n\t\t\t\t\t\"k\":        .01,\n\t\t\t\t\t\"filepath\": \"storage/bloomfilter/default\", // 完整路径\n\t\t\t\t},\n\t\t\t\t\"users\": contracts.Fields{\n\t\t\t\t\t\"driver\": \"redis\", // 通过 redis bitmap 存储，支持分布式\n\t\t\t\t\t\"size\":   100000,\n\t\t\t\t\t\"k\":      .01,\n\t\t\t\t\t\"key\":    \"bloomfilter:{name}\", // {name} 表示该 filter 的key，这里是 users\n\t\t\t\t\t//\"connection\": \"cache\", // redis 连接\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/cache.go",
    "content": "package config\n\nimport (\n\t\"time\"\n\n\t\"github.com/goal-web/cache\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/supports/utils\"\n)\n\nfunc init() {\n\tconfigs[\"cache\"] = func(env contracts.Env) any {\n\t\treturn cache.Config{\n\t\t\tDefault: utils.StringOr(env.GetString(\"cache.default\"), \"memory\"),\n\t\t\tStores: map[string]contracts.Fields{\n\t\t\t\t\"memory\": {\n\t\t\t\t\t\"driver\": \"ram\",\n\t\t\t\t\t\"prefix\": env.GetString(\"cache.prefix\"),\n\t\t\t\t\t\"ttl\":    utils.IntOr(env.GetInt(\"cache.ttl\"), 24*int(time.Hour)), // 默认缓存生命周期\n\t\t\t\t},\n\t\t\t\t\"file\": {\n\t\t\t\t\t\"driver\": \"file\",\n\t\t\t\t\t\"path\":   utils.StringOr(env.GetString(\"cache.file.path\"), \"./storage/cache\"),\n\t\t\t\t\t\"prefix\": env.GetString(\"cache.prefix\"),\n\t\t\t\t},\n\t\t\t\t\"redis\": {\n\t\t\t\t\t\"driver\":     \"redis\",\n\t\t\t\t\t\"connection\": utils.StringOr(env.GetString(\"cache.connection\"), \"default\"),\n\t\t\t\t\t\"prefix\":     env.GetString(\"cache.prefix\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/cache_example.toml",
    "content": "# 缓存配置示例\n# Cache Configuration Example\n\n# 默认缓存驱动\ncache.default = \"memory\"\n\n# 缓存键前缀\ncache.prefix = \"goal_\"\n\n# 默认缓存TTL（秒）\ncache.ttl = 86400\n\n# 文件缓存配置\ncache.file.path = \"./storage/cache\"\n\n# Redis缓存配置\ncache.connection = \"default\"\n\n# 环境变量示例\n# CACHE_DEFAULT=memory\n# CACHE_PREFIX=goal_\n# CACHE_TTL=86400\n# CACHE_FILE_PATH=./storage/cache\n# CACHE_CONNECTION=default\n\n\n"
  },
  {
    "path": "config/database.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/database\"\n\t\"strings\"\n)\n\nfunc init() {\n\tconfigs[\"database\"] = func(env contracts.Env) any {\n\t\treturn database.Config{\n\t\t\tDefault: env.StringOptional(\"db.connection\", \"mysql\"),\n\t\t\tConnections: map[string]contracts.Fields{\n\t\t\t\t\"sqlite\": {\n\t\t\t\t\t\"driver\":   \"sqlite\",\n\t\t\t\t\t\"database\": env.GetString(\"db.sqlite.database\"),\n\t\t\t\t},\n\t\t\t\t\"mysql\": {\n\t\t\t\t\t\"driver\":          \"mysql\",\n\t\t\t\t\t\"host\":            env.GetString(\"db.host\"),\n\t\t\t\t\t\"port\":            env.GetString(\"db.port\"),\n\t\t\t\t\t\"database\":        env.GetString(\"db.database\"),\n\t\t\t\t\t\"username\":        env.GetString(\"db.username\"),\n\t\t\t\t\t\"password\":        env.GetString(\"db.password\"),\n\t\t\t\t\t\"unix_socket\":     env.GetString(\"db.unix_socket\"),\n\t\t\t\t\t\"charset\":         env.StringOptional(\"db.charset\", \"utf8mb4\"),\n\t\t\t\t\t\"collation\":       env.StringOptional(\"db.collation\", \"utf8mb4_unicode_ci\"),\n\t\t\t\t\t\"prefix\":          env.GetString(\"db.prefix\"),\n\t\t\t\t\t\"strict\":          env.GetBool(\"db.struct\"),\n\t\t\t\t\t\"max_connections\": env.GetInt(\"db.max_connections\"),\n\t\t\t\t\t\"max_idles\":       env.GetInt(\"db.max_idles\"),\n\t\t\t\t\t\"other\":           \"&parseTime=true&multiStatements=true\",\n\t\t\t\t},\n\t\t\t\t\"pgsql\": {\n\t\t\t\t\t\"driver\":          \"postgres\",\n\t\t\t\t\t\"host\":            env.GetString(\"db.pgsql.host\"),\n\t\t\t\t\t\"port\":            env.GetString(\"db.pgsql.port\"),\n\t\t\t\t\t\"database\":        env.GetString(\"db.pgsql.database\"),\n\t\t\t\t\t\"username\":        env.GetString(\"db.pgsql.username\"),\n\t\t\t\t\t\"password\":        env.GetString(\"db.pgsql.password\"),\n\t\t\t\t\t\"charset\":         env.StringOptional(\"db.pgsql.charset\", \"utf8mb4\"),\n\t\t\t\t\t\"prefix\":          env.GetString(\"db.pgsql.prefix\"),\n\t\t\t\t\t\"schema\":          env.StringOptional(\"db.pgsql.schema\", \"public\"),\n\t\t\t\t\t\"sslmode\":         env.StringOptional(\"db.pgsql.sslmode\", \"disable\"),\n\t\t\t\t\t\"max_connections\": env.GetInt(\"db.pgsql.max_connections\"),\n\t\t\t\t\t\"max_idles\":       env.GetInt(\"db.pgsql.max_idles\"),\n\t\t\t\t},\n\t\t\t\t\"clickhouse\": {\n\t\t\t\t\t\"driver\":          \"clickhouse\",\n\t\t\t\t\t\"dsn\":             env.GetString(\"db.clickhouse.dsn\"), // see https://github.com/ClickHouse/clickhouse-go#dsn\n\t\t\t\t\t\"max_connections\": env.GetInt(\"db.clickhouse.max_connections\"),\n\t\t\t\t\t\"max_idles\":       env.GetInt(\"db.clickhouse.max_idles\"),\n\t\t\t\t\t\"address\":         strings.Split(env.GetString(\"db.clickhouse.address\"), \",\"),\n\t\t\t\t\t\"database\":        env.GetString(\"db.clickhouse.database\"),\n\t\t\t\t\t\"username\":        env.GetString(\"db.clickhouse.username\"),\n\t\t\t\t\t\"password\":        env.GetString(\"db.clickhouse.password\"),\n\t\t\t\t\t\"debug\":           env.GetString(\"db.clickhouse.debug\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/encryption.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/encryption\"\n)\n\nfunc init() {\n\tconfigs[\"encryption\"] = func(env contracts.Env) any {\n\t\treturn encryption.Config{\n\t\t\tDefault: \"AES\",\n\t\t\tDrivers: map[string]contracts.EncryptDriver{},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/filesystem.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/filesystem\"\n\t\"os\"\n)\n\nfunc init() {\n\tconfigs[\"filesystem\"] = func(env contracts.Env) any {\n\t\treturn filesystem.Config{\n\t\t\tDefault: env.StringOptional(\"filesystem.disk\", \"public\"),\n\t\t\tDisks: map[string]contracts.Fields{\n\t\t\t\t\"public\": {\n\t\t\t\t\t\"driver\": \"local\",\n\t\t\t\t\t\"root\":   env.StringOptional(\"filesystem.root\", \"storage/app/public\"),\n\t\t\t\t\t\"perm\":   os.ModePerm,\n\t\t\t\t},\n\t\t\t\t\"qiniu\": {\n\t\t\t\t\t\"driver\":     \"qiniu\",\n\t\t\t\t\t\"ttl\":        3600, // 私有 url 有效期，单位秒\n\t\t\t\t\t\"private\":    env.GetBool(\"qiniu.private\"),\n\t\t\t\t\t\"domain\":     env.GetBool(\"qiniu.domain\"), // example: https://image.example.com\"\n\t\t\t\t\t\"bucket\":     env.GetString(\"qiniu.bucket\"),\n\t\t\t\t\t\"access_key\": env.GetString(\"qiniu.access.key\"),\n\t\t\t\t\t\"secret_key\": env.GetString(\"qiniu.secret.key\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/http.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/http\"\n)\n\nfunc init() {\n\tconfigs[\"http\"] = func(env contracts.Env) any {\n\t\tconfig := http.Config{\n\t\t\tHost:              env.GetString(\"http.host\"),\n\t\t\tPort:              env.GetString(\"http.port\"),\n\t\t\tStaticDirectories: map[string]string{\n\t\t\t\t//\"/\": \"public\",\n\t\t\t},\n\t\t}\n\n\t\tif env.GetString(\"app.env\") == \"local\" {\n\t\t\tconfig.StaticDirectories[\"/\"] = \"public\"\n\t\t}\n\n\t\treturn config\n\t}\n}\n"
  },
  {
    "path": "config/mail.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/email\"\n)\n\nfunc init() {\n\tconfigs[\"mail\"] = func(env contracts.Env) any {\n\t\treturn email.Config{\n\t\t\tDefault: \"default\",\n\t\t\tMailers: map[string]contracts.Fields{\n\t\t\t\t\"default\": {\n\t\t\t\t\t\"driver\": \"mailer\",\n\t\t\t\t\t//\"tls\":      &tls.Config{InsecureSkipVerify: true},\n\t\t\t\t\t\"from\":     env.GetString(\"mail.from\"),\n\t\t\t\t\t\"host\":     env.GetString(\"mail.host\"),\n\t\t\t\t\t\"port\":     env.GetString(\"mail.port\"),\n\t\t\t\t\t\"username\": env.GetString(\"mail.username\"),\n\t\t\t\t\t\"password\": env.GetString(\"mail.password\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/queue.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/queue\"\n\t\"github.com/nsqio/go-nsq\"\n\t\"strings\"\n)\n\nfunc init() {\n\tconfigs[\"queue\"] = func(env contracts.Env) any {\n\t\treturn queue.Config{\n\t\t\tDefaults: queue.Defaults{\n\t\t\t\tConnection: env.StringOptional(\"queue.connection\", \"default\"),\n\t\t\t\tQueue:      env.StringOptional(\"queue.default\", \"default\"),\n\t\t\t},\n\t\t\tConnections: map[string]contracts.Fields{\n\t\t\t\t\"default\": {\n\t\t\t\t\t\"driver\":  \"kafka\",\n\t\t\t\t\t\"delay\":   \"delay_queue\", // 延迟队列名\n\t\t\t\t\t\"brokers\": strings.Split(env.GetString(\"queue.kafka.brokers\"), \",\"),\n\t\t\t\t\t//\"dialer\": &kafka.Dialer{}, // 自定义 kafka.Dialer\n\t\t\t\t\t\"queue\": []string{\n\t\t\t\t\t\t\"default\", \"slow\", \"high\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"nsq\": {\n\t\t\t\t\t\"driver\":           \"nsq\",\n\t\t\t\t\t\"address\":          env.GetString(\"queue.nsq.address\"),\n\t\t\t\t\t\"lookup_addresses\": strings.Split(env.GetString(\"queue.nsq.lookup_addresses\"), \",\"),\n\t\t\t\t\t\"config\":           &nsq.Config{}, // 自定义 nsq 设置\n\t\t\t\t\t\"queue\": []string{\n\t\t\t\t\t\t\"default\", \"slow\", \"high\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"sync\":      {\"driver\": \"sync\"},\n\t\t\t\t\"empty\":     {\"driver\": \"empty\"},\n\t\t\t\t\"goroutine\": {\"driver\": \"goroutine\"},\n\t\t\t},\n\t\t\tFailed: queue.FailedJobs{\n\t\t\t\tDatabase: env.StringOptional(\"db.connection\", \"mysql\"),\n\t\t\t\tTable:    \"failed_jobs\",\n\t\t\t},\n\t\t\tWorkers: map[string]queue.Workers{ // 相当于 laravel 的 horizon 配置\n\t\t\t\t\"local\": { // 本地环境\n\t\t\t\t\t\"default\": { // 工作组\n\t\t\t\t\t\tConnection: env.StringOptional(\"queue.connection\", \"default\"), // 指定连接\n\t\t\t\t\t\tTries:      3,                                                 // 最大尝试次数\n\t\t\t\t\t\tQueue:      []string{\"default\", \"slow\", \"high\"},               // 处理指定队列\n\t\t\t\t\t\tProcesses:  10,                                                // 十个协程(工人)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"production\": { // 生产环境\n\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/redis.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/redis\"\n\t\"github.com/goal-web/supports/utils\"\n)\n\nfunc init() {\n\tconfigs[\"redis\"] = func(env contracts.Env) any {\n\t\treturn redis.Config{\n\t\t\tDefault: utils.StringOr(env.GetString(\"redis.default\"), \"default\"),\n\t\t\tStores: map[string]contracts.Fields{\n\t\t\t\t\"default\": {\n\t\t\t\t\t\"network\":  env.GetString(\"redis.network\"),\n\t\t\t\t\t\"host\":     env.GetString(\"redis.host\"),\n\t\t\t\t\t\"port\":     env.GetString(\"redis.port\"),\n\t\t\t\t\t\"username\": env.GetString(\"redis.username\"),\n\t\t\t\t\t\"password\": env.GetString(\"redis.password\"),\n\t\t\t\t\t\"db\":       env.GetInt64(\"redis.db\"),\n\t\t\t\t\t\"retries\":  env.GetInt64(\"redis.retries\"),\n\t\t\t\t},\n\t\t\t\t\"cache\": {\n\t\t\t\t\t\"network\":  env.GetString(\"redis.cache.network\"),\n\t\t\t\t\t\"host\":     env.GetString(\"redis.cache.host\"),\n\t\t\t\t\t\"port\":     env.GetString(\"redis.cache.port\"),\n\t\t\t\t\t\"username\": env.GetString(\"redis.cache.username\"),\n\t\t\t\t\t\"password\": env.GetString(\"redis.cache.password\"),\n\t\t\t\t\t\"db\":       env.GetInt64(\"redis.cache.db\"),\n\t\t\t\t\t\"retries\":  env.GetInt64(\"redis.cache.retries\"),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/serialization.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/jobs\"\n\t\"github.com/goal-web/serialization\"\n)\n\nfunc init() {\n\tconfigs[\"serialization\"] = func(env contracts.Env) any {\n\t\treturn serialization.Config{\n\t\t\tDefault: \"json\", // 支持：json、gob、xml。\n\t\t\tClass: []contracts.Class[any]{ // 需要序列化的类\n\t\t\t\tjobs.DemoClass,\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/session.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/session\"\n\t\"time\"\n)\n\nfunc init() {\n\tconfigs[\"session\"] = func(env contracts.Env) any {\n\t\treturn session.Config{\n\t\t\tDriver:     \"redis\", // 目前支持 cookie、redis\n\t\t\tEncrypt:    true,\n\t\t\tDomain:     env.GetString(\"session.domain\"),\n\t\t\tLifetime:   time.Duration(env.GetInt(\"session.lifetime\")),\n\t\t\tConnection: \"default\",         // database、redis 用到\n\t\t\tKey:        \"goal_session:%s\", // redis 驱动所用到的 key\n\t\t\tTable:      \"sessions\",        // database 用到\n\t\t\tName:       env.StringOptional(\"session.name\", \"goal\"),\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/views.go",
    "content": "package config\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/views\"\n)\n\nfunc init() {\n\tconfigs[\"views\"] = func(env contracts.Env) any {\n\t\treturn views.Config{\n\t\t\tPath: env.StringOptional(\"views.path\", \"views\"),\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "config/websocket.go",
    "content": "package config\n\nimport (\n\twebsocket2 \"github.com/fasthttp/websocket\"\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/http/websocket\"\n)\n\nfunc init() {\n\tconfigs[\"websocket\"] = func(env contracts.Env) any {\n\t\treturn websocket.Config{\n\t\t\tUpgrader: websocket2.FastHTTPUpgrader{\n\t\t\t\tHandshakeTimeout: 5,\n\t\t\t\t//ReadBufferSize:    0,\n\t\t\t\t//WriteBufferSize:   0,\n\t\t\t\t//WriteBufferPool:   nil,\n\t\t\t\t//Subprotocols:      nil,\n\t\t\t\t//Error:             nil,\n\t\t\t\t//CheckOrigin:       nil,\n\t\t\t\t//EnableCompression: false,\n\t\t\t},\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "database/.gitignore",
    "content": ""
  },
  {
    "path": "database/migrations/2024_05_09_141932_create_articles.down.sql",
    "content": "drop table if exists articles"
  },
  {
    "path": "database/migrations/2024_05_09_141932_create_articles.sql",
    "content": "CREATE TABLE IF NOT EXISTS articles\n(\n    `id`       INT UNSIGNED AUTO_INCREMENT,\n    title      varchar(20) not null,\n    created_at timestamp,\n    updated_at timestamp,\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;"
  },
  {
    "path": "env.toml",
    "content": "[app]\nname = \"goal\"\nkey = \"dQcxsKvBZKNfWivwnhKlDwvseguknBZPEiiDRQlIatjKLLpbzK\"\nenv = \"local\"\ndebug = true\n\n[http]\nhost = \"0.0.0.0\"\nport = \"8009\"\n\n\n[queue]\nconnection = \"goroutine\"\nkafka.brokers = \"localhost:9092\"\nnsq.address = \"localhost:49156\"\n\n[db]\nconnection = \"mysql\"\nhost = \"127.0.0.1\"\nport = \"3306\"\ndatabase = \"goal\"\nusername = \"root\"\npassword = \"root\"\n\n[db.sqlite]\ndatabase = \"database/database.sqlite\"\n\n[db.pgsql]\nhost = \"localhost\"\nport = \"55433\"\ndatabase = \"postgres\"\nusername = \"postgres\"\npassword = \"123456\"\n\n[redis]\nhost = \"hsy\"\nport = \"6379\"\npassword = \"123456\"\n\n[redis.cache]\nhost = \"hsy\"\nport = \"6379\"\ndb = 1\n\n# 缓存配置\n[cache]\ndriver = \"redis\"\nconnection = \"cache\"\nprefix = \"redis_\"\n\n# 哈希配置\n[hashing]\ndriver = \"bcrypt\"\ncost = \"14\"\nsalt = \"goal\"\n# 自定义哈希\n[hashing.hashers]\nmd5.driver = \"md5\"\nmd5.salt = \"goal\"\n\n# 文件系统配置\n[filesystem]\ndisk = \"public\"\nroot = \"storage/app/public\"\nperm = \"0777\"\n\n[filesystem.qiniu]\nprivate = \"false\"\nbucket = \"aa\"\ndomain = \"https://xxx.xxx.com\"\naccess_key = \"\"\nsecret_key = \"\"\n\n# session 配置\n[session]\nid = \"goal\"\nname = \"goal_session:\"\n\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/goal-web/goal\n\ngo 1.25.0\n\nreplace github.com/goal-web/goal-cli => ../goal-cli\n\nrequire (\n\tgithub.com/alicebob/miniredis/v2 v2.34.0\n\tgithub.com/fasthttp/websocket v1.5.10\n\tgithub.com/go-redis/redis/v8 v8.11.4\n\tgithub.com/goal-web/application v0.5.2\n\tgithub.com/goal-web/auth v0.5.3\n\tgithub.com/goal-web/bloomfilter v0.5.2\n\tgithub.com/goal-web/cache v0.5.2\n\tgithub.com/goal-web/collection v0.5.2\n\tgithub.com/goal-web/config v0.5.4\n\tgithub.com/goal-web/console v0.5.4\n\tgithub.com/goal-web/contracts v0.5.3\n\tgithub.com/goal-web/database v0.5.3\n\tgithub.com/goal-web/email v0.5.2\n\tgithub.com/goal-web/encryption v0.5.2\n\tgithub.com/goal-web/events v0.5.2\n\tgithub.com/goal-web/filesystem v0.5.2\n\tgithub.com/goal-web/goal-cli v0.5.42\n\tgithub.com/goal-web/hashing v0.5.2\n\tgithub.com/goal-web/http v0.5.11\n\tgithub.com/goal-web/migration v0.5.6\n\tgithub.com/goal-web/queue v0.5.2\n\tgithub.com/goal-web/ratelimiter v0.5.2\n\tgithub.com/goal-web/redis v0.5.2\n\tgithub.com/goal-web/routing v0.5.2\n\tgithub.com/goal-web/serialization v0.5.2\n\tgithub.com/goal-web/session v0.5.2\n\tgithub.com/goal-web/supports v0.5.7\n\tgithub.com/goal-web/validation v0.5.2\n\tgithub.com/goal-web/views v0.5.2\n\tgithub.com/golang-jwt/jwt v3.2.2+incompatible\n\tgithub.com/golang-module/carbon/v2 v2.3.12\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/gookit/goutil v0.6.18\n\tgithub.com/nsqio/go-nsq v1.1.0\n\tgithub.com/spf13/cast v1.7.1\n)\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.4.0 // indirect\n\tgithub.com/joho/godotenv v1.5.1 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nrequire (\n\tgithub.com/ClickHouse/clickhouse-go/v2 v2.0.9 // indirect\n\tgithub.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect\n\tgithub.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect\n\tgithub.com/andybalholm/brotli v1.1.0 // indirect\n\tgithub.com/apex/log v1.9.0 // indirect\n\tgithub.com/bits-and-blooms/bitset v1.2.1 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.2.0 // indirect\n\tgithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect\n\tgithub.com/emicklei/proto v1.13.2 // indirect\n\tgithub.com/flosch/pongo2/v6 v6.0.0 // indirect\n\tgithub.com/fsnotify/fsnotify v1.6.0 // indirect\n\tgithub.com/go-playground/locales v0.14.0 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.0 // indirect\n\tgithub.com/go-playground/validator/v10 v10.10.0 // indirect\n\tgithub.com/go-sql-driver/mysql v1.6.0 // indirect\n\tgithub.com/goal-web/container v0.5.3 // indirect\n\tgithub.com/goal-web/pipeline v0.5.2 // indirect\n\tgithub.com/goal-web/querybuilder v0.5.4 // indirect\n\tgithub.com/golang/snappy v0.0.4 // indirect\n\tgithub.com/gookit/color v1.5.4 // indirect\n\tgithub.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 // indirect\n\tgithub.com/jmoiron/sqlx v1.3.4 // indirect\n\tgithub.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect\n\tgithub.com/klauspost/compress v1.17.9 // indirect\n\tgithub.com/leodido/go-urn v1.2.1 // indirect\n\tgithub.com/lib/pq v1.10.4 // indirect\n\tgithub.com/mattn/go-sqlite3 v1.14.10 // indirect\n\tgithub.com/modood/table v0.0.0-20220527013332-8d47e76dad33 // indirect\n\tgithub.com/paulmach/orb v0.4.0 // indirect\n\tgithub.com/pierrec/lz4 v2.6.1+incompatible // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.14 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/qbhy/parallel v1.4.0 // indirect\n\tgithub.com/qiniu/go-sdk/v7 v7.11.1 // indirect\n\tgithub.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect\n\tgithub.com/segmentio/kafka-go v0.4.27 // indirect\n\tgithub.com/shopspring/decimal v1.4.0 // indirect\n\tgithub.com/valyala/bytebufferpool v1.0.0 // indirect\n\tgithub.com/valyala/fasthttp v1.55.0 // indirect\n\tgithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect\n\tgithub.com/yuin/gopher-lua v1.1.1 // indirect\n\tgo.opentelemetry.io/otel v1.3.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.3.0 // indirect\n\tgo.uber.org/ratelimit v0.2.0 // indirect\n\tgolang.org/x/crypto v0.24.0 // indirect\n\tgolang.org/x/net v0.26.0 // indirect\n\tgolang.org/x/sync v0.10.0 // indirect\n\tgolang.org/x/sys v0.28.0 // indirect\n\tgolang.org/x/text v0.21.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=\ngithub.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/ClickHouse/clickhouse-go v1.5.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.0.9 h1:JKtF6JlROrcdZRMoQUTv6fW8CBSL9FiBKylXXQx5YnY=\ngithub.com/ClickHouse/clickhouse-go/v2 v2.0.9/go.mod h1:FfiBHxYkESSf1DQxROQ1kOP2XtI4Fy8XDVPasZSkI+k=\ngithub.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=\ngithub.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=\ngithub.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=\ngithub.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0=\ngithub.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8=\ngithub.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=\ngithub.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=\ngithub.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=\ngithub.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=\ngithub.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=\ngithub.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=\ngithub.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=\ngithub.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=\ngithub.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=\ngithub.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=\ngithub.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=\ngithub.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=\ngithub.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=\ngithub.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=\ngithub.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=\ngithub.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=\ngithub.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=\ngithub.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=\ngithub.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=\ngithub.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4=\ngithub.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU=\ngithub.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU=\ngithub.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=\ngithub.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=\ngithub.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=\ngithub.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=\ngithub.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=\ngithub.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=\ngithub.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=\ngithub.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=\ngithub.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=\ngithub.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=\ngithub.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=\ngithub.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=\ngithub.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=\ngithub.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=\ngithub.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=\ngithub.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=\ngithub.com/goal-web/application v0.5.2 h1:bDatyicAwuz4kNCKg+T47kNOtfXETlaRGEcPyWcM2AE=\ngithub.com/goal-web/application v0.5.2/go.mod h1:JVFX9zGWI9uG2ur1jlH87pWSG3hbatWGDyEHYj3FkHo=\ngithub.com/goal-web/auth v0.5.3 h1:i2UdvuY79TAwIqDHLI5KhBXZLTDncGVHDWPoQCqt6Vk=\ngithub.com/goal-web/auth v0.5.3/go.mod h1:y4ytkPR47ZQFJx26l0kVkbw0YXhCnWPkPMe+wEMbwJ0=\ngithub.com/goal-web/bloomfilter v0.5.2 h1:r4bdTOM3lXeb7qgrZI9SYI6I1ehBrB9l+kuf88g71dE=\ngithub.com/goal-web/bloomfilter v0.5.2/go.mod h1:uczJ+qBurMla6+nGhuR/Ezk3X4aydRFCqismyJ7SGDo=\ngithub.com/goal-web/cache v0.5.2 h1:gmUVwfOzzNMe53bXb4sTnAjdbmip1/uHe6wSw3gI0/Y=\ngithub.com/goal-web/cache v0.5.2/go.mod h1:RdZd3TeiJnhGzwrWACZPeZjqbBHR5vHjgtix2KpNOwA=\ngithub.com/goal-web/collection v0.5.2 h1:lPZbHeV4juiAh/NWp5FkG8+Wjb4ouu7IoQN8SNhtvq0=\ngithub.com/goal-web/collection v0.5.2/go.mod h1:dwO/vxDW4hLKzkHtDNXdgdgDWV8D+MHVXHKYy/nEKfQ=\ngithub.com/goal-web/config v0.5.4 h1:2w9bkpnXEuKA8V/2x21fAewWidyLNoUZWUoL8lLmJGo=\ngithub.com/goal-web/config v0.5.4/go.mod h1:L7qzwZnE547rioTSlhxZ2WyEYeqkboAiDoRk1G/dY2s=\ngithub.com/goal-web/console v0.5.4 h1:G7GvqgbpGV+iMOStz5s5sX1Cj8N+JpU+Nn+t4VaBUfw=\ngithub.com/goal-web/console v0.5.4/go.mod h1:8/MEDbVCMm1my5IYDS/6yMGlDXCsg8gLsy39pzfmEvo=\ngithub.com/goal-web/container v0.5.3 h1:pSz+ARibpOKXbGKLN8Yw/LbKfLSq5MdOwp9xlWHDsQs=\ngithub.com/goal-web/container v0.5.3/go.mod h1:RbzqAvWBKywaljql2JY1uoYzx1XJLjlDf7SIYiKbVlw=\ngithub.com/goal-web/contracts v0.5.3 h1:/W8n1B/GoKtXWwElrVR5RbbVSKRPkGVuJsLoSkbNJaw=\ngithub.com/goal-web/contracts v0.5.3/go.mod h1:mDFF5dx3G3newdB4qvfOWMnwWkGxQuzbymiNSKcdlzM=\ngithub.com/goal-web/database v0.5.3 h1:BoJ3juFknn0H9CBzDKpjix7Q3ejQOa3snwKXbXJlcBY=\ngithub.com/goal-web/database v0.5.3/go.mod h1:2R/b0mjO2xNImP0/v3gT/FL2eOceY6cDHZgFiFYxrds=\ngithub.com/goal-web/email v0.5.2 h1:MjWr2o8gwHekmH0J0DYeKNozkcavKjmRtJfcOf9LcsI=\ngithub.com/goal-web/email v0.5.2/go.mod h1:sI8eznbLhejS7j7/ZZehBTXFYiB2gVqQP3+Zx/I7ST4=\ngithub.com/goal-web/encryption v0.5.2 h1:YkCiLOt0ZLPjZfPpCyvPDR+HJy9kfIYHYPRKY3k9R5s=\ngithub.com/goal-web/encryption v0.5.2/go.mod h1:lzshlcMozyd3K39GBoKQhmZmJkjveQ0bNCiuyEsuqsM=\ngithub.com/goal-web/events v0.5.2 h1:Z+uHCp/axjjcoeEIZMb3Ug0g7MY70FZ2/qMurdY3GEY=\ngithub.com/goal-web/events v0.5.2/go.mod h1:33AiZ3h+HgXv2tEmbjLGob9t89wwFOdLfYGcN6PkwsA=\ngithub.com/goal-web/filesystem v0.5.2 h1:yXJDaEq8c6pAyRYdCcLcPaIqdhJ4SWH9+bSgsOZ26XA=\ngithub.com/goal-web/filesystem v0.5.2/go.mod h1:3VaOj8fzMnCh2EY28xUGhphRBmxbzKnSoaHfdOJgqvQ=\ngithub.com/goal-web/hashing v0.5.2 h1:QN3LetMqiJsTWT6Lo52GPD0FBaJ3c8+D7bIOVBs5VjY=\ngithub.com/goal-web/hashing v0.5.2/go.mod h1:Ft7MTHZSzppWPbtF8JNhtU0XLv5i2NEwYVpuDWc3c+M=\ngithub.com/goal-web/http v0.5.11 h1:7AuCNQ85Gmg8RN3pYC6P5kojD+iQ6v7+695ycMgsQec=\ngithub.com/goal-web/http v0.5.11/go.mod h1:+3RXhErKxuutSmxuIUaL52/7WVg0oCc10hJcDcgPCzY=\ngithub.com/goal-web/migration v0.5.6 h1:xNPirTwGIbgmY4e3dfeUmeKoh8i6FxTpZ9QeQL5CupU=\ngithub.com/goal-web/migration v0.5.6/go.mod h1:iGbpVpwPHQJde/I8//09HcHkKUovB8qQJmxgEyzvnNA=\ngithub.com/goal-web/pipeline v0.5.2 h1:aEpGmulH5CzOXqnSAZr7J43D4yy3Wi8quAY6t5ejseg=\ngithub.com/goal-web/pipeline v0.5.2/go.mod h1:9JPnhTvotfXdcdhH98oMjQmvuPa9WKye0TI8xb+y8HY=\ngithub.com/goal-web/querybuilder v0.5.4 h1:e6VGrM6Em+n6femrwIqCjpvzZ/uh1BwsfZHWysctz/s=\ngithub.com/goal-web/querybuilder v0.5.4/go.mod h1:v8Z8nnrriyq70QX7W5zGgxhSoz98DB/cnmN+tJQNyn0=\ngithub.com/goal-web/queue v0.5.2 h1:o/7V1B/lyHR4aGR4nqZaRWMQs84aDWnpR5AXx8X68WE=\ngithub.com/goal-web/queue v0.5.2/go.mod h1:Jr9dXUcY34T4/5g1F1CLZFPT9d0o42wB58hNfYekgjs=\ngithub.com/goal-web/ratelimiter v0.5.2 h1:S1gDxpZdvmQsdlULVafoK5dqhG74bNZ2R0nhkqcdhgs=\ngithub.com/goal-web/ratelimiter v0.5.2/go.mod h1:8j/SxH51dJSg7n7GYkvoGaiRfOv9EW2VNfwLDzQLwTY=\ngithub.com/goal-web/redis v0.5.2 h1:lBz/avfsDkp1pnubaYW+wFGrWN6wm7j/edsUYOBPqdg=\ngithub.com/goal-web/redis v0.5.2/go.mod h1:UWlrR1lkdbweOCiKzTOAGMcvCdwTZG0dNwKYOcVu3BQ=\ngithub.com/goal-web/routing v0.5.2 h1:i86o3vmu45xPaYQNYpx3utPST4L9Cx5iou8QVfYqRZA=\ngithub.com/goal-web/routing v0.5.2/go.mod h1:rtLq7/7qHmOAgNNikEF0HdMeEHqn5Rvt4WjPLag1Rzg=\ngithub.com/goal-web/serialization v0.5.2 h1:SipUuA7AF65FprNF271x7Isr6Yg1H/z4vSkDuovtOVE=\ngithub.com/goal-web/serialization v0.5.2/go.mod h1:7D5zjCADeHBXxFU4olxYhYaNRX1B/IgBGtY1MyS/mcg=\ngithub.com/goal-web/session v0.5.2 h1:juOXuFW/dOIRsa8YqsLEnBQ+NlFXIos/NN6lHlTqs2Y=\ngithub.com/goal-web/session v0.5.2/go.mod h1:WR7c7K+vvX5CqPhIg5Qwdt7GYDpnunaSEOg0xUlJQaA=\ngithub.com/goal-web/supports v0.5.7 h1:j0c0ZY5IJyiozGyp9fq0hy6Qkh4AMCP/GRSwDEQaOzE=\ngithub.com/goal-web/supports v0.5.7/go.mod h1:TViRmtPhjFfQ1YqOKBfxej8vdFkYwbzWe2uvhgGO2Zg=\ngithub.com/goal-web/validation v0.5.2 h1:3ufzNB30gqa4TqcZhFH/I3JWVxsSKCVhjvJgxZ5MMKQ=\ngithub.com/goal-web/validation v0.5.2/go.mod h1:UvlpuogwjQqngAqVAkSxHSEoxqWINolaXM1RLjkopao=\ngithub.com/goal-web/views v0.5.2 h1:euAKBqEgumpiGcNVQms8ROsZrg2Tze69qYrTsTOn9R8=\ngithub.com/goal-web/views v0.5.2/go.mod h1:yCo/xoXkBFKd8hUvVWaTcFO2jpxMO6LqTn/j6pAaR+4=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=\ngithub.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=\ngithub.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k=\ngithub.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=\ngithub.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=\ngithub.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=\ngithub.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=\ngithub.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=\ngithub.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=\ngithub.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=\ngithub.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=\ngithub.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=\ngithub.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=\ngithub.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=\ngithub.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=\ngithub.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=\ngithub.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=\ngithub.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=\ngithub.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=\ngithub.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=\ngithub.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=\ngithub.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=\ngithub.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=\ngithub.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=\ngithub.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=\ngithub.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=\ngithub.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=\ngithub.com/modood/table v0.0.0-20220527013332-8d47e76dad33 h1:T5IbS9C1G2zeHb6eBy6OfIvj5tfQB23kGFpewCJuGDg=\ngithub.com/modood/table v0.0.0-20220527013332-8d47e76dad33/go.mod h1:41qyXVI5QH9/ObyPj27CGCVau5v/njfc3Gjj7yzr0HQ=\ngithub.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=\ngithub.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=\ngithub.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=\ngithub.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=\ngithub.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=\ngithub.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=\ngithub.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A=\ngithub.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU=\ngithub.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=\ngithub.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pierrec/lz4/v4 v4.1.13/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=\ngithub.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/qbhy/parallel v1.4.0 h1:RvdjXbxIRNMG2lA6gkaEOgVhr7JbNy4BljabsD+u9JI=\ngithub.com/qbhy/parallel v1.4.0/go.mod h1:gjKS0IACnz3SWXkeEOUvPPZZxpeQAOW47jT4cpWPvqU=\ngithub.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=\ngithub.com/qiniu/go-sdk/v7 v7.11.1 h1:/LZ9rvFS4p6SnszhGv11FNB1+n4OZvBCwFg7opH5Ovs=\ngithub.com/qiniu/go-sdk/v7 v7.11.1/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w=\ngithub.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=\ngithub.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=\ngithub.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=\ngithub.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=\ngithub.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjKhAM4=\ngithub.com/segmentio/kafka-go v0.4.27/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=\ngithub.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=\ngithub.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=\ngithub.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=\ngithub.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=\ngithub.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=\ngithub.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=\ngithub.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=\ngithub.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=\ngithub.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=\ngithub.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=\ngithub.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=\ngithub.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=\ngithub.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc=\ngithub.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=\ngithub.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=\ngithub.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=\ngithub.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=\ngithub.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=\ngithub.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=\ngithub.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=\ngithub.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=\ngithub.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=\ngithub.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=\ngithub.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=\ngithub.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=\ngo.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y=\ngo.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=\ngo.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY=\ngo.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=\ngo.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=\ngolang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=\ngolang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=\ngolang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=\ngolang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=\ngolang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=\ngolang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=\ngolang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=\ngolang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/controllers\"\n\t\"github.com/goal-web/goal/bootstrap/core\"\n\t\"github.com/goal-web/goal/routes\"\n\t\"github.com/goal-web/http\"\n\t\"github.com/goal-web/http/sse\"\n\t\"github.com/goal-web/http/websocket\"\n\t\"github.com/goal-web/session\"\n\t\"github.com/goal-web/supports/signal\"\n\t\"github.com/goal-web/views\"\n)\n\nfunc main() {\n\n\ta := \"a\"\n\tfmt.Println(a)\n\n\tapp := core.Application(core.App{\n\t\tQueueWorker:      true,\n\t\tSchedulingWorker: true,\n\t})\n\n\tapp.RegisterServices(\n\t\tviews.NewService(),\n\t\thttp.NewService(\n\t\t\troutes.Api,\n\t\t\troutes.WebSocket,\n\t\t\troutes.Sse,\n\t\t\tcontrollers.Register,\n\t\t),\n\t\tsession.NewService(),\n\t\tsse.NewService(),\n\t\twebsocket.NewService(),\n\t\tsignal.NewService(syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT),\n\t)\n\n\tapp.Call(func(console3 contracts.Console, input contracts.ConsoleInput) {\n\t\tconsole3.Run(input)\n\t})\n}\n"
  },
  {
    "path": "pro/Article.proto",
    "content": "syntax = \"proto3\";\n\n\n//@table: articles\n//@timestamps\nmessage ArticleModel {\n    uint32 id = 1;\n    string title = 2;\n    string created_at = 3;\n    string updated_at = 4;\n}\n"
  },
  {
    "path": "pro/Project.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"project\";\n\n//@timestamps\n//@table: projects\nmessage ProjectModel {\n  int64 id = 1;\n  string uuid = 2;\n  string name = 3;\n  int64 creator_id = 4;\n  int64 group_id = 5;\n  int64 key_id = 6;\n  string repo_address = 7;\n  string project_path = 8;\n  string default_branch = 9;\n  string settings = 10;\n  string created_at = 11;\n  string updated_at = 12;\n}\n\n\n//@controller:/project\nservice ProjectService {\n  rpc CreateProject(CreateProjectReq) returns (CreateProjectResult) {}\n  //@method:Get\n  rpc GetProject(GetProjectReq) returns (GetProjectResult) {}\n  //@method:Get\n  rpc ListProjects(ListProjectsReq) returns (ListProjectsResult) {}\n  rpc UpdateProject(UpdateProjectReq) returns (UpdateProjectResult) {}\n  rpc DeleteProject(DeleteProjectReq) returns (DeleteProjectResult) {}\n}\n\nmessage CreateProjectReq {\n  string uuid = 1;\n  string name = 2;\n  int64 creator_id = 3;\n  int64 group_id = 4;\n  int64 key_id = 5;\n  string repo_address = 6;\n  string project_path = 7;\n  string default_branch = 8;\n  string settings = 9;\n}\nmessage CreateProjectResult {\n  string code = 1;\n}\n\n\nmessage GetProjectReq {\n  string id = 1;\n}\nmessage GetProjectResult {\n  ProjectModel project = 1;\n}\n\n\n\nmessage ListProjectsReq {\n  int64 page = 1;\n  int64 per_page = 2;\n}\nmessage ListProjectsResult {\n  int64 total = 1;\n  //@ptr\n  repeated ProjectModel projects = 2;\n}\n\n\n\nmessage UpdateProjectReq {\n  int64 id = 1;\n  string uuid = 2;\n  string name = 3;\n  int64 creator_id = 4;\n  int64 group_id = 5;\n  int64 key_id = 6;\n  string repo_address = 7;\n  string project_path = 8;\n  string default_branch = 9;\n  string settings = 10;\n}\nmessage UpdateProjectResult {\n  string code = 1;\n}\n\n\nmessage DeleteProjectReq {\n  string id = 1;\n}\n\nmessage DeleteProjectResult {\n  string code = 1;\n}\n\n\n"
  },
  {
    "path": "pro/common.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \".\";\n\nenum Code {\n  //@msg:成功\n  Success = 0;\n\n  //@msg:参数解析失败\n  ParseReqErr = 10400;\n  //@msg:未登录\n  Unauthorized = 10401;\n  //@msg:没有权限\n  Forbidden = 100403;\n  //@msg:找不到\n  NotFound = 100404;\n  //@msg:业务错误\n  BizErr = 10201;\n}\n\nmessage ResponseResult {\n  int32 code = 1;\n  string err_message = 2;\n  string message = 3;\n  //@goType:any\n  string data = 4;\n}\n"
  },
  {
    "path": "pro/goal-cli.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/goal-web/goal-cli/app/gen\"\n)\n\nfunc main() {\n\t// 定义命令行参数\n\tout := flag.String(\"out\", \"app\", \"output\")                   // 输出目录\n\ttemplate := flag.String(\"template\", \"template.tmpl\", \"模板文件\") // 模板文件\n\tdir := flag.String(\"dir\", \"pro\", \"指定扫描的 proto 文件目录\")         // 要扫描的目录\n\tmode := flag.String(\"mode\", \"pro\", \"pro 或者 SDK\")\n\n\tflag.Parse()\n\n\t// 检查是否指定了 proto 文件目录\n\tif *dir == \"\" {\n\t\tfmt.Println(\"请指定要扫描的 proto 文件目录, 使用 --dir 参数\")\n\t\tos.Exit(1)\n\t}\n\n\t// 获取指定目录中的所有 proto 文件\n\tprotoFiles, err := scanProtoFiles(*dir)\n\tif err != nil {\n\t\tfmt.Printf(\"扫描目录 %s 中的 proto 文件失败: %v\\n\", *dir, err)\n\t\tos.Exit(1)\n\t}\n\n\tif *mode == \"pro\" {\n\t\t// 遍历所有找到的 proto 文件，依次调用 gen.Pro()\n\t\tfor _, protoFile := range protoFiles {\n\t\t\tfmt.Printf(\"正在处理 proto 文件: %s\\n\", protoFile)\n\t\t\tgen.Pro(protoFile, *template, *out)\n\t\t}\n\t} else {\n\t\t// 遍历所有找到的 proto 文件，依次调用 gen.Pro()\n\t\tgen.SDK(protoFiles, *template, *out)\n\t}\n}\n\n// scanProtoFiles 扫描指定目录，返回所有的 .proto 文件路径\nfunc scanProtoFiles(root string) ([]string, error) {\n\tvar protoFiles []string\n\n\t// 使用 filepath.Walk 遍历目录，查找所有 .proto 文件\n\terr := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// 如果是 .proto 文件，则加入到列表中\n\t\tif !info.IsDir() && filepath.Ext(path) == \".proto\" {\n\t\t\tprotoFiles = append(protoFiles, path)\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn protoFiles, nil\n}\n"
  },
  {
    "path": "pro/user.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"user\";\n\nmessage WechatInfoData {\n  string city = 1;\n  int64 gender = 2;\n  string open_id = 3;\n  string country = 4;\n  string language = 5;\n  string nickname = 6;\n  string province = 7;\n  string avatar_url = 8;\n}\n\n// 用户注释\n//@authenticatable\n//@table: users\n//@timestamps\nmessage UserModel {\n\n  int64 id = 1;\n  string name = 2;\n  string avatar = 3;\n\n  //@index\n  //@goTag:db:\"open_id;type:varchar(255);default 'xxasdasdsx'\"\n  string open_id = 4;\n\n  //@ptr\n  WechatInfoData wechat_info = 5;\n\n  string channel = 6;\n\n  //@hidden\n  string password = 9;\n\n  string created_at = 7;\n  string updated_at = 8;\n}\n\n// 通过微信小程序的 code 登录\nmessage LoginByWxCodeReq {\n  //@gotag:validate:\"required\"\n  string code = 1;\n}\n\n// 通过微信小程序的 code 登录\nmessage LoginByWxInfoReq {\n  //@gotag: validate:\"required\"\n  string iv = 1;\n  //@gotag: validate:\"required\"\n  string sessionKey = 2;\n  //@gotag: validate:\"required\"\n  string encryptedData = 3;\n}\n\nmessage LoginByWxResult {\n  //@gotag:json:\"token,omitempty\"\n  string token = 1;\n  //@ptr\n  //@gotag:json:\"user,omitempty\"\n  UserModel user = 2;\n  //@gotag:json:\"sessionKey,omitempty\"\n  string sessionKey = 3;\n}\n\n//@controller:/auth\nservice AuthService {\n\n  //@method:Post\n  //@middleware:guest\n  rpc LoginByWxAppCode(LoginByWxCodeReq) returns(LoginByWxResult);\n\n  //@middleware:guest\n  rpc LoginByWxAppInfo(LoginByWxInfoReq) returns(LoginByWxResult);\n}"
  },
  {
    "path": "routes/api.go",
    "content": "package routes\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/app/controllers\"\n)\n\nfunc Api(router contracts.HttpRouter) {\n\n\trouter.Get(\"/wrk/{name}\", func(request contracts.HttpRequest) any {\n\t\treturn request.Param(\"name\")\n\t})\n\n\trouter.Get(\"/\", controllers.HelloWorld)\n\trouter.Get(\"/view\", func(views contracts.Views) any {\n\t\treturn views.Render(\"view.html\")\n\t})\n}\n"
  },
  {
    "path": "routes/sse.go",
    "content": "package routes\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\tsse2 \"github.com/goal-web/goal/app/http/sse\"\n\t\"github.com/goal-web/http/sse\"\n)\n\nfunc Sse(router contracts.HttpRouter) {\n\t// 自定义 sse 控制器\n\trouter.Get(sse.New(\"/sse-demo\", sse2.DemoController{}))\n\n\t// 默认 sse 控制器\n\trouter.Get(sse.Default())\n\n\trouter.Get(\"/send-sse\", func(sse contracts.Sse, request contracts.HttpRequest) error {\n\t\treturn sse.Send(uint64(request.GetInt64(\"fd\")), request.GetString(\"msg\"))\n\t})\n\n\trouter.Get(\"/close-sse\", func(sse contracts.Sse, request contracts.HttpRequest) error {\n\t\treturn sse.Close(uint64(request.GetInt64(\"fd\")))\n\t})\n}\n"
  },
  {
    "path": "routes/ws.go",
    "content": "package routes\n\nimport (\n\t\"fmt\"\n\t\"github.com/goal-web/contracts\"\n\twebsocket2 \"github.com/goal-web/goal/app/websocket\"\n\t\"github.com/goal-web/http/websocket\"\n)\n\nfunc WebSocket(router contracts.HttpRouter) {\n\n\trouter.Get(\"/ws-demo\", websocket.New(websocket2.DemoController{}))\n\n\trouter.Get(\"/ws\", websocket.Default(func(frame contracts.WebSocketFrame) {\n\n\t\tfmt.Println(\"收到消息\", frame.RawString(), frame.Connection().Fd())\n\t\t_ = frame.Send(\"来自服务器的回复1\")\n\t\t_ = frame.SendBytes([]byte(\"来自服务器的回复2\"))\n\n\t}))\n\n}\n"
  },
  {
    "path": "sdk.tmpl",
    "content": "{{- define \"request\" -}}\n{{- range .Imports }}\nimport {{ .Alias }} from \"{{ .Pkg }}\"\n{{- end }}\n\nexport default interface {{ .Model.Name }} {\n  {{- range .Fields }}\n  {{ .JSONName }}{{ if hasComment .Comment \"@nullable\" }}?{{end}}: {{ tsType . }}\n  {{- end }}\n}\n{{ end }}\n\n{{- define \"model\" -}}\n{{- range .Imports }}\nimport {{ .Alias }} from \"{{ .Pkg }}\"\n{{- end }}\n\nexport default interface {{ .Model.Name }} {\n  {{- range .Fields }}\n  {{ .JSONName }}{{ if hasComment .Comment \"@nullable\" }}?{{end}}: {{ tsType . }}\n  {{- end }}\n}\n{{ end }}\n\n\n{{- define \"result\" -}}\n{{- range .Imports }}\nimport {{ .Alias }} from \"{{ .Pkg }}\"\n{{- end }}\n\nexport default interface {{ .Model.Name }} {\n  {{- range .Fields }}\n  {{ .JSONName }}{{ if hasComment .Comment \"@nullable\" }}?{{end}}: {{ tsType . }}\n  {{- end }}\n}\n{{ end }}\n\n{{- define \"enum\" -}}\n\n{{- $enumName := .Name }}\n\nexport enum {{ $enumName }} {\n  {{- range .Values }}\n  {{- $FieldName := sprintf \"%s%s\" $enumName .Name }}\n\n  {{ toComments $FieldName .Comments }}\n  {{ .Name }} = {{ .Value }},\n  {{- end }}\n}\n\n{{ end }}\n\n{{- define \"data\" -}}\n\n{{- range .Imports }}\nimport {{ .Alias }} from \"{{ .Pkg }}\"\n{{- end }}\n\nexport default interface {{ .Model.Name }} {\n  {{- range .Fields }}\n  {{ .JSONName }}{{ if hasComment .Comment \"@nullable\" }}?{{end}}: {{ tsType . }}\n  {{- end }}\n}\n{{ end }}\n\n{{- define \"controller\" -}}\nimport {alovaInstance, wrapParams} from \"../index\";\nimport {useRequest} from \"alova/client\";\nimport {RequestHookConfig} from \"alova/client\";\n{{- range .Imports }}\nimport {{ .Alias }} from \"{{ .Pkg }}\"\n{{- end }}\n\n{{- $serviceName := .Name }}\n{{- $prefix := .Prefix }}\n{{- $hasHook := hasComment .Comment \"@hook\" }}\n\n{{- range .Methods }}\n\n{{- $name := .Name }}\n{{- $req := .InputUsageName }}\n{{- $resp := .OutputUsageName }}\n{{- $path := .Path }}\n{{- $hook := or $hasHook (hasComment .Comment \"@hook\") }}\n\n{{- if eq (len .Method) 1 }}\n\nexport function {{ .Name }}(req: {{ .InputUsageName }}) {\n    return alovaInstance.{{ (index .Method 0) }}<{{ .OutputUsageName }}>(\"{{ $prefix }}{{ .Path }}\", wrapParams('{{ index .Method 0 }}', req))\n}\n\n{{- if $hook }}\nexport function use{{ .Name }}(req: {{ .InputUsageName }}, config?: RequestHookConfig<any, any>) {\n    return useRequest({{ .Name }}(req), config)\n}\n{{- end }}\n\n{{- else }}\n{{- range .Method }}\n\nexport function {{ . }}{{ $name }}(req: {{ $req }}) {\n    return alovaInstance.{{ . }}<{{ $resp }}>(\"{{ $prefix }}{{ $path }}\", wrapParams('{{ . }}', req))\n}\n\n{{- if $hook }}\nexport function use{{ . }}{{ $name }}(req: {{ .InputUsageName }}, config?: RequestHookConfig<any, any>) {\n    return useRequest({{ . }}{{ $name }}(req), config)\n}\n{{- end }}\n\n{{- end }}\n\n{{- end }}\n\n{{- end }}\n\n\n{{ end }}"
  },
  {
    "path": "server.conf",
    "content": "server {\n    listen 80;\n\n    server_name example.com;\n\n    location = /favicon.ico { access_log off; log_not_found off; }\n    location = /robots.txt  { access_log off; log_not_found off; }\n\n    location / {\n        proxy_pass http://localhost:8008;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    }\n}"
  },
  {
    "path": "storage/app/.gitignore",
    "content": "*\n!.gitignore\n!public"
  },
  {
    "path": "storage/framework/bloomfilter/.gitignore",
    "content": ".gitignore\n!.gitignore\n"
  },
  {
    "path": "storage/framework/cache/.gitignore",
    "content": ".gitignore\n!.gitignore\n"
  },
  {
    "path": "storage/framework/sessions/.gitignore",
    "content": ".gitignore\n!.gitignore\n"
  },
  {
    "path": "storage/logs/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "supervisor.conf",
    "content": "[program:goal-server]\ncommand=/opt/app/goal\nautostart=true\nautorestart=true\nuser=root\nnumprocs=1\nredirect_stderr=true\nstdout_logfile=/opt/app/storage/logs/goal.log\n"
  },
  {
    "path": "template.tmpl",
    "content": "{{- define \"model\" -}}\npackage {{ .Package }}\n\nimport (\n    \"encoding/json\"\n    \"github.com/goal-web/supports/logs\"\n    \"github.com/goal-web/contracts\"\n    \"github.com/goal-web/database/table\"\n\t\"github.com/goal-web/migration/migrate\"\n    \"github.com/goal-web/supports/utils\"\n    \"github.com/goal-web/collection\"\n\t\"github.com/spf13/cast\"\n    \"fmt\"\n    {{- if hasMsgComment .Model \"@carbon\" }}\n    \"github.com/golang-module/carbon/v2\"\n    {{- end }}\n    {{- range .Imports }}\n    {{ .Alias }} \"{{ .Pkg }}\"\n    {{- end }}\n)\n\n{{- $modelName := .Model.Name }}\n{{- $rawName := .Model.RawName }}\n{{- $tableName := .Model.TableName }}\n{{- $primaryKey := .Model.PrimaryKey }}\n\nvar (\n    {{- range .Relations }}\n    {{ $rawName }}{{ .Name }}Relation contracts.RelationType = \"{{ .JSONName }}\"\n    {{- end }}\n)\n\n{{ toComments .Model.Name .Model.Comments }}\ntype {{ $modelName }} struct {\n\n  {{- range .Fields }}\n  {{- if hasComment .Comment \"@belongsTo\" }}\n  {{- else }}\n  {{ .Comments }}\n  {{ .Name }} {{ goType . }} `{{ toTags . }}`\n  {{- end }}\n  {{- end }}\n\n  _raw contracts.Fields\n  _update contracts.Fields\n  _append contracts.Fields\n  _hidden map[string]struct{}\n\n  _relation_loaded map[contracts.RelationType]struct{}\n  {{- range .Relations }}\n    _{{ .Name }} {{ goType . }}\n  {{- end }}\n}\n\n{{- $define := join $rawName \"Define\" }}\nvar {{ $define }} {{ $rawName }}Static\n\ntype {{ $rawName }}Static struct {\n    TableName string\n\tHidden []string\n\tIndexes []string\n\tWith []contracts.RelationType\n\tAppends map[string]func(model *{{ $modelName }}) any\n\n  {{- range .Fields }}\n  {{ .Name }}Getter func(model *{{ $modelName }}, raw {{ goType . }}) {{ goType . }}\n  {{ .Name }}Setter func(model *{{ $modelName }}, raw {{ goType . }}) {{ goType . }}\n  {{- end }}\n\n  Saving   func(model *{{ $modelName }}) contracts.Exception\n  Saved    func(model *{{ $modelName }})\n  Updating func(model *{{ $modelName }}, fields contracts.Fields) contracts.Exception\n  Updated  func(model *{{ $modelName }}, fields contracts.Fields)\n  Deleting func(model *{{ $modelName }}) contracts.Exception\n  Deleted  func(model *{{ $modelName }})\n  PrimaryKeyGetter func(model *{{ $modelName }}) any\n}\n\nfunc {{ $rawName }}Migrator() migrate.Migrator {\n\treturn func(executor contracts.SqlExecutor) contracts.Exception {\n\t    return migrate.Migrate({{ $define }}.TableName, {{ $define }}.Indexes, {{ $modelName }}{}, executor)\n\t}\n}\n\nfunc init() {\n    {{ $define }}.TableName = \"{{ $tableName }}\"\n    {{ $define }}.Appends = make(map[string]func(model *{{ $modelName }}) any)\n    {{- if hasMsgComment .Model \"@hidden\" }}\n    {{ $define }}.Hidden = append(\n        {{ $define }}.Hidden,\n        {{- range .Fields }}\n            {{- if hasComment .Comment \"@hidden\" }}\n            \"{{ .JSONName }}\",\n            {{- end }}\n        {{- end }}\n     )\n    {{- end }}\n\n    {{- if hasMsgComment .Model \"@with\" }}\n    {{ $define }}.With = append(\n        {{ $define }}.With,\n        {{- range .Relations }}\n            {{- if hasComment .Comment \"@with\" }}\n             {{ $rawName }}{{ .Name }}Relation,\n            {{- end }}\n        {{- end }}\n     )\n    {{- end }}\n\n    {{- if hasMsgComment .Model \"@index\" }}\n    {{ $define }}.Indexes = append(\n        {{ $define }}.Indexes,\n        {{- range .Fields }}\n            {{- if hasComment .Comment \"@index\" }}\n             \"index;{{ getIndexComment .Comment \"@index\" 0 (join .JSONName \"_idx\") }};{{ replace (getIndexComment .Comment \"@index\" 1 (join \"(\" .JSONName \")\")) \";\" \",\" }}\",\n            {{- end }}\n        {{- end }}\n     )\n    {{- end }}\n\n    {{- if hasMsgComment .Model \"@unique\" }}\n    {{ $define }}.Indexes = append(\n        {{ $define }}.Indexes,\n        {{- range .Fields }}\n            {{- if hasComment .Comment \"@unique\" }}\n             \"unique index;{{ getIndexComment .Comment \"@unique\" 0 (join .JSONName \"_idx\") }};{{ replace (getIndexComment .Comment \"@unique\" 1 (join \"(\" .JSONName \")\")) \";\" \",\" }}\",\n            {{- end }}\n        {{- end }}\n     )\n    {{- end }}\n}\n\nfunc New{{ $modelName }}(fields contracts.Fields) *{{ $modelName }} {\n  var model = {{ $modelName }}{\n    _raw: fields,\n  }\n  model.Set(fields)\n  return &model\n}\n\nfunc {{ $modelName }}SingleRelationSetter[T any](key contracts.RelationType) func(item *{{ $modelName }}, value []any) {\n    return func(item *{{ $modelName }}, values []any) {\n        var value T\n        if len(values) > 0 {\n            value = values[0].(T)\n        }\n        item.Set(contracts.Fields{\n            string(key): value,\n        })\n    }\n}\nfunc {{ $modelName }}MultiRelationSetter[T any](key contracts.RelationType) func(item *{{ $modelName }}, value []any) {\n    return func(model *{{ $modelName }}, value []any) {\n        var results []T\n        for _, item := range value {\n            results = append(results, item.(T))\n        }\n        model.Set(contracts.Fields{ string(key): results })\n    }\n}\n\nfunc {{ $modelName }}LocalKeyGetter(key string) func(item *{{ $modelName }}) any {\n    return func(item *{{ $modelName }}) any {\n        return item.Get(key)\n    }\n}\n\nfunc {{ $modelName }}RelationGetter[T any](query func() *table.Table[T], foreignKey string) func(keys []any) map[string][]any {\n    return func(keys []any) map[string][]any {\n        var results = map[string][]any{}\n        for key, values := range query().WhereIn(foreignKey, keys).Get().GroupBy(foreignKey) {\n            results[key] = collection.New(values).ToAnyArray()\n        }\n        return results\n    }\n}\n\nfunc {{ $modelName }}ThroughRelationGetter[T any](query func() *table.Table[T], midTable, firstKey, secondKey, secondLocalKey string) func(keys []any) map[string][]any {\n    return func(keys []any) map[string][]any {\n        var results = map[string][]any{}\n        groupKey := fmt.Sprintf(\"%s.%s\", midTable, firstKey)\n        for key, values := range query().\n            AddSelect(fmt.Sprintf(\"(%s) as _group_key\", groupKey)).\n            WhereIn(groupKey, keys).\n            Join(midTable, fmt.Sprintf(\"%s.%s\", midTable, secondLocalKey), \"=\", fmt.Sprintf(\"%s.%s\", query().GetTableName(), secondKey)).\n            Get().GroupBy(\"_group_key\") {\n            results[key] = collection.New(values).ToAnyArray()\n        }\n        return results\n    }\n }\n\n{{- $queryName := replace .Model.Name \"Model\" \"Query\" }}\nfunc {{ $queryName }}WithExecutor(executor contracts.SqlExecutor) *table.Table[{{ $modelName }}] {\n    return {{ $queryName }}().SetExecutor(executor)\n}\n\nfunc {{ $queryName }}() *table.Table[{{ $modelName }}] {\n  return table.NewQuery({{ $define }}.TableName, New{{ $modelName }}).\n    SetPrimaryKey(\"{{ $primaryKey }}\").\n    {{- if hasMsgComment .Model \"@timestamps\" }}\n    SetCreatedTimeColumn(\"{{ getIndexComment .Model.Comment \"@timestamps\" 0 \"created_at\" }}\").\n    SetUpdatedTimeColumn(\"{{ getIndexComment .Model.Comment \"@timestamps\" 1 \"updated_at\" }}\").\n    {{- end }}\n    {{- range $index, $item := .Relations }}\n        {{- $relationType := join $rawName  .Name \"Relation\" }}\n        {{- $relationItemType := substring (goType .) 1 }}\n        {{- $relationQuery := replace $relationItemType \"Model\" \"Query\"}}\n\n        {{- if .Repeated }}\n        {{- $relationItemType = substring (goType .) 2 }}\n        {{- $relationQuery = substring $relationQuery 2 }}\n        {{- end }}\n\n\n        {{- if hasComment .Comment \"@belongsTo\" }}\n            {{- $ownerKey := getIndexComment .Comment \"@belongsTo\" 0 \"id\" }}\n            {{- $localKey := getIndexComment .Comment \"@belongsTo\" 1 (join .JSONName \"_id\") }}\n            SetRelation( // belongsTo: {{ .Name }}\n            {{ $rawName }}{{ .Name }}Relation,\n                        {{ $modelName }}LocalKeyGetter(\"{{ $localKey }}\"),\n                        {{ $modelName }}RelationGetter({{ $relationQuery }}, \"{{ $ownerKey }}\"),\n                        {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}),\n            ).\n        {{- else if hasComment .Comment \"@hasOneThrough\" }}\n\n         {{- $midTable := getIndexComment .Comment \"@hasOneThrough\" 0 \"mid_table\" }}\n         {{- $firstKey := getIndexComment .Comment \"@hasOneThrough\" 1 (join (toLower $rawName) \"_id\") }}\n         {{- $secondKey := getIndexComment .Comment \"@hasOneThrough\" 2 \"id\" }}\n         {{- $localKey := getIndexComment .Comment \"@hasOneThrough\" 3 \"id\" }}\n         {{- $secondLocalKey := getIndexComment .Comment \"@hasOneThrough\" 4 (join $midTable \"_id\") }}\n\n                    SetRelation( // hasOneThrough: {{ .Name }}\n                    {{ $rawName }}{{ .Name }}Relation,\n                        {{ $modelName }}LocalKeyGetter(\"{{ $localKey }}\"),\n                        {{ $modelName }}ThroughRelationGetter({{ $relationQuery }}, \"{{ $midTable }}\", \"{{ $firstKey }}\", \"{{ $secondKey }}\", \"{{ $secondLocalKey }}\"),\n                        {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}),\n                    ).\n        {{- else if hasComment .Comment \"@hasOne\" }}\n         {{- $localKey := getIndexComment .Comment \"@hasOne\" 0 \"id\" }}\n         {{- $foreignKey := getIndexComment .Comment \"@hasOne\" 1 (join (toLower $rawName) \"_id\") }}\n                    SetRelation( // hasOne: {{ .Name }}\n                    {{ $rawName }}{{ .Name }}Relation,\n                        {{ $modelName }}LocalKeyGetter(\"{{ $localKey }}\"),\n                        {{ $modelName }}RelationGetter({{ $relationQuery }}, \"{{ $foreignKey }}\"),\n                        {{ $modelName }}SingleRelationSetter[*{{ $relationItemType }}]({{ $relationType }}),\n                    ).\n        {{- else if or (hasComment .Comment \"@hasManyThrough\") (hasComment .Comment \"@belongsToMany\") }}\n\n            {{- $relationName := \"hasManyThrough\" }}\n            {{- if (hasComment .Comment \"@belongsToMany\") }}\n            {{- $relationName = \"belongsToMany\" }}\n            {{- end }}\n\n         {{- $midTable := getIndexComment .Comment (join \"@\" $relationName) 0 \"mid_table\" }}\n         {{- $firstKey := getIndexComment .Comment (join \"@\" $relationName) 1 (join (toLower $rawName) \"_id\") }}\n         {{- $secondKey := getIndexComment .Comment (join \"@\" $relationName) 2 \"id\" }}\n         {{- $localKey := getIndexComment .Comment (join \"@\" $relationName) 3 \"id\" }}\n         {{- $secondLocalKey := getIndexComment .Comment (join \"@\" $relationName) 4 (join $midTable \"_id\") }}\n\n                    SetRelation( // {{- $relationName }}: {{ .Name }}\n                    {{ $rawName }}{{ .Name }}Relation,\n                        {{ $modelName }}LocalKeyGetter(\"{{ $localKey }}\"),\n                        {{ $modelName }}ThroughRelationGetter({{ $relationQuery }}, \"{{ $midTable }}\", \"{{ $firstKey }}\", \"{{ $secondKey }}\", \"{{ $secondLocalKey }}\"),\n                        {{ $modelName }}MultiRelationSetter[{{ $relationItemType }}]({{ $relationType }}),\n                    ).\n        {{- else if hasComment .Comment \"@hasMany\" }}\n         {{- $relationItemType := substring (goType .) 2 }}\n         {{- $relationQuery := replace (substring (goType .) 3) \"Model\" \"Query\"}}\n         {{- $foreignKey := getIndexComment .Comment \"@hasMany\" 0 (join (toLower $rawName) \"_id\") }}\n         {{- $localKey := getIndexComment .Comment \"@hasMany\" 1 \"id\" }}\n                    SetRelation( // hasMany: {{ .Name }}\n                    {{ $rawName }}{{ .Name }}Relation,\n                        {{ $modelName }}LocalKeyGetter(\"{{ $localKey }}\"),\n                        {{ $modelName }}RelationGetter({{ $relationQuery }}, \"{{ $foreignKey }}\"),\n                        {{ $modelName }}MultiRelationSetter[{{ $relationItemType }}]({{ $relationType }}),\n                    ).\n        {{- end }}\n\n    {{- end }}\n     SetWiths({{ $define }}.With...)\n}\n\nfunc (model *{{ $modelName }}) Hidden(fields ...string) *{{ $modelName }} {\n    for _, field := range fields {\n        if model._hidden == nil {\n            model._hidden = map[string]struct{}{\n                field: struct{}{},\n            }\n        } else {\n            model._hidden[field] = struct{}{}\n        }\n\n    }\n\n    return model\n}\n\nfunc (model *{{ $modelName }}) Exists() bool {\n  return {{ .Model.RawName }}Query().Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).Count() > 0\n}\n\nfunc (model *{{ $modelName }}) Save() contracts.Exception {\n  if model._update == nil {\n    return nil\n  }\n  if {{ $define }}.Saving != nil {\n    if err := {{ $define }}.Saving(model); err != nil {\n      return err\n    }\n  }\nvar err contracts.Exception\nvar pk = model. GetPrimaryKey()\nif cast.ToUint64(pk) == 0 {\n    pk, err = {{ .Model.RawName }}Query().Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).InsertGetIdE(model._update)\n    if err == nil {\n        {{- range .Fields }}\n        {{- if eq .JSONName $primaryKey }}\n        model.Set{{.Name}}(cast.{{ convertFunc (goType .) }}(pk))\n        {{- end }}\n        {{- end }}\n    }\n} else {\n  _, err = {{ .Model.RawName }}Query().Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).UpdateE(model._update)\n}\n  if err == nil {\n    model._update = nil\n    if {{ $define }}.Saved != nil {\n      {{ $define }}.Saved(model)\n    }\n  }\n\n  return err\n}\n\nfunc (model *{{ $modelName }}) Set(fields contracts.Fields) {\n  for key, value := range fields {\n\n    switch key {\n  {{- range .Fields }}\n      case \"{{ .JSONName }}\":\n        switch v := value.(type) {\n                case {{ goType . }}:\n                  model.Set{{ .Name }}(v)\n                case func() {{ goType . }}:\n                  model.Set{{ .Name }}(v())\n                  {{- $type := goType . }}\n                  {{- if ne $type \"string\"}}\n                case string:\n                  {{- if eq $type \"[]byte\" }}\n                  model.Set{{ .Name }}([]byte(v))\n                  {{else}}\n                  var vd {{ goType . }}\n                  err := json.Unmarshal([]byte(v), &vd)\n                  if err != nil {\n                      logs.Default().Warn(\"Failed to Parse field \"+key)\n                      continue\n                  }\n                  model.Set{{ .Name }}(vd)\n                  {{end}}\n                  {{end}}\n                  {{- if ne $type \"[]byte\"}}\n                case []byte:\n                  {{- if eq $type \"string\" }}\n                  model.Set{{ .Name }}(string(v))\n                  {{else}}\n                  var vd {{ goType . }}\n                  err := json.Unmarshal(v, &vd)\n                  if err != nil {\n                      logs.Default().Warn(\"Failed to Parse field \"+key)\n                      continue\n                  }\n                  model.Set{{ .Name }}(vd)\n                  {{end}}\n                  {{end}}\n                {{- if isBasicType . }}\n                default:\n                    model.Set{{ .Name }}(cast.{{ convertFunc (goType .) }}(v))\n                {{- end }}\n                }\n    {{- end }}\n    {{- range .Relations }}\n    {{- $relationType := join $rawName  .Name \"Relation\" }}\n    case string({{ $relationType }}):\n        model.Set{{ .Name }}(value.({{ goType . }}))\n    {{- end }}\n    }\n\n  }\n}\n\nfunc (model *{{ $modelName }}) Only(key ...string) contracts.Fields {\n  var fields = make(contracts.Fields)\n  for _, k := range key {\n  {{- range .Fields }}\n    if k == \"{{ .JSONName }}\" {\n      fields[k] = model.Get{{ .Name }}()\n      continue\n    }\n  {{- end }}\n\n    if {{ $define }}.Appends[k] != nil {\n     fields[k] = {{ $define }}.Appends[k](model)\n    }\n  }\n  return fields\n}\n\nfunc (model *{{ $modelName }}) Get(key string) any {\n    switch key {\n        {{- range $index, $item := .Fields }}\n            case \"{{ .JSONName }}\":\n              return model.Get{{ .Name }}()\n        {{- end }}\n    }\n\n    if value, exists := model._append[key]; exists {\n      return value\n    }\n\n    if fn, exists := {{ $define }}.Appends[key]; exists {\n        model._append[key] = fn(model)\n      return model._append[key]\n    }\n\n     switch contracts.RelationType(key) {\n            {{- range $index, $item := .Relations }}\n            {{- $relationType := join $rawName  .Name \"Relation\" }}\n                case {{ $relationType }}:\n                  return model.{{ .Name }}()\n            {{- end }}\n        }\n\n  return nil\n}\n\nfunc (model *{{ $modelName }}) Except(keys ...string) contracts.Fields {\n  var excepts = map[string]struct{}{}\n  for _, k := range keys {\n    excepts[k] = struct{}{}\n  }\n  var fields = make(contracts.Fields)\n  for key, value := range model.ToFields() {\n    if _, ok := excepts[key]; ok {\n      continue\n    }\n    fields[key] = value\n  }\n  return fields\n}\n\nfunc (model *{{ $modelName }}) ToFields() contracts.Fields {\n    if model == nil {\n        return nil\n    }\n\n  model.Hidden({{ $define }}.Hidden...)\n\n  fields := contracts.Fields{}\n\n    {{- range .Fields }}\n    if _,exists := model._hidden[\"{{ .JSONName }}\"]; !exists {\n        fields[\"{{ .JSONName }}\"] = model.Get{{ .Name }}()\n    }\n    {{- end }}\n\n  for key := range {{ $define }}.Appends {\n    value := model.Get(key)\n    if fieldsProvider, ok := value.(contracts.FieldsProvider); ok {\n        fields[key] = fieldsProvider.ToFields()\n    } else {\n        fields[key] = value\n    }\n  }\n\n  for key := range model._relation_loaded {\n    switch key {\n    {{- range .Relations }}\n    {{- $relationType := join $rawName  .Name \"Relation\" }}\n    case {{ $relationType }}:\n        {{- if .Repeated }}\n        var results []contracts.Fields\n        for _, item := range model._{{ .Name }} {\n            results = append(results, item.ToFields())\n        }\n        fields[string(key)] = results\n        {{- else }}\n        fields[string(key)] = model._{{ .Name }}.ToFields()\n        {{- end }}\n    {{- end }}\n    }\n  }\n\n  for key, value := range model._raw {\n    _, hidden := model._hidden[key]\n    if _, exists := fields[key]; !exists && !hidden {\n        fields[key] = value\n    }\n  }\n\n  return fields\n}\n\nfunc (model *{{ $modelName }}) Update(fields contracts.Fields) contracts.Exception {\n\n  if {{ $define }}.Updating != nil {\n    if err := {{ $define }}.Updating(model, fields); err != nil {\n      return err\n    }\n  }\n\n  if model._update != nil {\n    utils.MergeFields(model._update, fields)\n  }\n\n\n  _, err := {{ .Model.RawName }}Query().Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).UpdateE(fields)\n\n  if err == nil {\n    model.Set(fields)\n    model._update = nil\n    if {{ $define }}.Updated != nil {\n      {{ $define }}.Updated(model, fields)\n    }\n  }\n\n  return err\n}\n\nfunc (model *{{ $modelName }}) Refresh() contracts.Exception {\n  fields, err := table.ArrayQuery(\"{{ $tableName }}\").Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).FirstE()\n  if err != nil {\n    return err\n  }\n\n  model.Set(*fields)\n  return nil\n}\n\nfunc (model *{{ $modelName }}) Delete() contracts.Exception {\n\n  if {{ $define }}.Deleting != nil {\n    if err := {{ $define }}.Deleting(model); err != nil {\n      return err\n    }\n  }\n\n  _, err := {{ .Model.RawName }}Query().Where(\"{{ $primaryKey }}\", model.GetPrimaryKey()).DeleteE()\n  if err == nil && {{ $define }}.Deleted != nil {\n    {{ $define }}.Deleted(model)\n  }\n\n  return err\n}\n\n\nfunc (model *{{ $modelName }}) GetPrimaryKey() any {\n  if {{ $define }}.PrimaryKeyGetter != nil {\n    return {{ $define }}.PrimaryKeyGetter(model)\n  }\n\n  return model.{{ toCamelCase $primaryKey }}\n}\n\n{{- if .Model.Authenticatable }}\nfunc (model *{{ $modelName }}) GetAuthenticatableKey() string {\n  return fmt.Sprintf(\"%v\", model.GetPrimaryKey())\n}\n\nfunc {{ .Model.RawName }}AuthProvider(identify string) contracts.Authenticatable {\n  return {{ .Model.RawName }}Query().Find(identify)\n}\n\n{{- end }}\n\n\n{{- range .Fields }}\n\nfunc (model *{{ $modelName }}) Get{{ .Name }}() {{ goType . }} {\n  if {{ $define }}.{{ .Name }}Getter != nil {\n    return {{ $define }}.{{ .Name }}Getter(model, model.{{ .Name }})\n  }\n  return model.{{ .Name }}\n}\n\nfunc (model *{{ $modelName }}) Set{{ .Name }}(value {{ goType . }}) {\n  if {{ $define }}.{{ .Name }}Setter != nil {\n    value = {{ $define }}.{{ .Name }}Setter(model, value)\n  }\n\n  if model._update == nil {\n    model._update = contracts.Fields{\"{{ .JSONName }}\": value}\n  } else {\n    model._update[\"{{ .JSONName }}\"] = value\n  }\n  model.{{ .Name }} = value\n}\n\n{{- if hasComment .Comment \"@carbon\" }}\nfunc (model *{{ $modelName }}) Get{{ .Name }}Carbon() carbon.Carbon {\n  return carbon.Parse(model.Get{{ .Name }}())\n}\n{{- end }}\n\n\n{{- end }}\n\n{{- range .Relations }}\n{{- $relationType := join $rawName  .Name \"Relation\" }}\n{{- $relationItemType := substring (goType .) 1 }}\n{{- $relationQueryType := substring (goType .) 1 }}\n{{- $throughName := \"\" }}\n\n{{- if .Repeated }}\n{{- $relationItemType = substring (goType .) 3 }}\n{{- $relationQueryType = substring (goType .) 3 }}\n{{- end }}\n\n\n{{- $relationQuery := replace $relationItemType \"Model\" \"Query\" }}\n{{- $foreignKey := \"\" }}\n{{- $localKey := \"\" }}\n{{- $localQuery := join .Name \"Query\" }}\n\n{{- if (hasComment .Comment \"@belongsTo\") }}\n{{- $throughName = \"@belongsTo\" }}\n{{- $foreignKey = getIndexComment .Comment \"@belongsTo\" 0 \"id\" }}\n{{ $localKey = getIndexComment .Comment \"@belongsTo\" 1 (join .JSONName \"_id\") }}\n\n{{- else if (hasComment .Comment \"@hasOne\") }}\n{{- $throughName = \"@hasOne\" }}\n\n{{- $localKey = getIndexComment .Comment \"@hasOne\" 0 \"id\" }}\n{{- $foreignKey = getIndexComment .Comment \"@hasOne\" 1 (join (toLower $rawName) \"_id\") }}\n\n{{- else if (hasComment .Comment \"@hasMany\") }}\n{{- $throughName = \"@hasMany\" }}\n\n{{- $relationQuery = replace $relationItemType \"Model\" \"Query\" }}\n{{- $foreignKey = getIndexComment .Comment \"@hasMany\" 0 (join .JSONName \"_id\") }}\n{{- $localKey = getIndexComment .Comment \"@hasMany\" 1 \"id\" }}\n{{- $relationQueryType = $relationItemType }}\n\n{{- end }}\n\n{{- if .Repeated }}\n// {{ $localQuery }} {{ $throughName }}\nfunc (model *{{ $modelName }}) {{ .Name }}() {{ goType . }} {\n    _, exists := model._relation_loaded[{{ $relationType }}]\n    if !exists {\n        value := model.{{ $localQuery }}().Get().ToArray()\n        model.Set{{ .Name }}(value)\n        return value\n    }\n    return model._{{ .Name }}\n}\n\n{{- else }}\n// {{ $localQuery }} {{ $throughName }}\nfunc (model *{{ $modelName }}) {{ .Name }}() {{ goType . }} {\n    _, exists := model._relation_loaded[{{ $relationType }}]\n    if !exists {\n        value := model.{{ $localQuery }}().First()\n        model.Set{{ .Name }}(value)\n        return value\n    }\n    return model._{{ .Name }}\n}\n{{- end }}\n\n\n{{- if or (hasComment .Comment \"@hasManyThrough\") (hasComment .Comment \"@belongsToMany\") (hasComment .Comment \"@hasOneThrough\")  }}\n\n{{- $throughName := \"@hasManyThrough\" }}\n\n{{- if (hasComment .Comment \"@belongsToMany\") }}\n{{- $throughName = \"@belongsToMany\" }}\n{{- else if (hasComment .Comment \"@hasOneThrough\") }}\n{{- $throughName = \"@hasOneThrough\" }}\n{{- end }}\n\n\n{{- $midTable := getIndexComment .Comment $throughName 0 \"mid_table\" }}\n{{- $firstKey := getIndexComment .Comment $throughName 1 (join (toLower $rawName) \"_id\") }}\n{{- $secondKey := getIndexComment .Comment $throughName 2 \"id\" }}\n{{- $localKey := getIndexComment .Comment $throughName 3 \"id\" }}\n{{- $secondLocalKey := getIndexComment .Comment $throughName 4 (join $midTable \"_id\") }}\n// {{ $localQuery }} {{ $throughName }}\nfunc (model *{{ $modelName }}) {{ $localQuery }}() contracts.QueryBuilder[{{ $relationQueryType }}] {\n    query := {{ $relationQuery }}()\n    return query.\n        Where(\"{{ $midTable }}.{{ $firstKey }}\", model.Get(\"{{ $localKey }}\")).\n        Join(\"{{ $midTable }}\", \"{{ $midTable }}.{{ $secondLocalKey }}\",  \"=\", fmt.Sprintf(\"%s.{{ $secondKey }}\", query.GetTableName()))\n}\n\n{{- else }}\n// {{ $localQuery }} {{ $throughName }}\nfunc (model *{{ $modelName }}) {{ $localQuery }}() contracts.QueryBuilder[{{ $relationQueryType }}] {\n    return {{ $relationQuery }}().Where(\"{{ $foreignKey }}\", model.Get(\"{{ $localKey }}\"))\n}\n{{- end }}\n\n// {{ $localQuery }} {{ $throughName }}\nfunc (model *{{ $modelName }}) Set{{ .Name }}(value {{ goType . }}) {\n    if model._relation_loaded == nil {\n        model._relation_loaded = make(map[contracts.RelationType]struct{})\n    }\n    model._relation_loaded[{{ $relationType }}] = struct{}{}\n    model._{{ .Name }} = value\n}\n\n{{- end }}\n\n{{ end }}\n\n\n{{- define \"data\" -}}\npackage {{ .Package }}\n\nimport (\n{{- range .Imports }}\n{{ .Alias }} \"{{ .Pkg }}\"\n{{- end }}\n)\n\ntype {{ .Model.Name }} struct {\n  {{- range .Fields }}\n  {{ .Name }} {{ goType . }} `{{ toTags . }}`\n  {{- end }}\n}\n\n{{ end }}\n\n{{- define \"request\" -}}\npackage {{ .Package }}\n\nimport (\n  {{- range .Imports }}\n  {{ .Alias }} \"{{ .Pkg }}\"\n  {{- end }}\n  \"github.com/goal-web/contracts\"\n)\n\ntype {{ .Model.Name }} struct {\n  {{- range .Fields }}\n  {{ .Name }} {{ goType . }} `{{ toTags . }}`\n  {{- end }}\n}\n\nfunc (model *{{ .Model.Name }}) ToFields() contracts.Fields {\n  if model == nil {\n    return nil\n  }\n  fields := contracts.Fields{\n  {{- range .Fields }}\n    \"{{ .JSONName }}\": model.{{ .Name }},\n  {{- end }}\n  }\n  return fields\n}\n\n{{ end }}\n\n{{- define \"result\" -}}\npackage {{ .Package }}\n\nimport (\n    \"github.com/goal-web/contracts\"\n  {{- range .Imports }}\n  {{ .Alias }} \"{{ .Pkg }}\"\n  {{- end }}\n)\n\n{{- $resultName := .Model.Name }}\n\ntype {{ $resultName }} struct {\n  {{- range .Fields }}\n  {{ .Name }} {{ goType . }} `{{ toTags . }}`\n  {{- end }}\n}\n\nfunc (result *{{ $resultName }}) ToFields() contracts.Fields {\n\n    fields := contracts.Fields{\n        {{- range .Fields }}\n            {{- if eq (fieldMsg .) nil }}\n            \"{{ .JSONName }}\": result.{{ .Name }},\n            {{- else if and (ne .Repeated true) .IsModel }}\n            \"{{ .JSONName }}\": result.{{ .Name }}.ToFields(),\n            {{- else }}\n            \"{{ .JSONName }}\": result.{{ .Name }},\n            {{- end }}\n        {{- end }}\n    }\n\n    {{- range .Fields }}\n        {{- if and .Repeated (ne (fieldMsg .) nil) (fieldMsg .).IsModel }}\n        {{ .JSONName }}List := make([]contracts.Fields, len(result.{{ .Name }}))\n        for i, item := range result.{{ .Name }} {\n            {{ .JSONName }}List[i] = item.ToFields()\n        }\n        fields[\"{{ .JSONName }}\"] = {{ .JSONName }}List\n        {{- end }}\n    {{- end }}\n\n\n    return fields\n}\n\n{{ end }}\n\n{{- define \"enum\" -}}\npackage {{ .Package }}\n\n{{- $enumName := .Name }}\ntype {{ .Name }} int\nconst (\n  {{- range .Values }}\n  {{- $FieldName := sprintf \"%s%s\" $enumName .Name }}\n\n  {{ toComments $FieldName .Comments }}\n  {{ $enumName }}{{ .Name }} {{ $enumName }} = {{ .Value }}\n  {{- end }}\n  {{ $enumName }}Unknown {{ $enumName }} = -1000\n\n)\n\n\nfunc (item {{ $enumName }}) String() string {\n    switch item {\n      {{- range .Values }}\n        case {{ $enumName }}{{ .Name }}:\n          return \"{{ .Name }}\"\n      {{- end }}\n        default:\n          return \"Unknown\"\n  }\n}\n\nfunc (item {{ $enumName }}) Message() string {\n    switch item {\n      {{- range .Values }}\n        case {{ $enumName }}{{ .Name }}:\n          return \"{{ .Message }}\"\n      {{- end }}\n        default:\n          return \"Unknown\"\n  }\n}\n\nfunc Parse{{ $enumName }}FromString(msg string) {{ $enumName }} {\n    switch msg {\n    {{- range .Values }}\n        case \"{{ .Name }}\":\n          return {{ $enumName }}{{ .Name }}\n    {{- end }}\n        default:\n          return {{ $enumName }}Unknown\n  }\n}\n\n\n{{ end }}\n\n\n\n{{- define \"service\" -}}\npackage {{ .Package }}\n\nimport (\n    \"github.com/goal-web/contracts\"\n  {{- range .Imports }}\n  {{ .Alias }} \"{{ .Pkg }}\"\n  {{- end }}\n)\n\n{{- $serviceName := .Name }}\n{{- $define := join .Name \"Define\" }}\n\nvar {{ $define }} {{ $serviceName }}Static\ntype  {{ $serviceName }}Static struct {\n{{- range .Methods }}\n    {{ .Name }} func (req *{{ .InputUsageName }}, ctx contracts.Context) (*{{ .OutputUsageName }}, error)\n{{- end }}\n}\n\n{{- range .Methods }}\n\nfunc {{ $serviceName }}{{ .Name }}(req *{{ .InputUsageName }}, ctx contracts.Context) (*{{ .OutputUsageName }}, error) {\n  if {{ $define }}.{{ .Name }} != nil {\n    return {{ $define }}.{{ .Name }}(req, ctx)\n  }\n  return nil, nil\n}\n{{- end }}\n{{ end }}\n\n\n{{- define \"controller\" -}}\npackage {{ .Package }}\n\nimport (\n  \"github.com/goal-web/contracts\"\n  \"github.com/goal-web/validation\"\n  \"{{ .ResponsePath }}\"\n  svc \"{{ .ImportPath }}\"\n  {{- range .Imports }}\n  {{- if notContains .Pkg \"results\" }}\n  {{ .Alias }} \"{{ .Pkg }}\"\n  {{ end -}}\n  {{- end }}\n)\n\n{{- $serviceName := .Name }}\n{{- $prefix := .Prefix }}\nfunc {{ .Name }}Router(router contracts.HttpRouter) {\n  routeGroup := router.Group(\"{{ $prefix }}\"{{ toMiddlewares .Middlewares }})\n  {{- range .Methods }}\n  {{- $controllerMethod := sprintf \"%s%s\" $serviceName .Name  }}\n  {{- $path := .Path  }}\n  {{- $middlewares := .Middlewares }}\n    {{- range .Method }}\n    routeGroup.{{ . }}(\"{{ $path }}\", {{ $controllerMethod }}{{ toMiddlewares $middlewares }})\n    {{- end }}\n  {{- end }}\n}\n\n\n{{- $usageName := .UsageName }}\n\n{{- range .Methods }}\nfunc {{ $serviceName }}{{ .Name }}(request contracts.HttpRequest) any {\n    var req {{ .InputUsageName }}\n\n    if err:= request.Parse(&req); err != nil {\n      return response.ParseReqErr(err)\n    }\n\n    if err := validation.Struct(req); err != nil {\n      return response.InvalidReq(err)\n    }\n\n    resp, err := {{ $usageName }}{{ .Name }}(&req, request)\n    if err != nil {\n      return response.BizErr(err)\n    }\n\n    return response.Success(resp)\n}\n{{- end }}\n{{ end }}"
  },
  {
    "path": "tests/bootstrap.go",
    "content": "package tests\n\nimport (\n\t\"github.com/goal-web/contracts\"\n\t\"github.com/goal-web/goal/bootstrap/core\"\n)\n\nfunc initApp() contracts.Application {\n\tapp := core.Application(core.App{\n\t\tQueueWorker:      false,\n\t\tSchedulingWorker: false,\n\t})\n\n\treturn app\n}\n"
  },
  {
    "path": "tests/bootstrap_test.go",
    "content": "package tests\n\nimport \"testing\"\n\nfunc TestBootstrap(t *testing.T) {\n\tinitApp()\n}\n"
  },
  {
    "path": "tests/db_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n)\n\nfunc TestModel(t *testing.T) {\n\tinitApp()\n}\n"
  },
  {
    "path": "tests/env.toml",
    "content": "[app]\nname = \"goal\"\nkey = \"dQcxsKvBZKNfWivwnhKlDwvseguknBZPEiiDRQlIatjKLLpbzK\"\nenv = \"local\"\ndebug = true\n\n[http]\nhost = \"0.0.0.0\"\nport = \"8009\"\n\n\n[queue]\nconnection = \"goroutine\"\nkafka.brokers = \"localhost:9092\"\nnsq.address = \"localhost:49156\"\n\n[db]\nconnection = \"mysql\"\nhost = \"127.0.0.1\"\nport = \"3306\"\ndatabase = \"goal\"\nusername = \"root\"\npassword = \"root\"\n\n[db.sqlite]\ndatabase = \"database/database.sqlite\"\n\n[db.pgsql]\nhost = \"localhost\"\nport = \"55433\"\ndatabase = \"postgres\"\nusername = \"postgres\"\npassword = \"123456\"\n\n[redis]\nhost = \"hsy\"\nport = \"6379\"\npassword = \"123456\"\n\n[redis.cache]\nhost = \"hsy\"\nport = \"6379\"\ndb = 1\n\n# 缓存配置\n[cache]\ndriver = \"redis\"\nconnection = \"cache\"\nprefix = \"redis_\"\n\n# 哈希配置\n[hashing]\ndriver = \"bcrypt\"\ncost = \"14\"\nsalt = \"goal\"\n# 自定义哈希\n[hashing.hashers]\nmd5.driver = \"md5\"\nmd5.salt = \"goal\"\n\n# 文件系统配置\n[filesystem]\ndisk = \"public\"\nroot = \"storage/app/public\"\nperm = \"0777\"\n\n[filesystem.qiniu]\nprivate = \"false\"\nbucket = \"aa\"\ndomain = \"https://xxx.xxx.com\"\naccess_key = \"\"\nsecret_key = \"\"\n\n# session 配置\n[session]\nid = \"goal\"\nname = \"goal_session:\"\n\n"
  },
  {
    "path": "views/view.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>Document</title>\n</head>\n<body>\n\nview example\n\n</body>\n</html>"
  }
]