├── cmd └── jzero │ ├── .template │ ├── frame │ │ ├── api │ │ │ ├── .gitignore │ │ │ ├── app │ │ │ │ ├── go.mod.tpl │ │ │ │ ├── .jzero.yaml.tpl │ │ │ │ ├── main.go.tpl │ │ │ │ ├── internal │ │ │ │ │ ├── svc │ │ │ │ │ │ ├── middleware.go.tpl │ │ │ │ │ │ ├── config.go.tpl │ │ │ │ │ │ └── e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw= │ │ │ │ │ ├── custom │ │ │ │ │ │ └── custom.go.tpl │ │ │ │ │ ├── handler │ │ │ │ │ │ └── routes.go.tpl │ │ │ │ │ ├── model │ │ │ │ │ │ └── model.go.tpl │ │ │ │ │ ├── middleware │ │ │ │ │ │ ├── middleware.go.tpl │ │ │ │ │ │ ├── validator.go.tpl │ │ │ │ │ │ └── response.go.tpl │ │ │ │ │ ├── logic │ │ │ │ │ │ └── version │ │ │ │ │ │ │ └── version.go.tpl │ │ │ │ │ └── config │ │ │ │ │ │ └── config.go.tpl │ │ │ │ ├── plugins │ │ │ │ │ └── plugins.go.tpl │ │ │ │ ├── etc │ │ │ │ │ └── etc.yaml.tpl │ │ │ │ ├── desc │ │ │ │ │ └── api │ │ │ │ │ │ └── version.api.tpl │ │ │ │ ├── .gitignore.tpl │ │ │ │ ├── Dockerfile.tpl │ │ │ │ ├── README.md.tpl │ │ │ │ ├── cmd │ │ │ │ │ ├── root.go.tpl │ │ │ │ │ ├── version.go.tpl │ │ │ │ │ └── server.go.tpl │ │ │ │ └── serverless │ │ │ │ │ └── serverless.go.tpl │ │ │ ├── README.md │ │ │ └── LICENSE │ │ ├── rpc │ │ │ ├── .gitignore │ │ │ ├── app │ │ │ │ ├── .jzero.yaml.tpl │ │ │ │ ├── main.go.tpl │ │ │ │ ├── go.mod.tpl │ │ │ │ ├── internal │ │ │ │ │ ├── middleware │ │ │ │ │ │ ├── middleware.go.tpl │ │ │ │ │ │ └── validator.go.tpl │ │ │ │ │ ├── custom │ │ │ │ │ │ └── custom.go.tpl │ │ │ │ │ ├── model │ │ │ │ │ │ └── model.go.tpl │ │ │ │ │ ├── svc │ │ │ │ │ │ ├── config.go.tpl │ │ │ │ │ │ └── e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw= │ │ │ │ │ ├── server │ │ │ │ │ │ └── server.go.tpl │ │ │ │ │ └── config │ │ │ │ │ │ └── config.go.tpl │ │ │ │ ├── plugins │ │ │ │ │ └── plugins.go.tpl │ │ │ │ ├── desc │ │ │ │ │ └── proto │ │ │ │ │ │ ├── third_party │ │ │ │ │ │ ├── jzero │ │ │ │ │ │ │ └── api │ │ │ │ │ │ │ │ └── zrpc.proto │ │ │ │ │ │ └── google │ │ │ │ │ │ │ └── api │ │ │ │ │ │ │ └── annotations.proto │ │ │ │ │ │ └── version.proto.tpl │ │ │ │ ├── etc │ │ │ │ │ └── etc.yaml.tpl │ │ │ │ ├── .gitignore.tpl │ │ │ │ ├── README.md.tpl │ │ │ │ ├── Dockerfile.tpl │ │ │ │ ├── cmd │ │ │ │ │ ├── root.go.tpl │ │ │ │ │ ├── version.go.tpl │ │ │ │ │ └── server.go.tpl │ │ │ │ └── serverless │ │ │ │ │ └── serverless.go.tpl │ │ │ ├── README.md │ │ │ └── LICENSE │ │ └── gateway │ │ │ ├── .gitignore │ │ │ ├── app │ │ │ ├── go.mod.tpl │ │ │ ├── .jzero.yaml.tpl │ │ │ ├── main.go.tpl │ │ │ ├── plugins │ │ │ │ └── plugins.go.tpl │ │ │ ├── internal │ │ │ │ ├── custom │ │ │ │ │ └── custom.go.tpl │ │ │ │ ├── model │ │ │ │ │ └── model.go.tpl │ │ │ │ ├── middleware │ │ │ │ │ ├── middleware.go.tpl │ │ │ │ │ ├── header_processor.go.tpl │ │ │ │ │ ├── validator.go.tpl │ │ │ │ │ └── response.go.tpl │ │ │ │ ├── svc │ │ │ │ │ ├── config.go.tpl │ │ │ │ │ └── e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw= │ │ │ │ ├── server │ │ │ │ │ └── server.go.tpl │ │ │ │ └── config │ │ │ │ │ └── config.go.tpl │ │ │ ├── desc │ │ │ │ ├── proto │ │ │ │ │ ├── third_party │ │ │ │ │ │ ├── jzero │ │ │ │ │ │ │ └── api │ │ │ │ │ │ │ │ ├── http.proto │ │ │ │ │ │ │ │ └── zrpc.proto │ │ │ │ │ │ ├── google │ │ │ │ │ │ │ └── api │ │ │ │ │ │ │ │ └── annotations.proto │ │ │ │ │ │ └── grpc-gateway │ │ │ │ │ │ │ └── protoc-gen-openapiv2 │ │ │ │ │ │ │ └── options │ │ │ │ │ │ │ └── annotations.proto │ │ │ │ │ └── version.proto.tpl │ │ │ │ └── pb │ │ │ │ │ └── embed.go.tpl │ │ │ ├── .gitignore.tpl │ │ │ ├── Dockerfile.tpl │ │ │ ├── etc │ │ │ │ └── etc.yaml.tpl │ │ │ ├── cmd │ │ │ │ ├── root.go.tpl │ │ │ │ └── version.go.tpl │ │ │ ├── README.md.tpl │ │ │ ├── Makefile.tpl │ │ │ └── serverless │ │ │ │ └── serverless.go.tpl │ │ │ ├── README.md │ │ │ └── LICENSE │ ├── go-zero │ │ ├── model │ │ │ ├── tag.tpl │ │ │ ├── field.tpl │ │ │ ├── interface-delete.tpl │ │ │ ├── err.tpl │ │ │ ├── interface-find-one-by-field.tpl │ │ │ ├── interface-find-one.tpl │ │ │ ├── interface-update.tpl │ │ │ ├── interface-insert.tpl │ │ │ ├── model-gen.tpl │ │ │ ├── import-no-cache.tpl │ │ │ ├── import.tpl │ │ │ ├── table-name.tpl │ │ │ ├── find-one-by-field-extra-method.tpl │ │ │ ├── model-new.tpl │ │ │ ├── model.tpl │ │ │ ├── var.tpl │ │ │ ├── delete.tpl │ │ │ ├── types.tpl │ │ │ ├── find-one.tpl │ │ │ ├── find-one-by-field.tpl │ │ │ └── update.tpl │ │ ├── mongo │ │ │ ├── err.tpl │ │ │ ├── model_types.tpl │ │ │ └── model_custom.tpl │ │ └── api │ │ │ ├── logic.tpl │ │ │ └── handler.tpl │ ├── client │ │ └── zrpcclient-go │ │ │ ├── go.mod.tpl │ │ │ ├── plugins.go.tpl │ │ │ ├── clientset.go.tpl │ │ │ └── plugin.go.tpl │ ├── model │ │ ├── template.sql.tpl │ │ └── model.go.tpl │ ├── rpc │ │ ├── template.proto.tpl │ │ ├── serverless_plugins.go.tpl │ │ ├── middleware_http.go.tpl │ │ ├── server.go.tpl │ │ ├── middleware_zrpc.go.tpl │ │ └── middleware_gen.go.tpl │ ├── api │ │ ├── template.api.tpl │ │ ├── routes.go.tpl │ │ ├── serverless_plugins.go.tpl │ │ └── route2code.go.tpl │ ├── swagger │ │ └── swagger.json.tpl │ ├── gateway │ │ ├── template.proto.tpl │ │ └── serverless_plugins.go.tpl │ └── mongo │ │ └── model.go.tpl │ └── internal │ ├── pkg │ ├── osx │ │ └── osx.go │ ├── console │ │ └── console.go │ ├── gogen │ │ ├── gogen_test.go │ │ ├── util.go │ │ └── testdata │ │ │ └── example.api │ ├── stringx │ │ ├── stringx.go │ │ └── stringx_test.go │ ├── templatex │ │ ├── function_test.go │ │ ├── template.go │ │ └── function.go │ ├── execx │ │ └── exec.go │ ├── gitstatus │ │ └── status.go │ ├── dsn │ │ └── dsn_test.go │ └── filex │ │ └── filex.go │ ├── plugin │ └── plugin.go │ ├── command │ ├── migrate │ │ ├── migrategoto │ │ │ └── migrategoto.go │ │ ├── migratedown │ │ │ └── migratedown.go │ │ ├── migrateup │ │ │ └── migrateup.go │ │ ├── migrateversion │ │ │ └── migrateversion.go │ │ └── migrate.go │ ├── template │ │ ├── templatebuild │ │ │ └── filter.go │ │ └── templateinit │ │ │ └── templateinit.go │ ├── upgrade │ │ └── upgrade.go │ ├── add │ │ ├── addsql │ │ │ └── addsql.go │ │ ├── add.go │ │ ├── addapi │ │ │ └── addapi.go │ │ └── addproto │ │ │ └── addproto.go │ ├── format │ │ ├── format.go │ │ └── formatgo │ │ │ └── formatgo.go │ ├── version │ │ └── version.go │ ├── serverless │ │ └── serverless.go │ ├── completion │ │ └── completion.go │ └── gen │ │ ├── genmongo │ │ └── plugins.go │ │ └── genmodel │ │ └── plugins.go │ ├── embeded │ └── embeded.go │ └── hooks │ └── hooks.go ├── docs ├── src │ ├── .vuepress │ │ ├── styles │ │ │ ├── index.scss │ │ │ ├── palette.scss │ │ │ └── config.scss │ │ ├── navbar │ │ │ ├── index.ts │ │ │ ├── zh.ts │ │ │ └── en.ts │ │ ├── public │ │ │ └── favicon.ico │ │ ├── config.ts │ │ ├── sidebar.ts │ │ └── theme.ts │ ├── guide │ │ ├── mongo.md │ │ ├── serverless.md │ │ ├── jzero.md │ │ ├── migrate.md │ │ ├── template.md │ │ └── api.md │ ├── getting-started │ │ ├── gen.md │ │ ├── install.md │ │ └── genclient.md │ ├── community │ │ └── contribute.md │ └── README.md ├── .gitignore ├── tsconfig.json └── package.json ├── .gitignore ├── examples └── README.md ├── SECURITY.md ├── .github ├── dependabot.yml └── workflows │ ├── ci.yaml │ └── deploy-docs.yml ├── .golangci.yml ├── core ├── configcenter │ ├── subscriber │ │ └── etcd.go │ └── configcenter.go ├── slicex │ ├── slicex.go │ └── slicex_test.go ├── stores │ ├── monx │ │ └── monx.go │ ├── cache │ │ ├── cache.go │ │ └── redis_test.go │ ├── condition │ │ ├── update_field_test.go │ │ └── chain_test.go │ └── modelx │ │ ├── modelx.go │ │ └── sqlxconn.go ├── middleware │ └── fuzzy │ │ ├── request.go │ │ └── decode.go ├── status │ └── status_test.go └── templatex │ └── templatex.go ├── CONTRIBUTING.md ├── .goreleaser.yaml ├── LICENSE └── Dockerfile /cmd/jzero/.template/frame/api/.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/tag.tpl: -------------------------------------------------------------------------------- 1 | `db:"{{.field}}"` -------------------------------------------------------------------------------- /docs/src/.vuepress/styles/index.scss: -------------------------------------------------------------------------------- 1 | // place your custom styles here 2 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/.jzero.yaml.tpl: -------------------------------------------------------------------------------- 1 | gen: 2 | style: {{.Style}} -------------------------------------------------------------------------------- /docs/src/.vuepress/navbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./en.js"; 2 | export * from "./zh.js"; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | .claude 4 | dist 5 | node_modules 6 | docs/package-lock.json -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/go.mod.tpl: -------------------------------------------------------------------------------- 1 | module {{ .Module }} 2 | 3 | go {{ .GoVersion }} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/go.mod.tpl: -------------------------------------------------------------------------------- 1 | module {{ .Module }} 2 | 3 | go {{ .GoVersion }} -------------------------------------------------------------------------------- /cmd/jzero/.template/client/zrpcclient-go/go.mod.tpl: -------------------------------------------------------------------------------- 1 | module {{ .Module }} 2 | 3 | go {{ .GoVersion }} -------------------------------------------------------------------------------- /docs/src/.vuepress/styles/palette.scss: -------------------------------------------------------------------------------- 1 | // you can change colors here 2 | $theme-color: #096dd9; 3 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/field.tpl: -------------------------------------------------------------------------------- 1 | {{.name}} {{.type}} {{.tag}} {{if .hasComment}}// {{.comment}}{{end}} -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules/ 3 | src/.vuepress/.cache/ 4 | src/.vuepress/.temp/ 5 | src/.vuepress/dist/ 6 | -------------------------------------------------------------------------------- /docs/src/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzero-io/jzero/HEAD/docs/src/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Rich examples of jzero usage view repository [**https://github.com/jzero-io/examples**](https://github.com/jzero-io/examples) -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/.jzero.yaml.tpl: -------------------------------------------------------------------------------- 1 | gen: 2 | hooks: 3 | after: 4 | - jzero gen swagger 5 | 6 | style: {{.Style}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/main.go.tpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "{{ .Module }}/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/.jzero.yaml.tpl: -------------------------------------------------------------------------------- 1 | gen: 2 | hooks: 3 | after: 4 | - jzero gen swagger 5 | 6 | style: {{.Style}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/main.go.tpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "{{ .Module }}/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/main.go.tpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "{{ .Module }}/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/interface-delete.tpl: -------------------------------------------------------------------------------- 1 | Delete(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/README.md: -------------------------------------------------------------------------------- 1 | # templates 2 | 3 | jzero template repo with only rpc project 4 | 5 | ```shell 6 | jzero new simplerpc --frame rpc 7 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/README.md: -------------------------------------------------------------------------------- 1 | # templates 2 | 3 | jzero template repo with only api project 4 | 5 | ```shell 6 | jzero new simpleapi --frame api 7 | ``` 8 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/err.tpl: -------------------------------------------------------------------------------- 1 | package {{.pkg}} 2 | 3 | import "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | 5 | var ErrNotFound = sqlx.ErrNotFound 6 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/README.md: -------------------------------------------------------------------------------- 1 | # templates 2 | 3 | jzero template repo with gateway project 4 | 5 | ```shell 6 | jzero new simplegateway --frame gateway 7 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/interface-find-one-by-field.tpl: -------------------------------------------------------------------------------- 1 | FindOneBy{{.upperField}}(ctx context.Context, session sqlx.Session, {{.in}}) (*{{.upperStartCamelObject}}, error) -------------------------------------------------------------------------------- /docs/src/.vuepress/styles/config.scss: -------------------------------------------------------------------------------- 1 | // you can change config here 2 | $colors: #c0392b, #d35400, #f39c12, #27ae60, #16a085, #2980b9, #8e44ad, #2c3e50, 3 | #7f8c8d !default; 4 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/interface-find-one.tpl: -------------------------------------------------------------------------------- 1 | FindOne(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/interface-update.tpl: -------------------------------------------------------------------------------- 1 | Update(ctx context.Context, session sqlx.Session, {{if .containsIndexCache}}newData{{else}}data{{end}} *{{.upperStartCamelObject}}) error -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/svc/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | type Middleware struct{} 4 | 5 | func (svcCtx *ServiceContext) NewMiddleware() Middleware { 6 | return Middleware{} 7 | } 8 | -------------------------------------------------------------------------------- /cmd/jzero/.template/model/template.sql.tpl: -------------------------------------------------------------------------------- 1 | CREATE TABLE `{{ .Name }}` ( 2 | `id` bigint NOT NULL AUTO_INCREMENT, 3 | PRIMARY KEY (`id`) 4 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/go.mod.tpl: -------------------------------------------------------------------------------- 1 | module {{ .Module }} 2 | 3 | go {{ .GoVersion }} 4 | 5 | {{if (VersionCompare .GoVersion ">=" "1.24")}} 6 | tool ( 7 | github.com/jzero-io/jzero/cmd/jzero 8 | ) 9 | {{end}} -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/osx/osx.go: -------------------------------------------------------------------------------- 1 | package osx 2 | 3 | import "os" 4 | 5 | func IsDir(path string) bool { 6 | if info, err := os.Stat(path); err == nil && info.IsDir() { 7 | return true 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/interface-insert.tpl: -------------------------------------------------------------------------------- 1 | // Insert insert a new record into the database. 2 | // Deprecated: use InsertV2 instead. 3 | Insert(ctx context.Context, session sqlx.Session, data *{{.upperStartCamelObject}}) (sql.Result,error) -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/middleware/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/zrpc" 5 | ) 6 | 7 | func Register(z *zrpc.RpcServer) { 8 | z.AddUnaryInterceptors(NewValidator().UnaryServerMiddleware()) 9 | } 10 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/mongo/err.tpl: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/zeromicro/go-zero/core/stores/mon" 7 | ) 8 | 9 | var ( 10 | ErrNotFound = mon.ErrNotFound 11 | ErrInvalidObjectId = errors.New("invalid objectId") 12 | ) 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the last stable version at any given point. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Vulnerabilities can be disclosed in private using 10 | [GitHub advisories](https://github.com/jzero-io/jzero/security). 11 | 12 | Thanks! 13 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "moduleResolution": "NodeNext", 5 | "target": "ES2022" 6 | }, 7 | "include": [ 8 | "src/.vuepress/**/*.ts", 9 | "src/.vuepress/**/*.vue" 10 | ], 11 | "exclude": [ 12 | "node_modules" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/plugins/plugins.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if not .Serverless }}// Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "google.golang.org/grpc" 6 | 7 | "{{ .Module }}/internal/svc" 8 | ) 9 | 10 | func LoadPlugins(grpcServer *grpc.Server, svcCtx *svc.ServiceContext) {}{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/plugins/plugins.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if not .Serverless }}// Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "google.golang.org/grpc" 6 | 7 | "{{ .Module }}/internal/svc" 8 | ) 9 | 10 | func LoadPlugins(grpcServer *grpc.Server, svcCtx *svc.ServiceContext) {}{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/plugins/plugins.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if not .Serverless }}// Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "{{ .Module }}/internal/svc" 6 | 7 | "github.com/zeromicro/go-zero/rest" 8 | ) 9 | 10 | func LoadPlugins(server *rest.Server, svcCtx *svc.ServiceContext) {}{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/model-gen.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. Templates Edited by jzero. DO NOT EDIT. 2 | 3 | package {{.pkg}} 4 | {{.imports}} 5 | {{.vars}} 6 | {{.types}} 7 | {{.new}} 8 | {{.delete}} 9 | {{.find}} 10 | {{.insert}} 11 | {{.update}} 12 | {{.extraMethod}} 13 | {{.tableName}} 14 | {{.customized}} 15 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/custom/custom.go.tpl: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | type Custom struct{} 4 | 5 | func New() *Custom { 6 | return &Custom{} 7 | } 8 | 9 | // Start Please add custom logic here. 10 | func (c *Custom) Start() {} 11 | 12 | // Stop Please add shut down logic here. 13 | func (c *Custom) Stop() {} 14 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/custom/custom.go.tpl: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | type Custom struct{} 4 | 5 | func New() *Custom { 6 | return &Custom{} 7 | } 8 | 9 | // Start Please add custom logic here. 10 | func (c *Custom) Start() {} 11 | 12 | // Stop Please add shut down logic here. 13 | func (c *Custom) Stop() {} 14 | -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/template.proto.tpl: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package {{ .Package | base }}; 4 | 5 | option go_package = "./types/{{ .Package }}"; 6 | 7 | message CreateRequest {} 8 | 9 | message CreateResponse {} 10 | 11 | service {{ .Service | FirstUpper }} { 12 | rpc Create(CreateRequest) returns(CreateResponse) {}; 13 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/api/template.api.tpl: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | go_package: "{{ .Group }}" 5 | ) 6 | 7 | type CreateRequest {} 8 | 9 | type CreateResponse {} 10 | 11 | @server ( 12 | prefix: /api 13 | group: {{ .Group }} 14 | ) 15 | service {{ .Service }} { 16 | @handler Create 17 | post / (CreateRequest) returns (CreateResponse) 18 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | time: "10:00" 8 | labels: 9 | - "dependencies" 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | time: "10:00" 15 | labels: 16 | - "dependencies" -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/custom/custom.go.tpl: -------------------------------------------------------------------------------- 1 | package custom 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/zrpc" 5 | ) 6 | 7 | type Custom struct{} 8 | 9 | func New() *Custom { 10 | return &Custom{} 11 | } 12 | 13 | // Start Please add custom logic here. 14 | func (c *Custom) Start() {} 15 | 16 | // Stop Please add shut down logic here. 17 | func (c *Custom) Stop() {} 18 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/handler/routes.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package handler 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/zeromicro/go-zero/rest" 9 | 10 | "{{.Module}}/internal/svc" 11 | ) 12 | 13 | var ( 14 | _ = http.StatusOK 15 | _ = time.Now() 16 | ) 17 | 18 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {} 19 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | modules-download-mode: readonly 4 | linters: 5 | default: none 6 | enable: 7 | - thelper 8 | - tparallel 9 | - unconvert 10 | - unused 11 | - wastedassign 12 | - whitespace 13 | formatters: 14 | enable: 15 | - gofmt 16 | - gofumpt 17 | - goimports 18 | settings: 19 | goimports: 20 | local-prefixes: 21 | - github.com/jzero-io/jzero -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/mongo/model_types.tpl: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | 6 | "go.mongodb.org/mongo-driver/v2/bson" 7 | ) 8 | 9 | type {{.Type}} struct { 10 | ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` 11 | // TODO: Fill your own fields 12 | UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` 13 | CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` 14 | } 15 | -------------------------------------------------------------------------------- /docs/src/.vuepress/navbar/zh.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { navbar } from "vuepress-theme-hope"; 3 | 4 | // @ts-ignore 5 | export const zhNavbar = navbar([ 6 | "/", 7 | { 8 | link: "https://github.com/jzero-io/examples", 9 | text: "代码示例", 10 | icon: "vscode-icons:file-type-go" 11 | }, 12 | { 13 | link: "https://github.com/jzero-io/jzero-admin", 14 | text: "jzero 后台管理系统", 15 | icon: "icon-park-outline:system" 16 | }, 17 | ]); 18 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/model/model.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if has "model" .Features }}// Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | type Model struct {} 12 | 13 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 14 | return Model{} 15 | }{{ end }} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/model/model.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if has "model" .Features }}// Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | type Model struct {} 12 | 13 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 14 | return Model{} 15 | }{{ end }} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/model/model.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if has "model" .Features }}// Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/eddieowens/opts" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | ) 10 | 11 | type Model struct {} 12 | 13 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 14 | return Model{} 15 | }{{ end }} -------------------------------------------------------------------------------- /docs/src/.vuepress/navbar/en.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { navbar } from "vuepress-theme-hope"; 3 | 4 | // @ts-ignore 5 | export const enNavbar = navbar([ 6 | "/en/", 7 | { 8 | link: "https://github.com/jzero-io/examples", 9 | text: "code example", 10 | icon: "vscode-icons:file-type-go" 11 | }, 12 | { 13 | link: "https://github.com/jzero-io/jzero-admin", 14 | text: "jzero admin", 15 | icon: "icon-park-outline:system" 16 | }, 17 | ]); 18 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/desc/proto/third_party/jzero/api/zrpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package jzero.api; 4 | 5 | option go_package = "github.com/jzero-io/desc/proto/api"; 6 | 7 | import "google/protobuf/descriptor.proto"; 8 | 9 | extend google.protobuf.MethodOptions { 10 | ZrpcRule zrpc = 10002; 11 | } 12 | 13 | extend google.protobuf.ServiceOptions { 14 | ZrpcRule zrpc_group = 10003; 15 | } 16 | 17 | message ZrpcRule { 18 | string middleware = 1; 19 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/proto/third_party/jzero/api/http.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package jzero.api; 4 | 5 | option go_package = "github.com/jzero-io/desc/proto/api"; 6 | 7 | import "google/protobuf/descriptor.proto"; 8 | 9 | extend google.protobuf.MethodOptions { 10 | HttpRule http = 10000; 11 | } 12 | 13 | extend google.protobuf.ServiceOptions { 14 | HttpRule http_group = 10001; 15 | } 16 | 17 | message HttpRule { 18 | string middleware = 1; 19 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/proto/third_party/jzero/api/zrpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package jzero.api; 4 | 5 | option go_package = "github.com/jzero-io/desc/proto/api"; 6 | 7 | import "google/protobuf/descriptor.proto"; 8 | 9 | extend google.protobuf.MethodOptions { 10 | ZrpcRule zrpc = 10002; 11 | } 12 | 13 | extend google.protobuf.ServiceOptions { 14 | ZrpcRule zrpc_group = 10003; 15 | } 16 | 17 | message ZrpcRule { 18 | string middleware = 1; 19 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/import-no-cache.tpl: -------------------------------------------------------------------------------- 1 | import ( 2 | "context" 3 | "database/sql" 4 | "strings" 5 | "slices" 6 | {{if .time}}"time"{{end}} 7 | 8 | "github.com/zeromicro/go-zero/core/stores/sqlc" 9 | "github.com/zeromicro/go-zero/core/stores/sqlx" 10 | "github.com/huandu/go-sqlbuilder" 11 | "github.com/jzero-io/jzero/core/stores/condition" 12 | "github.com/jzero-io/jzero/core/stores/modelx" 13 | "github.com/eddieowens/opts" 14 | 15 | {{.third}} 16 | ) 17 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/import.tpl: -------------------------------------------------------------------------------- 1 | import ( 2 | "context" 3 | "database/sql" 4 | "fmt" 5 | "strings" 6 | "slices" 7 | {{if .time}}"time"{{end}} 8 | 9 | "github.com/zeromicro/go-zero/core/stores/sqlc" 10 | "github.com/zeromicro/go-zero/core/stores/sqlx" 11 | "github.com/huandu/go-sqlbuilder" 12 | "github.com/jzero-io/jzero/core/stores/condition" 13 | "github.com/jzero-io/jzero/core/stores/modelx" 14 | "github.com/eddieowens/opts" 15 | 16 | {{.third}} 17 | ) 18 | -------------------------------------------------------------------------------- /core/configcenter/subscriber/etcd.go: -------------------------------------------------------------------------------- 1 | package subscriber 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/configcenter/subscriber" 5 | "github.com/zeromicro/go-zero/core/logx" 6 | ) 7 | 8 | type EtcdConf subscriber.EtcdConf 9 | 10 | // MustNewEtcdSubscriber returns an etcd Subscriber, exits on errors. 11 | func MustNewEtcdSubscriber(conf EtcdConf) subscriber.Subscriber { 12 | s, err := subscriber.NewEtcdSubscriber(subscriber.EtcdConf(conf)) 13 | logx.Must(err) 14 | return s 15 | } 16 | -------------------------------------------------------------------------------- /cmd/jzero/.template/swagger/swagger.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "basePath": "/", 3 | "consumes": [ 4 | "application/json" 5 | ], 6 | "info": {}, 7 | "produces": [ 8 | "application/json" 9 | ], 10 | "schemes": [ 11 | "http", 12 | "https" 13 | ], 14 | "securityDefinitions": { 15 | "apiKey": { 16 | "description": "Enter Authorization", 17 | "in": "header", 18 | "name": "Authorization", 19 | "type": "apiKey" 20 | } 21 | }, 22 | "swagger": "2.0" 23 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Jzero 2 | 3 | ## steps 4 | 5 | ### 1. fork 6 | 7 | https://github.com/jzero-io/jzero/fork 8 | 9 | ### 2. clone 10 | 11 | ```shell 12 | git clone https://github.com/your_username/jzero 13 | ``` 14 | 15 | ### 3. checkout branch 16 | 17 | ```shell 18 | cd jzero 19 | 20 | git checkout -b feat/patch-1 21 | ``` 22 | 23 | ### 4. push 24 | 25 | ```shell 26 | git add . 27 | git commit -m "feat(xx): custom message" 28 | git push 29 | ``` 30 | 31 | ### 5. pull request 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /cmd/jzero/.template/api/routes.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package handler 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/zeromicro/go-zero/rest" 9 | "{{.Module}}/internal/svc"{{ if .HandlerImports }}{{ .HandlerImports }}{{ end }} 10 | ) 11 | 12 | var ( 13 | _ = http.StatusOK 14 | _ = time.Now() 15 | ) 16 | 17 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { 18 | {{if .Routes}}{{.Routes}}{{end}} 19 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/middleware/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/gateway" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | "github.com/zeromicro/go-zero/rest/httpx" 7 | ) 8 | 9 | func Register(z *zrpc.RpcServer, gw *gateway.Server) { 10 | z.AddUnaryInterceptors(NewValidator().UnaryServerMiddleware()) 11 | z.AddUnaryInterceptors(WithValueMiddleware) 12 | 13 | httpx.SetErrorHandlerCtx(ErrorMiddleware) 14 | gw.Use(ResponseMiddleware) 15 | } 16 | -------------------------------------------------------------------------------- /core/slicex/slicex.go: -------------------------------------------------------------------------------- 1 | package slicex 2 | 3 | func Paginate[T any](slice []T, page, size int) []T { 4 | start := (page - 1) * size 5 | if start >= len(slice) { 6 | return []T{} 7 | } 8 | 9 | end := start + size 10 | if end > len(slice) { 11 | end = len(slice) 12 | } 13 | 14 | return slice[start:end] 15 | } 16 | 17 | func ToMap[K comparable, T any](rows []T, keyFunc func(row T) K) map[K]T { 18 | res := make(map[K]T, len(rows)) 19 | for _, row := range rows { 20 | key := keyFunc(row) 21 | res[key] = row 22 | } 23 | return res 24 | } 25 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/etc/etc.yaml.tpl: -------------------------------------------------------------------------------- 1 | rest: 2 | name: {{ .APP }}-api 3 | host: 0.0.0.0 4 | port: 8001 5 | 6 | log: 7 | serviceName: {{ .APP }} 8 | encoding: plain 9 | level: info 10 | mode: console 11 | {{ if has "model" .Features }} 12 | sqlx: 13 | driverName: "mysql" 14 | dataSource: "root:123456@tcp(127.0.0.1:3306)/{{ .APP }}?charset=utf8mb4&parseTime=True&loc=Local" 15 | {{ end }}{{ if has "redis" .Features }} 16 | redis: 17 | host: "127.0.0.1:6379" 18 | type: "node" 19 | pass: "123456"{{ end }} -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/table-name.tpl: -------------------------------------------------------------------------------- 1 | func (m *default{{.upperStartCamelObject}}Model)withTableColumns(columns ...string) []string { 2 | var withTableColumns []string 3 | for _, col := range columns { 4 | if strings.Contains(col, ".") { 5 | withTableColumns = append(withTableColumns, condition.QuoteWithFlavor(m.flavor, col)) 6 | } else { 7 | withTableColumns = append(withTableColumns, m.table + "." + condition.QuoteWithFlavor(m.flavor, col)) 8 | } 9 | } 10 | return withTableColumns 11 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/etc/etc.yaml.tpl: -------------------------------------------------------------------------------- 1 | zrpc: 2 | listenOn: 0.0.0.0:8000 3 | mode: dev 4 | name: {{ .APP }}.rpc 5 | 6 | log: 7 | serviceName: {{ .APP }} 8 | encoding: plain 9 | level: info 10 | mode: console 11 | {{ if has "model" .Features }} 12 | sqlx: 13 | driverName: "mysql" 14 | dataSource: "root:123456@tcp(127.0.0.1:3306)/{{ .APP }}?charset=utf8mb4&parseTime=True&loc=Local" 15 | {{ end }}{{ if has "redis" .Features }} 16 | redis: 17 | host: "127.0.0.1:6379" 18 | type: "node" 19 | pass: "123456"{{ end }} -------------------------------------------------------------------------------- /cmd/jzero/.template/api/serverless_plugins.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "github.com/zeromicro/go-zero/rest" 6 | 7 | "{{ .Module }}/internal/svc" 8 | {{range $v := .Plugins}}{{ $v.Path | base }} "{{ $v.Module }}/serverless" 9 | {{end}} 10 | ) 11 | 12 | func LoadPlugins(server *rest.Server, svcCtx *svc.ServiceContext) { 13 | {{ range $v := .Plugins }} 14 | { 15 | serverless := {{ $v.Path | base }}.New() 16 | serverless.HandlerFunc(server, serverless.SvcCtx) 17 | } 18 | {{end}} 19 | } -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/console/console.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "fmt" 4 | 5 | const consoleColorTag = 0x1B 6 | 7 | // Green 控制台绿色字符 8 | func Green(txt string) string { 9 | return fmt.Sprintf("%c[32m%s%c[0m", consoleColorTag, txt, consoleColorTag) 10 | } 11 | 12 | // Yellow 控制台黄色字符 13 | func Yellow(txt string) string { 14 | return fmt.Sprintf("%c[33m%s%c[0m", consoleColorTag, txt, consoleColorTag) 15 | } 16 | 17 | // Red 控制台红色字符 18 | func Red(txt string) string { 19 | return fmt.Sprintf("%c[31m%s%c[0m", consoleColorTag, txt, consoleColorTag) 20 | } 21 | -------------------------------------------------------------------------------- /docs/src/.vuepress/config.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { defineUserConfig } from "vuepress"; 3 | import theme from "./theme.js"; 4 | 5 | export default defineUserConfig({ 6 | base: "/", 7 | 8 | locales: { 9 | "/": { 10 | lang: "zh-CN", 11 | title: "Jzero Framework", 12 | description: "Jzero docs", 13 | }, 14 | // "/en/": { 15 | // lang: "en-US", 16 | // title: "Jzero Framework", 17 | // description: "Jzero docs", 18 | // }, 19 | }, 20 | 21 | theme, 22 | 23 | // 和 PWA 一起启用 24 | // shouldPrefetch: false, 25 | }); 26 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/desc/proto/version.proto.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}{{else}}syntax = "proto3"; 2 | 3 | package {{if .Serverless}}{{.APP | lower}}{{end}}version; 4 | option go_package = "./types/{{if .Serverless}}{{.APP | lower}}{{end}}version"; 5 | 6 | message VersionRequest {} 7 | 8 | message VersionResponse { 9 | string version = 1; 10 | string goVersion = 2; 11 | string commit = 3; 12 | string date = 4; 13 | } 14 | 15 | service {{if .Serverless}}{{.APP | ToCamel}}{{end}}Version { 16 | rpc Version(VersionRequest) returns(VersionResponse) {}; 17 | }{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/serverless_plugins.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "{{ .Module }}/internal/svc" 6 | "google.golang.org/grpc" 7 | 8 | {{range $v := .Plugins}}{{ $v.Path | base }} "{{ $v.Module }}/serverless" 9 | {{end}} 10 | ) 11 | 12 | func LoadPlugins(grpcServer *grpc.Server,svcCtx *svc.ServiceContext) { 13 | {{ range $v := .Plugins }} 14 | { 15 | serverless := {{ $v.Path | base }}.New() 16 | serverless.RegisterZrpcServer(grpcServer, serverless.SvcCtx) 17 | } 18 | {{end}} 19 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/desc/api/version.api.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}{{else}}syntax = "v1" 2 | 3 | info ( 4 | go_package: "version" 5 | WrapCodeMsg: true 6 | ) 7 | 8 | type VersionRequest {} 9 | 10 | type VersionResponse { 11 | Version string `json:"version"` 12 | GoVersion string `json:"goVersion"` 13 | Commit string `json:"commit"` 14 | Date string `json:"date"` 15 | } 16 | 17 | @server( 18 | group: version 19 | ) 20 | service {{ .APP | ToCamel }} { 21 | @handler Version 22 | get /api/version (VersionRequest) returns (VersionResponse) 23 | }{{end}} -------------------------------------------------------------------------------- /docs/src/guide/mongo.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: mongodb 指南 3 | icon: logos:mongodb 4 | star: true 5 | order: 5 6 | --- 7 | 8 | ## 前言 9 | 10 | jzero 支持通过指定 mongo type 将代码到 `internal/mongo` 下. 11 | 12 | 为了在使用上更加方便, jzero 自动生成了 `internal/mongo/model.go` 文件, 用于注册所有生成的 mongo model. 13 | 14 | ## 特性 15 | 16 | * 支持 redis/sync_map 缓存 17 | 18 | ## 生成代码 19 | 20 | ```yaml 21 | gen: 22 | # 指定 mongo type 23 | mongo-type: ["user", "role", "menu"] 24 | # 是否需要缓存 25 | mongo-cache: true 26 | # 指定哪些类型需要缓存 27 | mongo-cache-type: 28 | - user 29 | ``` 30 | 31 | ```shell 32 | jzero gen 33 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/gateway/template.proto.tpl: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package {{ .Package | base }}; 4 | 5 | option go_package = "./types/{{ .Package }}"; 6 | 7 | import "google/api/annotations.proto"; 8 | import "grpc-gateway/protoc-gen-openapiv2/options/annotations.proto"; 9 | 10 | message CreateRequest {} 11 | 12 | message CreateResponse {} 13 | 14 | service {{ .Service | FirstUpper }} { 15 | rpc Create(CreateRequest) returns(CreateResponse) { 16 | option (google.api.http) = { 17 | post: "/api/{{ .Package }}" 18 | body: "*" 19 | }; 20 | }; 21 | } -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jzero-docs", 3 | "version": "1.0.0", 4 | "description": "jzero framework", 5 | "license": "UnLicense", 6 | "type": "module", 7 | "scripts": { 8 | "docs:build": "vuepress-vite build src", 9 | "docs:clean-dev": "vuepress-vite dev src --clean-cache", 10 | "docs:dev": "vuepress-vite dev src", 11 | "docs:update-package": "pnpm dlx vp-update" 12 | }, 13 | "devDependencies": { 14 | "@vuepress/bundler-vite": "2.0.0-rc.13", 15 | "vue": "^3.4.21", 16 | "vuepress": "2.0.0-rc.13", 17 | "vuepress-theme-hope": "2.0.0-rc.49" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/middleware/middleware.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/rest" 5 | "github.com/zeromicro/go-zero/rest/httpx" 6 | ) 7 | 8 | func Register(server *rest.Server) { 9 | httpx.SetOkHandler(NewOkMiddleware().Handle) 10 | httpx.SetErrorHandlerCtx(NewErrorMiddleware().Handle) 11 | httpx.SetValidator(NewValidator()) 12 | 13 | // add custom middleware 14 | // server.Use(func(next http .HandlerFunc) http.HandlerFunc { 15 | // return func(w http.ResponseWriter, r *http.Request) { 16 | // next.ServeHTTP(w, r) 17 | // } 18 | // }) 19 | } 20 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/find-one-by-field-extra-method.tpl: -------------------------------------------------------------------------------- 1 | func (m *default{{.upperStartCamelObject}}Model) formatPrimary(primary any) string { 2 | return fmt.Sprintf("%s%v", {{.primaryKeyLeft}}, primary) 3 | } 4 | 5 | func (m *default{{.upperStartCamelObject}}Model) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error { 6 | sb := sqlbuilder.Select({{.lowerStartCamelObject}}Rows).From(m.table) 7 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryField}}"), primary)) 8 | sql, args := sb.BuildWithFlavor(m.flavor) 9 | return conn.QueryRowCtx(ctx, v, sql, args...) 10 | } 11 | -------------------------------------------------------------------------------- /core/stores/monx/monx.go: -------------------------------------------------------------------------------- 1 | package monx 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/zeromicro/go-zero/core/stores/cache" 6 | ) 7 | 8 | type MonOpts struct { 9 | CacheConf cache.CacheConf 10 | CacheOpts []cache.Option 11 | } 12 | 13 | func (opts MonOpts) DefaultOptions() MonOpts { 14 | return MonOpts{} 15 | } 16 | 17 | func WithCacheConf(cacheConf cache.CacheConf) opts.Opt[MonOpts] { 18 | return func(o *MonOpts) { 19 | o.CacheConf = cacheConf 20 | } 21 | } 22 | 23 | func WithCacheOpts(cacheOpts ...cache.Option) opts.Opt[MonOpts] { 24 | return func(o *MonOpts) { 25 | o.CacheOpts = cacheOpts 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/.gitignore.tpl: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/.gitignore.tpl: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/.gitignore.tpl: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # idea 21 | .idea 22 | 23 | # Vs Code 24 | .vscode 25 | 26 | # logs 27 | logs -------------------------------------------------------------------------------- /core/stores/cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/zeromicro/go-zero/core/stores/cache" 8 | ) 9 | 10 | type Cache interface { 11 | cache.Cache 12 | 13 | // SetNoExpireCtx Because zero cache set ctx has default expire, so jzero add this method 14 | SetNoExpireCtx(ctx context.Context, key string, val any) error 15 | 16 | // GetPrefixKeysCtx get prefix key, give prefix key return all matched key 17 | GetPrefixKeysCtx(ctx context.Context, prefix string) ([]string, error) 18 | 19 | // ExpireCtx set key expire 20 | ExpireCtx(ctx context.Context, key string, expire time.Duration) error 21 | } 22 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/gogen/gogen_test.go: -------------------------------------------------------------------------------- 1 | package gogen 2 | 3 | import ( 4 | "fmt" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/zeromicro/go-zero/tools/goctl/config" 10 | "github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/parser" 11 | ) 12 | 13 | func TestGenRoutesString(t *testing.T) { 14 | parse, err := parser.Parse(filepath.Join("testdata", "example.api"), nil) 15 | assert.Nil(t, err) 16 | 17 | routesString, err := GenRoutesString("example", &config.Config{ 18 | NamingFormat: "gozero", 19 | }, parse) 20 | assert.NotNil(t, routesString) 21 | assert.Nil(t, err) 22 | fmt.Println(routesString) 23 | } 24 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/README.md.tpl: -------------------------------------------------------------------------------- 1 | # {{ .APP }} 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ## Build docker image 20 | 21 | ```shell 22 | # add a builder first 23 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 24 | 25 | # build and load 26 | docker buildx build --platform linux/{{ .GoArch }} --progress=plain -t {{ .APP }}:latest . --load 27 | ``` 28 | 29 | ## Documents 30 | 31 | https://docs.jzero.io -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/proto/version.proto.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}{{else}}syntax = "proto3"; 2 | 3 | package version; 4 | 5 | import "google/api/annotations.proto"; 6 | import "grpc-gateway/protoc-gen-openapiv2/options/annotations.proto"; 7 | 8 | option go_package = "./types/version"; 9 | 10 | message VersionRequest {} 11 | 12 | message VersionResponse { 13 | string version = 1; 14 | string goVersion = 2; 15 | string commit = 3; 16 | string date = 4; 17 | } 18 | 19 | service Version { 20 | rpc Version(VersionRequest) returns(VersionResponse) { 21 | option (google.api.http) = { 22 | get: "/api/version" 23 | }; 24 | }; 25 | }{{end}} -------------------------------------------------------------------------------- /docs/src/guide/serverless.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 插件指南 3 | icon: arcticons:game-plugins 4 | star: true 5 | order: 5.4 6 | --- 7 | 8 | jzero 支持插件化机制, 可以方便的进行插件的安装和卸载操作. 9 | 10 | ## 新增插件 11 | 12 | ```shell 13 | # api 项目插件 14 | jzero new your_plugin --frame api --serverless 15 | 16 | # rpc 项目插件 17 | jzero new your_plugin --frame rpc --serverless 18 | 19 | # gateway 项目插件 20 | jzero new your_plugin --frame gateway --serverless 21 | ``` 22 | 23 | ## 编译项目 24 | 25 | ```shell 26 | jzero serverless build 27 | 28 | go build 29 | ``` 30 | 31 | ## 卸载插件 32 | 33 | ```shell 34 | # 卸载所有 35 | jzero serverless delete 36 | 37 | # 卸载指定插件 38 | jzero serverless delete --plugin 39 | 40 | # 重新编译 41 | go build 42 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/Dockerfile.tpl: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest as builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY https://goproxy.cn,direct 7 | 8 | WORKDIR /usr/local/go/src/app 9 | 10 | COPY ./ ./ 11 | 12 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 13 | && jzero gen swagger \ 14 | && cp -r etc /dist/etc \ 15 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc 16 | 17 | 18 | FROM --platform=$TARGETPLATFORM alpine:latest 19 | 20 | WORKDIR /dist 21 | 22 | COPY --from=builder /dist . 23 | 24 | EXPOSE 8001 25 | 26 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/stringx/stringx.go: -------------------------------------------------------------------------------- 1 | package stringx 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func FirstUpper(s string) string { 8 | if len(s) > 0 { 9 | return strings.ToUpper(string(s[0])) + s[1:] 10 | } 11 | return s 12 | } 13 | 14 | func FirstLower(s string) string { 15 | if len(s) > 0 { 16 | return strings.ToLower(string(s[0])) + s[1:] 17 | } 18 | return s 19 | } 20 | 21 | func ToCamel(s string) string { 22 | s = strings.ReplaceAll(s, "_", "-") 23 | s = strings.ReplaceAll(s, "/", "-") 24 | words := strings.Split(s, "-") 25 | 26 | for i := 1; i < len(words); i++ { 27 | words[i] = FirstUpper(words[i]) 28 | } 29 | 30 | result := strings.Join(words, "") 31 | 32 | return result 33 | } 34 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/Dockerfile.tpl: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest as builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY https://goproxy.cn,direct 7 | 8 | WORKDIR /usr/local/go/src/app 9 | 10 | COPY ./ ./ 11 | 12 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 13 | && jzero gen swagger \ 14 | && cp -r etc /dist/etc \ 15 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc 16 | 17 | 18 | FROM --platform=$TARGETPLATFORM alpine:latest 19 | 20 | WORKDIR /dist 21 | 22 | COPY --from=builder /dist . 23 | 24 | EXPOSE 8000 8001 25 | 26 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/Dockerfile.tpl: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/jzero-io/jzero:latest as builder 2 | 3 | ARG TARGETARCH 4 | ARG LDFLAGS 5 | 6 | ENV GOPROXY https://goproxy.cn,direct 7 | 8 | WORKDIR /usr/local/go/src/app 9 | 10 | COPY ./ ./ 11 | 12 | RUN --mount=type=cache,target=/go/pkg CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags="$LDFLAGS" -o /dist/app main.go \ 13 | && jzero gen swagger \ 14 | && cp -r etc /dist/etc \ 15 | && mkdir -p /dist/desc && cp -r desc/swagger /dist/desc 16 | 17 | 18 | FROM --platform=$TARGETPLATFORM alpine:latest 19 | 20 | WORKDIR /dist 21 | 22 | COPY --from=builder /dist . 23 | 24 | EXPOSE 8000 8001 25 | 26 | CMD ["./app", "server"] -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/etc/etc.yaml.tpl: -------------------------------------------------------------------------------- 1 | zrpc: 2 | listenOn: 0.0.0.0:8000 3 | mode: dev 4 | name: {{ .APP }}.rpc 5 | gateway: 6 | name: {{ .APP }}.gw 7 | port: 8001 8 | upstreams: 9 | - grpc: 10 | endpoints: 11 | - 0.0.0.0:8000 12 | name: {{ .APP }}.gw 13 | 14 | log: 15 | serviceName: {{ .APP }} 16 | encoding: plain 17 | level: info 18 | mode: console 19 | {{ if has "model" .Features }} 20 | sqlx: 21 | driverName: "mysql" 22 | dataSource: "root:123456@tcp(127.0.0.1:3306)/{{ .APP }}?charset=utf8mb4&parseTime=True&loc=Local" 23 | {{ end }}{{ if has "redis" .Features }} 24 | redis: 25 | host: "127.0.0.1:6379" 26 | type: "node" 27 | pass: "123456"{{ end }} -------------------------------------------------------------------------------- /docs/src/guide/jzero.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: jzero 指南 3 | icon: catppuccin:astro-config 4 | star: true 5 | order: 0.1 6 | --- 7 | 8 | :::important 涨知识的小技巧 9 | ::: 10 | 11 | * 支持通过配置文件 .jzero.yaml 控制各种参数 12 | * 支持通过 flag 控制各种参数 13 | * 支持通过环境变量控制各种参数 14 | * 支持通过以上组合的方式控制各种参数, 优先级从高到低为 环境变量 > flag > 配置文件 15 | 16 | 如: `jzero gen --style go_zero` 对应 `.jzero.yaml` 内容 17 | 18 | ```yaml 19 | gen: 20 | style: go_zero 21 | ``` 22 | 23 | 即 `jzero gen` + `.jzero.yaml` = `jzero gen --style go_zero` 24 | 25 | 对于环境变量的使用, 需要增加前缀 `JZERO_`, 如 `JZERO_GEN_STYLE` 26 | 27 | 即 `JZERO_GEN_STYLE=go_zero jzero gen` = `jzero gen --style go_zero` 28 | 29 | 环境变量的定义支持使用配置文件, 默认为 `.jzero.env.yaml` 30 | 31 | 如: 32 | 33 | ```yaml 34 | JZERO_GEN_STYLE=go_zero 35 | ``` -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/stringx/stringx_test.go: -------------------------------------------------------------------------------- 1 | package stringx 2 | 3 | import "testing" 4 | 5 | func TestToCamel(t *testing.T) { 6 | type args struct { 7 | s string 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want string 13 | }{ 14 | { 15 | name: "test1", 16 | args: args{ 17 | s: "ping-pong", 18 | }, 19 | want: "pingPong", 20 | }, 21 | 22 | { 23 | name: "test2", 24 | args: args{ 25 | s: "ping/pong", 26 | }, 27 | want: "pingPong", 28 | }, 29 | } 30 | for _, tt := range tests { 31 | t.Run(tt.name, func(t *testing.T) { 32 | if got := ToCamel(tt.args.s); got != tt.want { 33 | t.Errorf("ToCamel() = %v, want %v", got, tt.want) 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cmd/jzero/.template/gateway/serverless_plugins.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | package plugins 3 | 4 | import ( 5 | "{{ .Module }}/internal/svc" 6 | "google.golang.org/grpc" 7 | 8 | {{range $v := .Plugins}}{{ $v.Path | base }} "{{ $v.Module }}/serverless" 9 | {{end}} 10 | ) 11 | 12 | func LoadPlugins(grpcServer *grpc.Server,svcCtx *svc.ServiceContext) { 13 | {{ range $v := .Plugins }} 14 | { 15 | serverless := {{ $v.Path | base }}.New() 16 | serverless.RegisterZrpcServer(grpcServer, serverless.SvcCtx) 17 | svcCtx.ConfigCenter.MustGetConfig().Gateway.Upstreams[0].ProtoSets = append(svcCtx.ConfigCenter.MustGetConfig().Gateway.Upstreams[0].ProtoSets, serverless.ProtoSets...) 18 | } 19 | {{end}} 20 | } 21 | 22 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/templatex/function_test.go: -------------------------------------------------------------------------------- 1 | package templatex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFormatStyle(t *testing.T) { 10 | template, err := ParseTemplate("test", map[string]any{ 11 | "Style": "go_zero", 12 | }, []byte(`{{FormatStyle .Style "service_context.go.tpl"}}`)) 13 | if err != nil { 14 | t.Fatal(err) 15 | } 16 | assert.Equal(t, "service_context.go.tpl", string(template)) 17 | } 18 | 19 | func TestVersionCompare(t *testing.T) { 20 | template, err := ParseTemplate("test", map[string]any{ 21 | "GoVersion": "1.24", 22 | }, []byte(`{{if (VersionCompare .GoVersion ">=" "1.24")}}true{{end}}`)) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | assert.Equal(t, "true", string(template)) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/jzero/internal/plugin/plugin.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | type Plugin struct { 9 | Name string 10 | Path string 11 | Module string 12 | } 13 | 14 | func GetPlugins() ([]Plugin, error) { 15 | var plugins []Plugin 16 | dir, err := os.ReadDir("plugins") 17 | if err != nil { 18 | return nil, err 19 | } 20 | for _, p := range dir { 21 | if p.IsDir() { 22 | plugins = append(plugins, Plugin{ 23 | Name: p.Name(), 24 | Path: filepath.ToSlash(filepath.Join("plugins", p.Name())), 25 | }) 26 | } else if p.Type() == os.ModeSymlink { 27 | plugins = append(plugins, Plugin{ 28 | Name: p.Name(), 29 | Path: filepath.ToSlash(filepath.Join("plugins", p.Name())), 30 | }) 31 | } 32 | } 33 | return plugins, nil 34 | } 35 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/cmd/root.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "{{ .APP }}", 12 | Short: "{{ .APP }} root", 13 | Long: "{{ .APP }} root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "set config file") 30 | } -------------------------------------------------------------------------------- /docs/src/.vuepress/sidebar.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { sidebar } from "vuepress-theme-hope"; 3 | 4 | export default sidebar({ 5 | "/": [ 6 | "", 7 | { 8 | text: "快速开始", 9 | icon: "streamline-sharp-color:startup", 10 | prefix: "getting-started/", 11 | children: "structure", 12 | collapsible: true, 13 | expanded: true, 14 | }, 15 | { 16 | text: "指南", 17 | icon: "icon-park-twotone:guide-board", 18 | prefix: "guide/", 19 | children: "structure", 20 | collapsible: true, 21 | expanded: true, 22 | }, 23 | { 24 | text: "社区", 25 | icon: "iconoir:community", 26 | prefix: "community/", 27 | children: "structure", 28 | collapsible: true, 29 | expanded: true, 30 | }, 31 | ], 32 | }); 33 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/README.md.tpl: -------------------------------------------------------------------------------- 1 | # {{ .APP }} 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ### Generate swagger code 20 | 21 | ```shell 22 | jzero gen swagger 23 | ``` 24 | 25 | you can see generated swagger json in `desc/swagger` 26 | 27 | ## Build docker image 28 | 29 | ```shell 30 | # add a builder first 31 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 32 | 33 | # build and load 34 | docker buildx build --platform linux/{{ .GoArch }} --progress=plain -t {{ .APP }}:latest . --load 35 | ``` 36 | 37 | ## Documents 38 | 39 | https://docs.jzero.io -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/cmd/root.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "{{ .APP }}", 12 | Short: "{{ .APP }} root", 13 | Long: "{{ .APP }} root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "config file (default is project root dir etc/etc.yaml") 30 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/README.md.tpl: -------------------------------------------------------------------------------- 1 | # {{ .APP }} 2 | 3 | ## Install Jzero Framework 4 | 5 | ```shell 6 | go install github.com/jzero-io/jzero/cmd/jzero@latest 7 | 8 | jzero check 9 | ``` 10 | 11 | ## Generate code 12 | 13 | ### Generate server code 14 | 15 | ```shell 16 | jzero gen 17 | ``` 18 | 19 | ### Generate client go code 20 | 21 | ```shell 22 | jzero gen sdk 23 | ``` 24 | 25 | ### Generate swagger code 26 | 27 | ```shell 28 | jzero gen swagger 29 | ``` 30 | 31 | ## Build docker image 32 | 33 | ```shell 34 | # add a builder first 35 | docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 36 | 37 | # build and load 38 | docker buildx build --platform linux/{{ .GoArch }} --progress=plain -t {{ .APP }}:latest . --load 39 | ``` 40 | 41 | ## Documents 42 | 43 | https://docs.jzero.io -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/cmd/root.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // rootCmd represents the base command when called without any subcommands 10 | var rootCmd = &cobra.Command{ 11 | Use: "{{ .APP }}", 12 | Short: "{{ .APP }} root", 13 | Long: "{{ .APP }} root.", 14 | CompletionOptions: cobra.CompletionOptions{ 15 | DisableDefaultCmd: true, 16 | }, 17 | } 18 | 19 | // Execute adds all child commands to the root command and sets flags appropriately. 20 | // This is called by main.main(). It only needs to happen once to the rootCmd. 21 | func Execute() { 22 | err := rootCmd.Execute() 23 | if err != nil { 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().String("config", "etc/etc.yaml", "config file (default is project root dir etc/etc.yaml)") 30 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/svc/config.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | 6 | "{{ .Module }}/internal/config" 7 | ) 8 | 9 | func (svcCtx *ServiceContext) SetConfigListener() { 10 | svcCtx.ConfigCenter.AddListener(func() { 11 | c, err := svcCtx.ConfigCenter.GetConfig() 12 | if err != nil { 13 | logx.Errorf("reload config error: %v", err) 14 | return 15 | } 16 | 17 | logx.Infof("reload config successfully") 18 | switch c.Log.Level { 19 | case "debug": 20 | logx.SetLevel(logx.DebugLevel) 21 | case "info": 22 | logx.SetLevel(logx.InfoLevel) 23 | case "error": 24 | logx.SetLevel(logx.ErrorLevel) 25 | case "severe": 26 | logx.SetLevel(logx.SevereLevel) 27 | } 28 | 29 | // add custom logic here 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/svc/config.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | 6 | "{{ .Module }}/internal/config" 7 | ) 8 | 9 | func (svcCtx *ServiceContext) SetConfigListener() { 10 | svcCtx.ConfigCenter.AddListener(func() { 11 | c, err := svcCtx.ConfigCenter.GetConfig() 12 | if err != nil { 13 | logx.Errorf("reload config error: %v", err) 14 | return 15 | } 16 | 17 | logx.Infof("reload config successfully") 18 | switch c.Log.Level { 19 | case "debug": 20 | logx.SetLevel(logx.DebugLevel) 21 | case "info": 22 | logx.SetLevel(logx.InfoLevel) 23 | case "error": 24 | logx.SetLevel(logx.ErrorLevel) 25 | case "severe": 26 | logx.SetLevel(logx.SevereLevel) 27 | } 28 | 29 | // add custom logic here 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/middleware_http.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/zeromicro/go-zero/core/logx" 8 | ) 9 | 10 | func {{.Name | FirstUpper}}Middleware(next http.HandlerFunc) http.HandlerFunc { 11 | return func(writer http.ResponseWriter, request *http.Request) { 12 | if MatchRoute("{{.Name}}", fmt.Sprintf("%s:%s",request.Method,request.URL.Path)) { 13 | // do something before middleware 14 | logx.WithContext(request.Context()).Info("enter {{.Name}} before middleware") 15 | } 16 | next.ServeHTTP(writer, request) 17 | if MatchRoute("{{.Name}}", fmt.Sprintf("%s:%s",request.Method,request.URL.Path)) { 18 | // do something after middleware 19 | logx.WithContext(request.Context()).Info("enter {{.Name}} after middleware") 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/mongo/model_custom.tpl: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/jzero-io/jzero/core/stores/monx" 6 | ) 7 | 8 | const {{.Type}}CollectionName = "{{.snakeType}}" 9 | 10 | var _ {{.Type}}Model = (*custom{{.Type}}Model)(nil) 11 | 12 | type ( 13 | // {{.Type}}Model is an interface to be customized, add more methods here, 14 | // and implement the added methods in custom{{.Type}}Model. 15 | {{.Type}}Model interface { 16 | {{.lowerType}}Model 17 | } 18 | 19 | custom{{.Type}}Model struct { 20 | *default{{.Type}}Model 21 | } 22 | ) 23 | 24 | // New{{.Type}}Model returns a model for the mongo. 25 | func New{{.Type}}Model(url, db string, op ...opts.Opt[monx.MonOpts]) {{.Type}}Model { 26 | return &custom{{.Type}}Model{ 27 | default{{.Type}}Model: newDefault{{.Type}}Model(url, db, op...), 28 | } 29 | } -------------------------------------------------------------------------------- /docs/src/guide/migrate.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 数据库迁移指南 3 | icon: carbon:migrate 4 | star: true 5 | order: 5.5 6 | --- 7 | 8 | * jzero 基于 [migrate](https://github.com/golang-migrate/migrate) 实现数据库迁移能力 9 | * jzero 默认检测 desc/sql_migration 目录下的文件, 执行迁移 10 | * 参考 [最佳实践](https://github.com/golang-migrate/migrate/blob/master/MIGRATIONS.md) 如何编写数据库迁移文件 11 | 12 | ## 配置 13 | 14 | ```yaml 15 | migrate: 16 | driver: "mysql" 17 | datasource-url: "root:123456@tcp(127.0.0.1:3306)/jzero-admin" 18 | ``` 19 | 20 | ## 升级 21 | 22 | ```shell 23 | # 默认升级到最新 24 | jzero migrate up 25 | # 升级 n 个 migrations 26 | jzero migrate up 3 27 | ``` 28 | 29 | ## 回滚 30 | 31 | ```shell 32 | # 默认回滚所有 33 | jzero migrate down 34 | # 回滚 n 个 migrations 35 | jzero migrate down 3 36 | ``` 37 | 38 | ## 获取版本 39 | 40 | ```shell 41 | jzero migrate version 42 | ``` 43 | 44 | ## 强制回滚到某个版本 45 | 46 | ```shell 47 | jzero migrate goto 48 | ``` -------------------------------------------------------------------------------- /cmd/jzero/internal/command/migrate/migrategoto/migrategoto.go: -------------------------------------------------------------------------------- 1 | package migrategoto 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/spf13/cast" 7 | "github.com/zeromicro/go-zero/core/stores/sqlx" 8 | 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/migrate" 11 | ) 12 | 13 | func Run(args []string) error { 14 | m, err := migrate.NewMigrate(sqlx.SqlConf{ 15 | DataSource: config.C.Migrate.DataSourceUrl, 16 | DriverName: config.C.Migrate.Driver, 17 | }, 18 | migrate.WithXMigrationsTable(config.C.Migrate.XMigrationsTable), 19 | migrate.WithSource(config.C.Migrate.Source), 20 | migrate.WithSourceAppendDriver(config.C.Migrate.SourceAppendDriver)) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | if len(args) <= 0 { 26 | return errors.New("step must be greater than 0") 27 | } 28 | return m.Goto(cast.ToUint(args[0])) 29 | } 30 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/template/templatebuild/filter.go: -------------------------------------------------------------------------------- 1 | package templatebuild 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "github.com/moby/patternmatcher" 8 | ) 9 | 10 | func filter(dir, name string, matcher *patternmatcher.PatternMatcher) bool { 11 | pwd, err := os.Getwd() 12 | if err != nil { 13 | return true 14 | } 15 | target := filepath.Join(dir, name) 16 | relFilePath, err := filepath.Rel(pwd, target) 17 | if err != nil { 18 | return true 19 | } 20 | skip, err := filepathMatches(matcher, relFilePath) 21 | if err != nil || skip { 22 | return true 23 | } 24 | return false 25 | } 26 | 27 | func filepathMatches(matcher *patternmatcher.PatternMatcher, file string) (bool, error) { 28 | file = filepath.Clean(file) 29 | if file == "." { 30 | // Don't let them exclude everything, kind of silly. 31 | return false, nil 32 | } 33 | return matcher.MatchesOrParentMatches(file) 34 | } 35 | -------------------------------------------------------------------------------- /cmd/jzero/.template/client/zrpcclient-go/plugins.go.tpl: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/zrpc" 5 | ) 6 | 7 | type Plugins interface { 8 | {{range $pluginName := .PluginNames}} {{$pluginName | ToCamel | FirstUpper}}() {{$pluginName | ToCamel | FirstUpper}} 9 | {{end}} 10 | } 11 | 12 | type plugins struct { 13 | {{range $pluginName := .PluginNames}} {{$pluginName | ToCamel | FirstLower}} {{$pluginName | ToCamel | FirstUpper}} 14 | {{end}} 15 | } 16 | 17 | {{range $pluginName := .PluginNames}}func (p *plugins) {{$pluginName | ToCamel | FirstUpper}}() {{$pluginName | ToCamel | FirstUpper}} { 18 | return p.{{$pluginName | ToCamel | FirstLower}} 19 | } 20 | 21 | {{end}} 22 | 23 | func NewPlugins(conn zrpc.Client) Plugins { 24 | return &plugins{ 25 | {{range $pluginName := .PluginNames}} {{$pluginName | ToCamel | FirstLower}}: New{{$pluginName | ToCamel | FirstUpper}}(conn), 26 | {{end}} 27 | } 28 | } -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/templatex/template.go: -------------------------------------------------------------------------------- 1 | package templatex 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "text/template" 7 | 8 | "github.com/Masterminds/sprig/v3" 9 | 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 11 | ) 12 | 13 | // ParseTemplate template 14 | func ParseTemplate(name string, data map[string]any, tplT []byte) ([]byte, error) { 15 | var err error 16 | t := template.New(name).Funcs(sprig.TxtFuncMap()) 17 | t.Funcs(registerFuncMap) 18 | 19 | t, err = t.Parse(string(tplT)) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | t.Funcs(registerFuncMap) 25 | 26 | buf := new(bytes.Buffer) 27 | 28 | for _, v := range config.C.RegisterTplVal { 29 | split := strings.Split(v, "=") 30 | if len(split) == 2 { 31 | data[split[0]] = split[1] 32 | } 33 | } 34 | 35 | err = t.Execute(buf, data) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return buf.Bytes(), err 40 | } 41 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/upgrade/upgrade.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 jaronnie 3 | 4 | */ 5 | 6 | package upgrade 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/zeromicro/go-zero/tools/goctl/pkg/golang" 13 | 14 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 15 | ) 16 | 17 | var upgradeCmd = &cobra.Command{ 18 | Use: "upgrade", 19 | Short: `Upgrade the version of jzero tool.`, 20 | RunE: func(cmd *cobra.Command, args []string) error { 21 | switch config.C.Upgrade.Channel { 22 | case "stable": 23 | return golang.Install("github.com/jzero-io/jzero/cmd/jzero@latest") 24 | default: 25 | return golang.Install(fmt.Sprintf("github.com/jzero-io/jzero/cmd/jzero@%s", config.C.Upgrade.Channel)) 26 | } 27 | }, 28 | } 29 | 30 | func GetCommand() *cobra.Command { 31 | upgradeCmd.Flags().StringP("channel", "c", "stable", "channel to upgrade jzero") 32 | return upgradeCmd 33 | } 34 | -------------------------------------------------------------------------------- /core/slicex/slicex_test.go: -------------------------------------------------------------------------------- 1 | package slicex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | type Data struct { 10 | Id int 11 | Name string 12 | } 13 | 14 | var datas = []Data{ 15 | {Id: 1, Name: "a"}, 16 | {Id: 2, Name: "b"}, 17 | {Id: 3, Name: "c"}, 18 | } 19 | 20 | func TestPaginate(t *testing.T) { 21 | paginate := Paginate[Data](datas, 1, 3) 22 | assert.Equal(t, 3, len(paginate)) 23 | assert.Equal(t, "a", paginate[0].Name) 24 | assert.Equal(t, "b", paginate[1].Name) 25 | assert.Equal(t, "c", paginate[2].Name) 26 | 27 | paginate = Paginate[Data](datas, 2, 3) 28 | assert.Equal(t, 0, len(paginate)) 29 | } 30 | 31 | func TestToMap(t *testing.T) { 32 | toMap := ToMap(datas, func(row Data) int { 33 | return row.Id 34 | }) 35 | 36 | assert.Equal(t, 3, len(toMap)) 37 | assert.Equal(t, "a", toMap[1].Name) 38 | assert.Equal(t, "b", toMap[2].Name) 39 | assert.Equal(t, "c", toMap[3].Name) 40 | } 41 | -------------------------------------------------------------------------------- /core/middleware/fuzzy/request.go: -------------------------------------------------------------------------------- 1 | package fuzzy 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "net/http" 7 | "strings" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | func DecodeRequest(r *http.Request, req any) error { 13 | if r.Body == nil { 14 | return nil 15 | } 16 | 17 | if r.Method != http.MethodPost && r.Method != http.MethodPut { 18 | return nil 19 | } 20 | 21 | if !strings.Contains(r.Header.Get("Content-Type"), "application/json") { 22 | return nil 23 | } 24 | 25 | bodyBytes, err := io.ReadAll(r.Body) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | if err = r.Body.Close(); err != nil { 31 | return err 32 | } 33 | 34 | bodyBytes, err = Decode(bodyBytes, req) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) 40 | r.ContentLength = int64(len(bodyBytes)) 41 | 42 | logx.Debugf("new request body bytes: %s", bodyBytes) 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/migrate/migratedown/migratedown.go: -------------------------------------------------------------------------------- 1 | package migratedown 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/spf13/cast" 7 | "github.com/zeromicro/go-zero/core/stores/sqlx" 8 | 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/migrate" 11 | ) 12 | 13 | func Run(args []string) error { 14 | m, err := migrate.NewMigrate(sqlx.SqlConf{ 15 | DataSource: config.C.Migrate.DataSourceUrl, 16 | DriverName: config.C.Migrate.Driver, 17 | }, 18 | migrate.WithXMigrationsTable(config.C.Migrate.XMigrationsTable), 19 | migrate.WithSource(config.C.Migrate.Source), 20 | migrate.WithSourceAppendDriver(config.C.Migrate.SourceAppendDriver)) 21 | if err != nil { 22 | return err 23 | } 24 | 25 | if len(args) > 0 { 26 | if cast.ToInt(args[0]) < 0 { 27 | return errors.New("step must be greater than 0") 28 | } 29 | return m.Down(cast.ToUint(args[0])) 30 | } 31 | 32 | return m.Down() 33 | } 34 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/migrate/migrateup/migrateup.go: -------------------------------------------------------------------------------- 1 | package migrateup 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | "github.com/spf13/cast" 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | 8 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/migrate" 10 | ) 11 | 12 | func Run(args []string) error { 13 | m, err := migrate.NewMigrate(sqlx.SqlConf{ 14 | DataSource: config.C.Migrate.DataSourceUrl, 15 | DriverName: config.C.Migrate.Driver, 16 | }, 17 | migrate.WithXMigrationsTable(config.C.Migrate.XMigrationsTable), 18 | migrate.WithSource(config.C.Migrate.Source), 19 | migrate.WithSourceAppendDriver(config.C.Migrate.SourceAppendDriver)) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | if len(args) > 0 { 25 | if cast.ToInt(args[0]) < 0 { 26 | return errors.New("step must be greater than 0") 27 | } 28 | return m.Up(cast.ToUint(args[0])) 29 | } 30 | 31 | return m.Up() 32 | } 33 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/migrate/migrateversion/migrateversion.go: -------------------------------------------------------------------------------- 1 | package migrateversion 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | 8 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/migrate" 10 | ) 11 | 12 | func Run(args []string) error { 13 | m, err := migrate.NewMigrate(sqlx.SqlConf{ 14 | DataSource: config.C.Migrate.DataSourceUrl, 15 | DriverName: config.C.Migrate.Driver, 16 | }, 17 | migrate.WithXMigrationsTable(config.C.Migrate.XMigrationsTable), 18 | migrate.WithSource(config.C.Migrate.Source), 19 | migrate.WithSourceAppendDriver(config.C.Migrate.SourceAppendDriver)) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | version, dirty, err := m.Version() 25 | if err != nil { 26 | return err 27 | } 28 | 29 | if dirty { 30 | fmt.Printf("%v (dirty)\n", version) 31 | } else { 32 | fmt.Printf("%v\n", version) 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | 7 | builds: 8 | - env: 9 | - CGO_ENABLED=0 10 | goos: 11 | - linux 12 | - windows 13 | - darwin 14 | goarch: 15 | - amd64 16 | - arm64 17 | dir: ./cmd/jzero 18 | id: jzero 19 | binary: jzero 20 | 21 | archives: 22 | - formats: [tar.gz] 23 | # this name template makes the OS and Arch compatible with the results of `uname`. 24 | name_template: >- 25 | {{ .ProjectName }}_ 26 | {{- title .Os }}_ 27 | {{- if eq .Arch "amd64" }}x86_64 28 | {{- else if eq .Arch "386" }}i386 29 | {{- else }}{{ .Arch }}{{ end }} 30 | {{- if .Arm }}v{{ .Arm }}{{ end }} 31 | # use zip for windows archives 32 | format_overrides: 33 | - goos: windows 34 | formats: [zip] 35 | 36 | changelog: 37 | sort: asc 38 | filters: 39 | exclude: 40 | - "^docs:" 41 | - "^test:" 42 | 43 | force_token: github 44 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/pb/embed.go.tpl: -------------------------------------------------------------------------------- 1 | package pb 2 | 3 | import ( 4 | "embed" 5 | "io/fs" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | var ( 11 | //go:embed * 12 | Embed embed.FS 13 | ) 14 | 15 | func WriteToLocal(ef embed.FS) ([]string, error) { 16 | var fileList []string 17 | 18 | err := fs.WalkDir(ef, ".", func(path string, d fs.DirEntry, err error) error { 19 | if err != nil { 20 | return err 21 | } 22 | if !d.IsDir() && filepath.Ext(path) == ".pb" { 23 | data, err := ef.ReadFile(path) 24 | if err != nil { 25 | return err 26 | } 27 | pbPath := filepath.Join("desc", "pb", path) 28 | fileList = append(fileList, pbPath) 29 | if err := os.MkdirAll(filepath.Dir(pbPath), 0o755); err != nil { 30 | return err 31 | } 32 | if err := os.WriteFile(pbPath, data, 0o644); err != nil { 33 | return err 34 | } 35 | } 36 | return nil 37 | }) 38 | if err != nil { 39 | return nil, err 40 | } 41 | return fileList, nil 42 | } 43 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/api/logic.tpl: -------------------------------------------------------------------------------- 1 | package {{.pkgName}} 2 | 3 | import ( 4 | "net/http" 5 | 6 | {{.imports}} 7 | ) 8 | 9 | type {{.logic}} struct { 10 | logx.Logger 11 | ctx context.Context 12 | svcCtx *svc.ServiceContext 13 | r *http.Request 14 | {{if eq .responseType "error"}}w http.ResponseWriter{{end}} 15 | } 16 | 17 | {{if .hasDoc}}{{.doc}}{{end}} 18 | func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request, {{if eq .responseType "error"}}w http.ResponseWriter{{end}}) *{{.logic}} { 19 | return &{{.logic}}{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | r: r, 24 | {{if eq .responseType "error"}}w: w,{{end}} 25 | } 26 | } 27 | 28 | func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} { 29 | // todo: add your logic here and delete this line 30 | 31 | {{.returnString}} 32 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/model-new.tpl: -------------------------------------------------------------------------------- 1 | func new{{.upperStartCamelObject}}Model(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) *default{{.upperStartCamelObject}}Model { 2 | o := opts.DefaultApply(op...) 3 | var cachedConn sqlc.CachedConn 4 | if len(o.CacheConf) > 0 { 5 | cachedConn = sqlc.NewConn(conn, o.CacheConf, o.CacheOpts...) 6 | } 7 | if o.CachedConn != nil { 8 | cachedConn = *o.CachedConn 9 | } 10 | 11 | init{{.upperStartCamelObject}}Vars(o.Flavor) 12 | 13 | return &default{{.upperStartCamelObject}}Model{ 14 | cachedConn: cachedConn, 15 | conn: conn, 16 | flavor: o.Flavor, 17 | table: condition.QuoteWithFlavor(o.Flavor, "{{.data.Name.Source}}"), 18 | } 19 | } 20 | 21 | func (m *default{{.upperStartCamelObject}}Model) clone() *default{{.upperStartCamelObject}}Model { 22 | return &default{{.upperStartCamelObject}}Model{ 23 | cachedConn: m.cachedConn, 24 | conn: m.conn, 25 | table: m.table, 26 | flavor: m.flavor, 27 | } 28 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/logic/version/version.go.tpl: -------------------------------------------------------------------------------- 1 | {{if .Serverless}}{{else}}package version 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "os" 7 | "runtime" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | 11 | "{{.Module}}/internal/svc" 12 | types "{{.Module}}/internal/types/version" 13 | ) 14 | 15 | type Version struct { 16 | logx.Logger 17 | ctx context.Context 18 | svcCtx *svc.ServiceContext 19 | r *http.Request 20 | } 21 | 22 | func NewVersion(ctx context.Context, svcCtx *svc.ServiceContext, r *http.Request) *Version { 23 | return &Version{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | r: r, 28 | } 29 | } 30 | 31 | func (l *Version) Version(req *types.VersionRequest) (resp *types.VersionResponse, err error) { 32 | return &types.VersionResponse{ 33 | Version: os.Getenv("VERSION"), 34 | GoVersion: runtime.Version(), 35 | Commit: os.Getenv("COMMIT"), 36 | Date: os.Getenv("DATE"), 37 | }, nil 38 | }{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/serverless/serverless.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}package serverless 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/jzero-io/jzero/core/configcenter" 7 | "github.com/jzero-io/jzero/core/configcenter/subscriber" 8 | "google.golang.org/grpc" 9 | 10 | "{{ .Module }}/internal/config" 11 | "{{ .Module }}/internal/server" 12 | "{{ .Module }}/internal/svc" 13 | ) 14 | 15 | type Serverless struct { 16 | SvcCtx *svc.ServiceContext // 服务上下文 17 | RegisterZrpcServer func(grpcServer *grpc.Server, ctx *svc.ServiceContext) 18 | } 19 | 20 | func New() *Serverless { 21 | cc := configcenter.MustNewConfigCenter[config.Config](configcenter.Config{ 22 | Type: "yaml", 23 | }, subscriber.MustNewFsnotifySubscriber(filepath.Join("plugins", "{{ .DirName }}", "etc", "etc.yaml"), subscriber.WithUseEnv(true))) 24 | 25 | svcCtx := svc.NewServiceContext(cc) 26 | 27 | return &Serverless{ 28 | SvcCtx: svcCtx, 29 | RegisterZrpcServer: server.RegisterZrpcServer, 30 | } 31 | }{{end}} -------------------------------------------------------------------------------- /core/stores/cache/redis_test.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/alicebob/miniredis/v2" 8 | "github.com/pkg/errors" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/zeromicro/go-zero/core/stores/redis" 11 | ) 12 | 13 | func TestRedisNode(t *testing.T) { 14 | r, err := miniredis.Run() 15 | assert.NoError(t, err) 16 | defer r.Close() 17 | 18 | cache := NewRedisNode(redis.New(r.Addr()), errors.New("not found")) 19 | 20 | err = cache.SetCtx(context.Background(), "JWT_ADMIN_AUTH:1:abc", "abc") 21 | assert.NoError(t, err) 22 | 23 | err = cache.SetCtx(context.Background(), "JWT_ADMIN_AUTH:1:def", "def") 24 | assert.NoError(t, err) 25 | 26 | err = cache.SetCtx(context.Background(), "JWT_ADMIN_AUTH:1:ghi", "ghi") 27 | assert.NoError(t, err) 28 | 29 | keys, err := cache.GetPrefixKeysCtx(context.Background(), "JWT_ADMIN_AUTH:1:") 30 | assert.NoError(t, err) 31 | 32 | assert.Equal(t, []string{"JWT_ADMIN_AUTH:1:abc", "JWT_ADMIN_AUTH:1:def", "JWT_ADMIN_AUTH:1:ghi"}, keys) 33 | } 34 | -------------------------------------------------------------------------------- /core/stores/condition/update_field_test.go: -------------------------------------------------------------------------------- 1 | package condition 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/huandu/go-sqlbuilder" 8 | ) 9 | 10 | func TestSetUpdateFields(t *testing.T) { 11 | builder := SetUpdateFieldsWithFlavor(sqlbuilder.MySQL, *sqlbuilder.NewUpdateBuilder().Update("users"), map[string]any{ 12 | "age": UpdateField{ 13 | Operator: Add, 14 | Value: 12, 15 | }, 16 | "version": UpdateField{ 17 | Operator: Incr, 18 | }, 19 | "name": "jaronnie", 20 | }) 21 | 22 | sql, args := builder.Build() 23 | fmt.Println(sql) 24 | fmt.Println(args) 25 | } 26 | 27 | func TestSetUpdateFieldChain(t *testing.T) { 28 | builder := SetUpdateFieldsWithFlavor(sqlbuilder.MySQL, *sqlbuilder.NewUpdateBuilder().Update("users"), NewUpdateFieldChain(). 29 | Assign("name", "jaronnie", WithUpdateFieldSkip(true)). 30 | Incr("version"). 31 | Add("age", 12, WithUpdateFieldValueFunc(func() any { 32 | return 15 33 | })). 34 | Build()) 35 | 36 | sql, args := builder.Build() 37 | fmt.Println(sql) 38 | fmt.Println(args) 39 | } 40 | -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/server.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package server 4 | 5 | import ( 6 | "github.com/zeromicro/go-zero/core/service" 7 | "github.com/zeromicro/go-zero/zrpc" 8 | "google.golang.org/grpc" 9 | "google.golang.org/grpc/reflection" 10 | 11 | "{{ .Module }}/internal/config" 12 | "{{ .Module }}/internal/svc"{{ if .ServerImports }}{{ .ServerImports }}{{ end }}{{ if .PbImports }}{{ .PbImports }}{{ end }} 13 | ) 14 | 15 | // RegisterZrpc Deprecated: use RegisterZrpcServer instead. 16 | func RegisterZrpc(c config.Config, ctx *svc.ServiceContext) *zrpc.RpcServer { 17 | s := zrpc.MustNewServer(c.Zrpc.RpcServerConf, func(grpcServer *grpc.Server) { 18 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 19 | 20 | if c.Zrpc.Mode == service.DevMode || c.Zrpc.Mode == service.TestMode { 21 | reflection.Register(grpcServer) 22 | } 23 | }) 24 | 25 | return s 26 | } 27 | 28 | func RegisterZrpcServer(grpcServer *grpc.Server, ctx *svc.ServiceContext) { 29 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 30 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/middleware/validator.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "reflect" 6 | 7 | "github.com/go-playground/validator/v10" 8 | ) 9 | 10 | type Validator struct { 11 | instance *validator.Validate 12 | } 13 | 14 | func NewValidator() *Validator { 15 | validate := validator.New() 16 | validate.RegisterTagNameFunc(func(field reflect.StructField) string { 17 | return getLabelValue(field) 18 | }) 19 | 20 | return &Validator{ 21 | instance: validate, 22 | } 23 | } 24 | 25 | func (v *Validator) Validate(r *http.Request, data any) (err error) { 26 | err = v.instance.Struct(data) 27 | if err != nil { 28 | for _, ve := range err.(validator.ValidationErrors) { 29 | return ve 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func getLabelValue(field reflect.StructField) string { 36 | tags := []string{"header", "json", "form", "path"} 37 | label := "" 38 | 39 | for _, tag := range tags { 40 | label = field.Tag.Get(tag) 41 | if label != "" { 42 | return label 43 | } 44 | } 45 | return "" 46 | } 47 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/Makefile.tpl: -------------------------------------------------------------------------------- 1 | ORGANIZATION = "organization" 2 | APP = "{{ .APP }}" 3 | 4 | VERSION := $(shell git describe --tags --always --match='v*' 2>/dev/null) 5 | ifeq ($(VERSION),) 6 | VERSION = "latest" 7 | endif 8 | 9 | COMMIT = $(shell git rev-parse --short HEAD 2>/dev/null) 10 | ifeq ($(COMMIT),) 11 | COMMIT = "" 12 | endif 13 | 14 | DATE = `date "+%Y-%m-%d %H:%M:%S"` 15 | ARCH = `go env GOARCH` 16 | 17 | .PHONY: build 18 | build: 19 | @go build -ldflags "-X '{{ .Module }}/cmd.Date=$(DATE)' -X '{{ .Module }}/cmd.Version=$(VERSION)' -X '{{ .Module }}/cmd.Commit=$(COMMIT)'" -o $(APP) main.go 20 | 21 | .PHONY: docker 22 | docker: 23 | @docker buildx build --platform linux/$(ARCH) --progress=plain -t $(ORGANIZATION)/$(APP):$(VERSION) . --load 24 | 25 | .PHONY: push 26 | push: 27 | @docker buildx create --use --name=mybuilder --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master 2> /dev/null || true 28 | @docker buildx build --platform linux/amd64,linux/arm64 --progress=plain -t $(ORGANIZATION)/$(APP):$(VERSION) . --push -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: jzero-ci 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'docs/**' 7 | - '**.md' 8 | pull_request: 9 | 10 | jobs: 11 | golangci: 12 | name: ci 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v6 17 | with: 18 | fetch-depth: 0 19 | 20 | - uses: actions/setup-go@v6 21 | with: 22 | go-version: '1.24.3' 23 | 24 | - name: Install Tool 25 | run: | 26 | cd cmd/jzero 27 | go install 28 | jzero check 29 | 30 | - name: format go 31 | run: | 32 | jzero format -d --git-change=false 33 | 34 | - uses: actions/checkout@v6 35 | - name: golangci-lint 36 | uses: golangci/golangci-lint-action@v9 37 | with: 38 | version: latest 39 | working-directory: ${{ matrix.workdir }} 40 | skip-go-installation: true 41 | skip-pkg-cache: true 42 | 43 | - name: run test case 44 | run: | 45 | go test ./... -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/server/server.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package server 4 | 5 | import ( 6 | "github.com/zeromicro/go-zero/core/service" 7 | "github.com/zeromicro/go-zero/zrpc" 8 | "google.golang.org/grpc" 9 | "google.golang.org/grpc/reflection" 10 | 11 | "{{ .Module }}/internal/config" 12 | "{{ .Module }}/internal/svc"{{ if .ServerImports }}{{ .ServerImports }}{{ end }}{{ if .PbImports }}{{ .PbImports }}{{ end }} 13 | ) 14 | 15 | // RegisterZrpc Deprecated: use RegisterZrpcServer instead. 16 | func RegisterZrpc(c config.Config, ctx *svc.ServiceContext) *zrpc.RpcServer { 17 | s := zrpc.MustNewServer(c.Zrpc.RpcServerConf, func(grpcServer *grpc.Server) { 18 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 19 | 20 | if c.Zrpc.Mode == service.DevMode || c.Zrpc.Mode == service.TestMode { 21 | reflection.Register(grpcServer) 22 | } 23 | }) 24 | 25 | return s 26 | } 27 | 28 | func RegisterZrpcServer(grpcServer *grpc.Server, ctx *svc.ServiceContext) { 29 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 30 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/server/server.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package server 4 | 5 | import ( 6 | "github.com/zeromicro/go-zero/core/service" 7 | "github.com/zeromicro/go-zero/zrpc" 8 | "google.golang.org/grpc" 9 | "google.golang.org/grpc/reflection" 10 | 11 | "{{ .Module }}/internal/config" 12 | "{{ .Module }}/internal/svc"{{ if .ServerImports }}{{ .ServerImports }}{{ end }}{{ if .PbImports }}{{ .PbImports }}{{ end }} 13 | ) 14 | 15 | // RegisterZrpc Deprecated: use RegisterZrpcServer instead. 16 | func RegisterZrpc(c config.Config, ctx *svc.ServiceContext) *zrpc.RpcServer { 17 | s := zrpc.MustNewServer(c.Zrpc.RpcServerConf, func(grpcServer *grpc.Server) { 18 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 19 | 20 | if c.Zrpc.Mode == service.DevMode || c.Zrpc.Mode == service.TestMode { 21 | reflection.Register(grpcServer) 22 | } 23 | }) 24 | 25 | return s 26 | } 27 | 28 | func RegisterZrpcServer(grpcServer *grpc.Server, ctx *svc.ServiceContext) { 29 | {{ if .RegisterServers }}{{ .RegisterServers }}{{ end }} 30 | } -------------------------------------------------------------------------------- /core/status/status_test.go: -------------------------------------------------------------------------------- 1 | package status 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "github.com/pkg/errors" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | const ( 12 | GetUserListError = Code(28001) 13 | ) 14 | 15 | func TestError(t *testing.T) { 16 | err := Error(GetUserListError) 17 | status := FromError(err) 18 | assert.Equal(t, GetUserListError, status.Code()) 19 | assert.Equal(t, "get user list error", status.Message()) 20 | } 21 | 22 | func TestUnknownError(t *testing.T) { 23 | err := Error(28000) 24 | 25 | status := FromError(err) 26 | assert.Equal(t, http.StatusInternalServerError, int(status.Code())) 27 | } 28 | 29 | func TestWrap(t *testing.T) { 30 | err := Wrap(GetUserListError, errors.New("connect to db error")) 31 | status := FromError(err) 32 | assert.Equal(t, GetUserListError, status.Code()) 33 | assert.Equal(t, "get user list error: connect to db error", status.Error()) 34 | assert.Equal(t, "connect to db error", status.Unwrap().Error()) 35 | } 36 | 37 | func init() { 38 | RegisterWithMessage(GetUserListError, "get user list error") 39 | } 40 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/model.tpl: -------------------------------------------------------------------------------- 1 | package {{.pkg}} 2 | import ( 3 | "github.com/zeromicro/go-zero/core/stores/sqlx" 4 | "github.com/jzero-io/jzero/core/stores/modelx" 5 | "github.com/eddieowens/opts" 6 | ) 7 | 8 | var _ {{.upperStartCamelObject}}Model = (*custom{{.upperStartCamelObject}}Model)(nil) 9 | 10 | type ( 11 | // {{.upperStartCamelObject}}Model is an interface to be customized, add more methods here, 12 | // and implement the added methods in custom{{.upperStartCamelObject}}Model. 13 | {{.upperStartCamelObject}}Model interface { 14 | {{.lowerStartCamelObject}}Model 15 | } 16 | 17 | custom{{.upperStartCamelObject}}Model struct { 18 | *default{{.upperStartCamelObject}}Model 19 | } 20 | ) 21 | 22 | // New{{.upperStartCamelObject}}Model returns a model for the database table. 23 | func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) {{.upperStartCamelObject}}Model { 24 | return &custom{{.upperStartCamelObject}}Model{ 25 | default{{.upperStartCamelObject}}Model: new{{.upperStartCamelObject}}Model(conn, op...), 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/var.tpl: -------------------------------------------------------------------------------- 1 | var ( 2 | {{.lowerStartCamelObject}}FieldNames []string 3 | {{.lowerStartCamelObject}}Rows string 4 | {{.lowerStartCamelObject}}RowsExpectAutoFieldNames []string 5 | {{.lowerStartCamelObject}}RowsExpectAutoSet string 6 | 7 | {{if .withCache}}{{.cacheKeys}}{{end}} 8 | ) 9 | 10 | const ( 11 | {{range $index, $v := .data.Fields}}{{$v.Name.ToCamel}} condition.Field = "{{$v.NameOriginal}}" 12 | {{end}} 13 | ) 14 | 15 | func init{{.upperStartCamelObject}}Vars(flavor sqlbuilder.Flavor) { 16 | {{.lowerStartCamelObject}}FieldNames = condition.RawFieldNamesWithFlavor(flavor, &{{.upperStartCamelObject}}{}) 17 | {{.lowerStartCamelObject}}Rows = strings.Join({{.lowerStartCamelObject}}FieldNames, ",") 18 | {{.lowerStartCamelObject}}RowsExpectAutoFieldNames = condition.RemoveIgnoreColumnsWithFlavor(flavor, {{.lowerStartCamelObject}}FieldNames, {{if .autoIncrement}}"{{.originalPrimaryKey}}", {{end}} {{.ignoreColumns}}) 19 | {{.lowerStartCamelObject}}RowsExpectAutoSet = strings.Join({{.lowerStartCamelObject}}RowsExpectAutoFieldNames, ",") 20 | } 21 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/config/config.go.tpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | "github.com/zeromicro/go-zero/rest" 6 | {{ if has "model" .Features }}"github.com/zeromicro/go-zero/core/stores/sqlx"{{ end }} 7 | {{ if has "redis" .Features }}"github.com/zeromicro/go-zero/core/stores/redis"{{ end }} 8 | ) 9 | 10 | type Config struct { 11 | Rest RestConf 12 | Log LogConf 13 | {{ if has "model" .Features }}Sqlx SqlxConf{{ end }} 14 | {{ if has "redis" .Features }}Redis RedisConf{{ end }} 15 | Banner BannerConf 16 | } 17 | 18 | type RestConf struct { 19 | rest.RestConf 20 | } 21 | 22 | type LogConf struct { 23 | logx.LogConf 24 | } 25 | 26 | {{ if has "model" .Features }}type SqlxConf struct { 27 | sqlx.SqlConf 28 | }{{ end }} 29 | {{ if has "redis" .Features }}type RedisConf struct { 30 | redis.RedisConf 31 | }{{ end }} 32 | 33 | type BannerConf struct { 34 | Text string `json:",default=JZERO"` 35 | Color string `json:",default=green"` 36 | FontName string `json:",default=starwars,options=big|larry3d|starwars|standard"` 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 jzero-io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/svc/config.go.tpl: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | 6 | "{{ .Module }}/internal/config" 7 | ) 8 | 9 | func (svcCtx *ServiceContext) GetConfig() (config.Config, error) { 10 | return svcCtx.ConfigCenter.GetConfig() 11 | } 12 | 13 | func (svcCtx *ServiceContext) MustGetConfig() config.Config { 14 | return svcCtx.ConfigCenter.MustGetConfig() 15 | } 16 | 17 | func (svcCtx *ServiceContext) SetConfigListener() { 18 | svcCtx.ConfigCenter.AddListener(func() { 19 | c, err := svcCtx.ConfigCenter.GetConfig() 20 | if err != nil { 21 | logx.Errorf("reload config error: %v", err) 22 | return 23 | } 24 | 25 | logx.Infof("reload config successfully") 26 | switch c.Log.Level { 27 | case "debug": 28 | logx.SetLevel(logx.DebugLevel) 29 | case "info": 30 | logx.SetLevel(logx.InfoLevel) 31 | case "error": 32 | logx.SetLevel(logx.ErrorLevel) 33 | case "severe": 34 | logx.SetLevel(logx.SevereLevel) 35 | } 36 | 37 | // add custom logic here 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/config/config.go.tpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | "github.com/zeromicro/go-zero/zrpc" 6 | {{ if has "model" .Features }}"github.com/zeromicro/go-zero/core/stores/sqlx"{{ end }} 7 | {{ if has "redis" .Features }}"github.com/zeromicro/go-zero/core/stores/redis"{{ end }} 8 | ) 9 | 10 | type Config struct { 11 | Zrpc ZrpcConf 12 | Log LogConf 13 | {{ if has "model" .Features }}Sqlx SqlxConf{{ end }} 14 | {{ if has "redis" .Features }}Redis RedisConf{{ end }} 15 | Banner BannerConf 16 | } 17 | 18 | type ZrpcConf struct { 19 | zrpc.RpcServerConf 20 | } 21 | 22 | type LogConf struct { 23 | logx.LogConf 24 | } 25 | 26 | {{ if has "model" .Features }}type SqlxConf struct { 27 | sqlx.SqlConf 28 | }{{ end }} 29 | {{ if has "redis" .Features }}type RedisConf struct { 30 | redis.RedisConf 31 | }{{ end }} 32 | 33 | type BannerConf struct { 34 | Text string `json:",default=JZERO"` 35 | Color string `json:",default=green"` 36 | FontName string `json:",default=starwars,options=big|larry3d|starwars|standard"` 37 | } 38 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/serverless/serverless.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}package serverless 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/jzero-io/jzero/core/configcenter" 7 | "github.com/jzero-io/jzero/core/configcenter/subscriber" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | "github.com/zeromicro/go-zero/rest" 10 | 11 | "{{ .Module }}/internal/config" 12 | "{{ .Module }}/internal/handler" 13 | "{{ .Module }}/internal/svc" 14 | ) 15 | 16 | type Serverless struct { 17 | SvcCtx *svc.ServiceContext // 服务上下文 18 | HandlerFunc func(server *rest.Server, svcCtx *svc.ServiceContext) // 服务路由 19 | } 20 | 21 | // New serverless function 22 | func New() *Serverless { 23 | cc := configcenter.MustNewConfigCenter[config.Config](configcenter.Config{ 24 | Type: "yaml", 25 | }, subscriber.MustNewFsnotifySubscriber(filepath.Join("plugins", "{{ .DirName }}", "etc", "etc.yaml"), subscriber.WithUseEnv(true))) 26 | 27 | svcCtx := svc.NewServiceContext(cc) 28 | 29 | return &Serverless{ 30 | SvcCtx: svcCtx, 31 | HandlerFunc: handler.RegisterHandlers, 32 | } 33 | }{{end}} -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine 2 | 3 | ENV CGO_ENABLED=0 4 | 5 | LABEL \ 6 | org.opencontainers.image.title="jzero" \ 7 | org.opencontainers.image.description="jzero framework" \ 8 | org.opencontainers.image.url="https://github.com/jzero-io/jzero" \ 9 | org.opencontainers.image.documentation="https://github.com/jzero-io/jzero#readme" \ 10 | org.opencontainers.image.source="https://github.com/jzero-io/jzero" \ 11 | org.opencontainers.image.licenses="MIT" \ 12 | maintainer="jaronnie " 13 | 14 | WORKDIR /app 15 | 16 | COPY dist/jzero_linux_amd64_v1/jzero /dist/jzero_linux_amd64/jzero 17 | COPY dist/jzero_linux_arm64_v8.0/jzero /dist/jzero_linux_arm64/jzero 18 | 19 | RUN if [ `go env GOARCH` = "amd64" ]; then \ 20 | cp /dist/jzero_linux_amd64/jzero /usr/local/bin/jzero; \ 21 | elif [ `go env GOARCH` = "arm64" ]; then \ 22 | cp /dist/jzero_linux_arm64/jzero /usr/local/bin/jzero; \ 23 | fi 24 | 25 | RUN apk update --no-cache \ 26 | && apk add --no-cache tzdata ca-certificates protoc \ 27 | && jzero check \ 28 | && rm -rf /dist \ 29 | && rm -rf /go/pkg/mod \ 30 | && rm -rf /go/pkg/sumdb 31 | 32 | ENTRYPOINT ["jzero"] -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 jzero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 jzero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 jzero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /core/stores/modelx/modelx.go: -------------------------------------------------------------------------------- 1 | package modelx 2 | 3 | import ( 4 | "github.com/eddieowens/opts" 5 | "github.com/huandu/go-sqlbuilder" 6 | "github.com/zeromicro/go-zero/core/stores/cache" 7 | "github.com/zeromicro/go-zero/core/stores/sqlc" 8 | ) 9 | 10 | type ModelOpts struct { 11 | CachedConn *sqlc.CachedConn 12 | CacheConf cache.CacheConf 13 | CacheOpts []cache.Option 14 | Flavor sqlbuilder.Flavor 15 | } 16 | 17 | func (opts ModelOpts) DefaultOptions() ModelOpts { 18 | return ModelOpts{ 19 | Flavor: sqlbuilder.DefaultFlavor, 20 | } 21 | } 22 | 23 | func WithCachedConn(cachedConn sqlc.CachedConn) opts.Opt[ModelOpts] { 24 | return func(o *ModelOpts) { 25 | o.CachedConn = &cachedConn 26 | } 27 | } 28 | 29 | func WithCacheConf(cacheConf cache.CacheConf) opts.Opt[ModelOpts] { 30 | return func(o *ModelOpts) { 31 | o.CacheConf = cacheConf 32 | } 33 | } 34 | 35 | func WithCacheOpts(cacheOpts ...cache.Option) opts.Opt[ModelOpts] { 36 | return func(o *ModelOpts) { 37 | o.CacheOpts = cacheOpts 38 | } 39 | } 40 | 41 | func WithFlavor(flavor sqlbuilder.Flavor) opts.Opt[ModelOpts] { 42 | return func(o *ModelOpts) { 43 | o.Flavor = flavor 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/middleware/response.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/jzero-io/jzero/core/status" 8 | "github.com/pkg/errors" 9 | "github.com/spf13/cast" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type Body struct { 14 | Data any `json:"data"` 15 | Code int `json:"code"` 16 | Msg string `json:"msg"` 17 | } 18 | 19 | type OkMiddleware struct{} 20 | 21 | func NewOkMiddleware() *OkMiddleware { 22 | return &OkMiddleware{} 23 | } 24 | 25 | type ErrorMiddleware struct{} 26 | 27 | func NewErrorMiddleware() *ErrorMiddleware { 28 | return &ErrorMiddleware{} 29 | } 30 | 31 | func (e *ErrorMiddleware) Handle(ctx context.Context, err error) (int, any) { 32 | logx.WithContext(ctx).Errorf("request error: %v", err) 33 | 34 | fromError := status.FromError(err) 35 | return http.StatusOK, Body{ 36 | Data: nil, 37 | Code: int(fromError.Code()), 38 | Msg: fromError.Error(), 39 | } 40 | } 41 | 42 | func (o *OkMiddleware) Handle(_ context.Context, data any) any { 43 | return Body{ 44 | Data: data, 45 | Code: http.StatusOK, 46 | Msg: "success", 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/execx/exec.go: -------------------------------------------------------------------------------- 1 | package execx 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "os/exec" 8 | "runtime" 9 | 10 | "github.com/zeromicro/go-zero/tools/goctl/vars" 11 | ) 12 | 13 | func Run(arg, dir string, env ...string) error { 14 | goos := runtime.GOOS 15 | var cmd *exec.Cmd 16 | switch goos { 17 | case vars.OsMac, vars.OsLinux: 18 | cmd = exec.Command("sh", "-c", arg) 19 | case vars.OsWindows: 20 | cmd = exec.Command("cmd.exe", "/c", arg) 21 | default: 22 | return fmt.Errorf("unexpected os: %v", goos) 23 | } 24 | 25 | if len(dir) > 0 { 26 | cmd.Dir = dir 27 | } 28 | 29 | if len(env) > 0 { 30 | cmd.Env = append(os.Environ(), env...) 31 | } 32 | 33 | stdout, err := cmd.StdoutPipe() 34 | if err != nil { 35 | return err 36 | } 37 | 38 | stderr, err := cmd.StderrPipe() 39 | if err != nil { 40 | return err 41 | } 42 | 43 | if err := cmd.Start(); err != nil { 44 | return err 45 | } 46 | 47 | go func() { 48 | _, _ = io.Copy(os.Stdout, stdout) 49 | }() 50 | 51 | go func() { 52 | _, _ = io.Copy(os.Stderr, stderr) 53 | }() 54 | 55 | if err := cmd.Wait(); err != nil { 56 | return err 57 | } 58 | 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /docs/src/guide/template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 模版指南 3 | icon: vscode-icons:folder-type-template 4 | star: true 5 | order: 5.3 6 | --- 7 | 8 | ## 模版初始化 9 | 10 | 将jzero内嵌模版或者远程仓库的模版初始化到本地磁盘。 11 | 12 | ```shell 13 | # 初始化jzero内嵌模板到 $HOME/.jzero/templates/$Version 下, 可以修改模板后再进行新建项目 14 | jzero template init 15 | # 或者初始化模板到当前项目的 .template, jzero gen 默认会优先读取当前项目的 .template 作为模板 home 16 | jzero template init --output .template 17 | # 初始化远程仓库模板到 $HOME/.jzero/templates/remote 下, 如 gateway, 18 | jzero template init --branch gateway 19 | 20 | # 如果仍需要扩展 go-zero 的 template 21 | goctl template init --home .template/go-zero 22 | ``` 23 | 24 | ## 构建属于自己的模版 25 | 26 | ```shell 27 | # 将当前项目构建为模版,并保存到 $HOME/.jzero/templates/local 下 28 | jzero template build --name template_name 29 | ``` 30 | 31 | ## 使用自定义模版初始化项目 32 | 33 | * 指定远程仓库模板 34 | 35 | ```shell 36 | jzero new project_name --remote repo_to_your_templates --branch template_branch 37 | # 从缓存获取远程模板 38 | jzero new project_name --remote repo_to_your_templates --branch template_branch --cache 39 | ``` 40 | 41 | * 使用本地模版 42 | 43 | ```shell 44 | jzero new project_name --local template_name 45 | ``` 46 | 47 | * 使用路径模版 48 | 49 | ```shell 50 | jzero new project_name --home path_to_template 51 | ``` -------------------------------------------------------------------------------- /cmd/jzero/internal/command/add/addsql/addsql.go: -------------------------------------------------------------------------------- 1 | package addsql 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/filex" 11 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/templatex" 12 | ) 13 | 14 | func Run(args []string) error { 15 | baseDir := filepath.Join("desc", "sql") 16 | 17 | sqlName := args[0] 18 | 19 | template, err := templatex.ParseTemplate(filepath.Join("model", "template.sql.tpl"), map[string]any{ 20 | "Name": sqlName, 21 | }, embeded.ReadTemplateFile(filepath.Join("model", "template.sql.tpl"))) 22 | if err != nil { 23 | return err 24 | } 25 | 26 | if config.C.Add.Output == "file" { 27 | if filex.FileExists(filepath.Join(baseDir, sqlName+".sql")) { 28 | return fmt.Errorf("%s already exists", sqlName) 29 | } 30 | 31 | _ = os.MkdirAll(filepath.Dir(filepath.Join(baseDir, sqlName)), 0755) 32 | 33 | err = os.WriteFile(filepath.Join(baseDir, sqlName+".sql"), template, 0o644) 34 | if err != nil { 35 | return err 36 | } 37 | return nil 38 | } 39 | fmt.Println(string(template)) 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /core/middleware/fuzzy/decode.go: -------------------------------------------------------------------------------- 1 | package fuzzy 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/jaronnie/genius" 7 | jsoniter "github.com/json-iterator/go" 8 | "github.com/microcosm-cc/bluemonday" 9 | ) 10 | 11 | var ( 12 | once sync.Once 13 | EnableXssProtection bool 14 | BlueMondayPolicy = bluemonday.StrictPolicy() 15 | ) 16 | 17 | func Decode(bodyBytes []byte, req any) ([]byte, error) { 18 | once.Do(func() { 19 | RegisterFuzzyDecoders() 20 | RegisterPointerFuzzyDecoders() 21 | }) 22 | 23 | g, err := genius.NewFromRawJSON(bodyBytes) 24 | if err != nil { 25 | return nil, err 26 | } 27 | keys := g.GetAllKeys() 28 | 29 | if err := jsoniter.Unmarshal(bodyBytes, &req); err != nil { 30 | return nil, err 31 | } 32 | 33 | fuzzyDecodeBytes, err := jsoniter.Marshal(req) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | ng, err := genius.NewFromRawJSON(fuzzyDecodeBytes) 39 | if err != nil { 40 | return nil, err 41 | } 42 | nkeys := ng.GetAllKeys() 43 | 44 | if len(keys) != len(nkeys) { 45 | for _, key := range keys { 46 | if err = g.Set(key, ng.Get(key)); err != nil { 47 | return nil, err 48 | } 49 | } 50 | return g.EncodeToJSON() 51 | } 52 | return fuzzyDecodeBytes, nil 53 | } 54 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/middleware/header_processor.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/zeromicro/go-zero/gateway" 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | func WithHeaderProcessor() gateway.Option { 12 | return gateway.WithHeaderProcessor(func(header http.Header) []string { 13 | var headers []string 14 | // // You can add header from request header here 15 | // // for example 16 | // for k, v := range header { 17 | // if k == "Authorization" { 18 | // headers = append(headers, fmt.Sprintf("%s:%s", k, strings.Join(v, ";"))) 19 | // } 20 | // } 21 | return headers 22 | }) 23 | } 24 | 25 | func WithValueMiddleware(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { 26 | // md, b := metadata.FromIncomingContext(ctx) 27 | // if !b { 28 | // return handler(ctx, req) 29 | // } 30 | // // You can verify Authorization here and set user info in context value 31 | // // get Authorization 32 | // value := md.Get("Authorization") 33 | // if len(value) == 1 { 34 | // // set context value 35 | // ctx = context.WithValue(ctx, "Authorization", value[0]) 36 | // } 37 | return handler(ctx, req) 38 | } 39 | -------------------------------------------------------------------------------- /docs/src/getting-started/gen.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 生成服务端代码 3 | icon: vscode-icons:folder-type-api-opened 4 | order: 4 5 | --- 6 | 7 | jzero 根据可描述语言生成代码: 8 | * desc/api: api 可描述语言, 生成 http 服务端/客户端代码. [使用指南](../guide/api.md) 9 | * desc/proto: proto 可描述语言, 生成 grpc 服务端/客户端代码. [使用指南](../guide/proto.md) 10 | * desc/sql: sql 可描述语言, 生成数据库代码. [使用指南](../guide/model.md) 11 | * model datasource: 通过远程数据源生成数据库代码. [使用指南](../guide/model.md) 12 | * mongo: 通过指定 mongo type 生成 mongo 代码. [使用指南](../guide/mongo.md) 13 | 14 | ## 生成代码 15 | 16 | ::: code-tabs#shell 17 | 18 | @tab jzero 19 | 20 | ```bash 21 | cd your_project 22 | jzero gen 23 | ``` 24 | 25 | @tab Docker 26 | 27 | ```bash 28 | cd your_project 29 | docker run --rm -v ${PWD}:/app ghcr.io/jzero-io/jzero:latest gen 30 | ``` 31 | ::: 32 | 33 | ## 基于 git 变动生成代码 34 | 35 | ```shell 36 | jzero gen --git-change 37 | ``` 38 | 39 | ## 指定 desc 生成代码 40 | 41 | ```shell 42 | jzero gen --desc desc/api/xx.api 43 | jzero gen --desc desc/proto/xx.proto 44 | jzero gen --desc desc/sql/xx.sql 45 | ``` 46 | 47 | ## 忽略指定 desc 生成代码 48 | 49 | ```shell 50 | jzero gen --desc-ignore desc/api/xx.api 51 | jzero gen --desc-ignore desc/proto/xx.proto 52 | jzero gen --desc-ignore desc/sql/xx.sql 53 | ``` 54 | 55 | 更多用法请参阅: [jzero 指南](../guide/jzero.md) -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/desc/proto/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/templatex/function.go: -------------------------------------------------------------------------------- 1 | package templatex 2 | 3 | import ( 4 | "github.com/hashicorp/go-version" 5 | "github.com/zeromicro/go-zero/tools/goctl/util/format" 6 | 7 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/stringx" 8 | ) 9 | 10 | var registerFuncMap = map[string]any{ 11 | "FirstUpper": stringx.FirstUpper, 12 | "FirstLower": stringx.FirstLower, 13 | "ToCamel": stringx.ToCamel, 14 | "FormatStyle": FormatStyle, 15 | "VersionCompare": VersionCompare, 16 | } 17 | 18 | func FormatStyle(style string, name string) string { 19 | namingFormat, err := format.FileNamingFormat(style, name) 20 | if err != nil { 21 | panic(err) 22 | } 23 | return namingFormat 24 | } 25 | 26 | func VersionCompare(v1, action, v2 string) bool { 27 | switch action { 28 | case ">": 29 | return version.Must(version.NewVersion(v1)).GreaterThan(version.Must(version.NewVersion(v2))) 30 | case "<": 31 | return version.Must(version.NewVersion(v1)).LessThan(version.Must(version.NewVersion(v2))) 32 | case ">=": 33 | return version.Must(version.NewVersion(v1)).GreaterThanOrEqual(version.Must(version.NewVersion(v2))) 34 | case "<=": 35 | } 36 | return version.Must(version.NewVersion(v1)).GreaterThanOrEqual(version.Must(version.NewVersion(v2))) 37 | } 38 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/proto/third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/serverless/serverless.go.tpl: -------------------------------------------------------------------------------- 1 | {{ if .Serverless }}package serverless 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/jzero-io/jzero/core/configcenter" 7 | "github.com/zeromicro/go-zero/core/logx" 8 | "github.com/jzero-io/jzero/core/configcenter/subscriber" 9 | "google.golang.org/grpc" 10 | 11 | "{{ .Module }}/internal/config" 12 | "{{ .Module }}/desc/pb" 13 | "{{ .Module }}/internal/server" 14 | "{{ .Module }}/internal/svc" 15 | ) 16 | 17 | type Serverless struct { 18 | SvcCtx *svc.ServiceContext // 服务上下文 19 | RegisterZrpcServer func(grpcServer *grpc.Server, ctx *svc.ServiceContext) 20 | ProtoSets []string 21 | } 22 | 23 | func New() *Serverless { 24 | cc := configcenter.MustNewConfigCenter[config.Config](configcenter.Config{ 25 | Type: "yaml", 26 | }, subscriber.MustNewFsnotifySubscriber(filepath.Join("plugins", "{{ .DirName }}", "etc", "etc.yaml"), subscriber.WithUseEnv(true))) 27 | 28 | svcCtx := svc.NewServiceContext(cc) 29 | 30 | // get protoSets 31 | protoSets, err := pb.WriteToLocal(pb.Embed) 32 | logx.Must(err) 33 | 34 | return &Serverless{ 35 | SvcCtx: svcCtx, 36 | RegisterZrpcServer: server.RegisterZrpcServer, 37 | ProtoSets: protoSets, 38 | } 39 | }{{end}} -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/config/config.go.tpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logx" 5 | "github.com/zeromicro/go-zero/gateway" 6 | "github.com/zeromicro/go-zero/zrpc" 7 | {{ if has "model" .Features }}"github.com/zeromicro/go-zero/core/stores/sqlx"{{ end }} 8 | {{ if has "redis" .Features }}"github.com/zeromicro/go-zero/core/stores/redis"{{ end }} 9 | ) 10 | 11 | type Config struct { 12 | Zrpc ZrpcConf 13 | Gateway GatewayConf 14 | Log LogConf 15 | {{ if has "model" .Features }}Sqlx SqlxConf{{ end }} 16 | {{ if has "redis" .Features }}Redis RedisConf{{ end }} 17 | Banner BannerConf 18 | } 19 | 20 | type ZrpcConf struct { 21 | zrpc.RpcServerConf 22 | } 23 | 24 | type GatewayConf struct { 25 | gateway.GatewayConf 26 | } 27 | 28 | type LogConf struct { 29 | logx.LogConf 30 | } 31 | 32 | {{ if has "model" .Features }}type SqlxConf struct { 33 | sqlx.SqlConf 34 | }{{ end }} 35 | {{ if has "redis" .Features }}type RedisConf struct { 36 | redis.RedisConf 37 | }{{ end }} 38 | 39 | type BannerConf struct { 40 | Text string `json:",default=JZERO"` 41 | Color string `json:",default=green"` 42 | FontName string `json:",default=starwars,options=big|larry3d|starwars|standard"` 43 | } 44 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/middleware/validator.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | 6 | "buf.build/go/protovalidate" 7 | "github.com/pkg/errors" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | "google.golang.org/grpc" 10 | "google.golang.org/grpc/codes" 11 | "google.golang.org/grpc/status" 12 | "google.golang.org/protobuf/proto" 13 | ) 14 | 15 | type Validator struct { 16 | v protovalidate.Validator 17 | } 18 | 19 | func NewValidator() *Validator { 20 | v, err := protovalidate.New() 21 | logx.Must(err) 22 | return &Validator{v: v} 23 | } 24 | 25 | func (v *Validator) UnaryServerMiddleware() grpc.UnaryServerInterceptor { 26 | return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { 27 | switch req.(type) { 28 | case proto.Message: 29 | if err := v.v.Validate(req.(proto.Message)); err != nil { 30 | var valErr *protovalidate.ValidationError 31 | if ok := errors.As(err, &valErr); ok && len(valErr.ToProto().GetViolations()) > 0 { 32 | return nil, status.Error(codes.InvalidArgument, valErr.ToProto().GetViolations()[0].GetMessage()) 33 | } 34 | return nil, status.Error(codes.InvalidArgument, err.Error()) 35 | } 36 | } 37 | return handler(ctx, req) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/src/getting-started/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 安装 jzero 3 | icon: marketeq:download-alt-4 4 | order: 2 5 | --- 6 | 7 | ## 安装 golang 8 | 9 | 推荐采用 [gvm](https://github.com/jaronnie/gvm) 安装 golang 环境 10 | 11 | ## 安装 jzero 12 | 13 | 提供以下三种方式使用 jzero, 请根据实际情况任选一种即可 14 | 15 | * 源码安装(**go version >= go1.24.3**) 16 | * 直接[下载 jzero 二进制文件](https://github.com/jzero-io/jzero/releases) 17 | * 基于 Docker 安装 jzero, [镜像地址](https://github.com/jzero-io/jzero/pkgs/container/jzero) 18 | 19 | ### 源码安装 jzero 20 | 21 | ```bash 22 | # 设置国内代理(可选) 23 | # go env -w GOPROXY=https://goproxy.cn,direct 24 | go install github.com/jzero-io/jzero/cmd/jzero@latest 25 | 26 | # 获取 jzero 版本信息 27 | jzero version 28 | 29 | # 自动下载所依赖的工具 30 | jzero check 31 | ``` 32 | 33 | ### 下载 jzero 二进制文件 34 | 35 | [下载地址](https://github.com/jzero-io/jzero/releases) 36 | 37 | 根据自己的操作系统选择对应的压缩包, 解压后放在 `$GOPATH/bin` 目录下即可 38 | 39 | 执行以下内容完成 jzero 的环境准备 40 | 41 | ```shell 42 | # 获取 jzero 版本信息 43 | jzero version 44 | 45 | # 自动下载所依赖的工具 46 | jzero check 47 | ``` 48 | 49 | ### 基于 Docker 安装 jzero 50 | 51 | ```shell 52 | # 获取 jzero 版本信息 53 | docker run --rm ghcr.io/jzero-io/jzero:latest version 54 | ``` 55 | 56 | ## 升级 jzero 57 | 58 | ```shell 59 | # 升级为最新版 60 | jzero upgrade 61 | # 升级到指定版本 62 | jzero upgrade --channel 63 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/middleware/validator.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "context" 5 | 6 | "buf.build/go/protovalidate" 7 | "github.com/pkg/errors" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | "google.golang.org/grpc" 10 | "google.golang.org/grpc/codes" 11 | "google.golang.org/grpc/status" 12 | "google.golang.org/protobuf/proto" 13 | ) 14 | 15 | type Validator struct { 16 | v protovalidate.Validator 17 | } 18 | 19 | func NewValidator() *Validator { 20 | v, err := protovalidate.New() 21 | logx.Must(err) 22 | return &Validator{v: v} 23 | } 24 | 25 | func (v *Validator) UnaryServerMiddleware() grpc.UnaryServerInterceptor { 26 | return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { 27 | switch req.(type) { 28 | case proto.Message: 29 | if err := v.v.Validate(req.(proto.Message)); err != nil { 30 | var valErr *protovalidate.ValidationError 31 | if ok := errors.As(err, &valErr); ok && len(valErr.ToProto().GetViolations()) > 0 { 32 | return nil, status.Error(codes.InvalidArgument, valErr.ToProto().GetViolations()[0].GetMessage()) 33 | } 34 | return nil, status.Error(codes.InvalidArgument, err.Error()) 35 | } 36 | } 37 | return handler(ctx, req) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/format/format.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2025 jaronnie 3 | */ 4 | 5 | package format 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/format/formatgo" 11 | ) 12 | 13 | // formatCmd represents the format command 14 | var formatCmd = &cobra.Command{ 15 | Use: "format", 16 | Short: "code format tool", 17 | Long: `used to format code`, 18 | RunE: func(cmd *cobra.Command, args []string) error { 19 | if err := formatgo.Run(); err != nil { 20 | return err 21 | } 22 | return nil 23 | }, 24 | SilenceUsage: true, 25 | } 26 | 27 | // formatGoCmd represents the format go code command 28 | var formatGoCmd = &cobra.Command{ 29 | Use: "go", 30 | Short: "used to format go code", 31 | RunE: func(cmd *cobra.Command, args []string) error { 32 | if err := formatgo.Run(); err != nil { 33 | return err 34 | } 35 | return nil 36 | }, 37 | SilenceUsage: true, 38 | } 39 | 40 | func GetCommand() *cobra.Command { 41 | formatCmd.PersistentFlags().BoolP("git-change", "", true, "just format git changed files") 42 | formatCmd.PersistentFlags().BoolP("display-diff", "d", false, "display diffs instead of rewriting files") 43 | 44 | formatCmd.AddCommand(formatGoCmd) 45 | return formatCmd 46 | } 47 | -------------------------------------------------------------------------------- /cmd/jzero/.template/mongo/model.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package mongo 4 | 5 | import ( 6 | "github.com/jzero-io/jzero/core/stores/monx" 7 | "github.com/eddieowens/opts" 8 | 9 | {{range $v := .Imports}}{{$v | base}} "{{$v}}" 10 | {{end}} 11 | ) 12 | 13 | {{range $k,$v := .MutiModels}} type {{$k | FirstUpper | ToCamel}}Model struct { 14 | {{range $vv := $v}}{{$vv | FirstUpper | ToCamel}} {{$vv}}.{{$vv | FirstUpper |ToCamel}}Model 15 | {{end}} 16 | } 17 | {{end}} 18 | 19 | type Model struct { 20 | {{range $v := .TypePackages}}{{$v | FirstUpper | ToCamel}} {{$v}}.{{$v | FirstUpper |ToCamel}}Model 21 | {{end}} 22 | } 23 | 24 | func NewModel(url, db string, op ...opts.Opt[monx.MonOpts]) Model { 25 | return Model{ 26 | {{range $v := .TypePackages}}{{$v | FirstUpper | ToCamel}}: {{$v}}.New{{ $v | FirstUpper | ToCamel }}Model(url, db, op...), 27 | {{end}} 28 | } 29 | } 30 | 31 | {{range $k,$v := .MutiModels}} func New{{$k | FirstUpper | ToCamel}}Model(url, db string, op ...opts.Opt[monx.MonOpts]) {{$k | FirstUpper | ToCamel}}Model { 32 | return {{$k | FirstUpper | ToCamel}}Model{ 33 | {{range $vv := $v}}{{$vv | FirstUpper | ToCamel}}: {{$vv}}.New{{ $vv | FirstUpper | ToCamel }}Model(url, db, op...), 34 | {{end}} 35 | } 36 | } 37 | {{end}} -------------------------------------------------------------------------------- /core/templatex/templatex.go: -------------------------------------------------------------------------------- 1 | package templatex 2 | 3 | import ( 4 | "bytes" 5 | "text/template" 6 | 7 | "github.com/Masterminds/sprig/v3" 8 | "github.com/eddieowens/opts" 9 | ) 10 | 11 | type TemplateOpts struct { 12 | Options []string 13 | FuncMaps []template.FuncMap 14 | } 15 | 16 | func (opts TemplateOpts) DefaultOptions() TemplateOpts { 17 | return TemplateOpts{} 18 | } 19 | 20 | func WithFuncMaps(funcMaps []template.FuncMap) opts.Opt[TemplateOpts] { 21 | return func(o *TemplateOpts) { 22 | o.FuncMaps = funcMaps 23 | } 24 | } 25 | 26 | func WithOptions(options ...string) opts.Opt[TemplateOpts] { 27 | return func(o *TemplateOpts) { 28 | o.Options = options 29 | } 30 | } 31 | 32 | // ParseTemplate template 33 | func ParseTemplate(data any, tplT []byte, op ...opts.Opt[TemplateOpts]) ([]byte, error) { 34 | o := opts.DefaultApply(op...) 35 | 36 | var err error 37 | t := template.New("production").Funcs(sprig.TxtFuncMap()) 38 | for _, funcMap := range o.FuncMaps { 39 | t = t.Funcs(funcMap) 40 | } 41 | if len(o.Options) > 0 { 42 | t = t.Option(o.Options...) 43 | } 44 | 45 | t, err = t.Parse(string(tplT)) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | buf := new(bytes.Buffer) 51 | err = t.Execute(buf, data) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return buf.Bytes(), err 56 | } 57 | -------------------------------------------------------------------------------- /docs/src/guide/api.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: api 指南 3 | icon: eos-icons:api 4 | star: true 5 | order: 0.2 6 | --- 7 | 8 | ## 前言 9 | 10 | 通过 go-zero 自研的 api 文件定义, 称为 api 可描述语言, 可用于 11 | 12 | * 自动生成多语言服务端代码 13 | * 自动生成文档(json/html/swagger) 14 | * 自动生成多语言客户端代码 15 | 16 | ## api 字段校验 17 | 18 | > jzero 默认集成 [https://github.com/go-playground/validator](https://github.com/go-playground/validator) 进行字段校验 19 | 20 | ```shell {4} 21 | syntax = "v1" 22 | 23 | type CreateRequest { 24 | name string `json:"name" validate:"gte=2,lte=30"` // 名称 25 | } 26 | ``` 27 | 28 | ## 将 types 文件夹按照 go_package 进行分组 29 | 30 | :::important go_package 的选项, 参考自 proto 文件, 能将 message 生成的结构体分组 31 | 32 | 在 api 文件中同理, go_package 选项能将定义的 type 生成的结构体分组 33 | 34 | 两大优点: 35 | 1. 避免默认生成的 types/types.go 爆炸 36 | 37 | 2. 提升开发体验, 不同 group 下的 type 命名不会冲突 38 | ::: 39 | 40 | ```shell {3,4,5,6} 41 | syntax = "v1" 42 | 43 | info ( 44 | go_package: "version" 45 | ) 46 | ``` 47 | 48 | ## 合并同一个 group 的 handler 为同一个文件 49 | 50 | ```shell {4} 51 | @server ( 52 | prefix: /api/v1 53 | group: system/user 54 | compact_handler: true 55 | ) 56 | service simpleapi { 57 | @handler GetUserHandler 58 | get /system/user/getUser (GetUser2Request) returns (GetUserResponse) 59 | 60 | @handler DeleteUserHandler 61 | get /system/user/deleteUser (DeleteUserRequest) returns (DeleteUserResponse) 62 | } 63 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/model/model.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package model 4 | 5 | import ( 6 | "github.com/zeromicro/go-zero/core/stores/sqlx" 7 | "github.com/jzero-io/jzero/core/stores/modelx" 8 | "github.com/eddieowens/opts" 9 | 10 | {{range $v := .Imports}}"{{$v}}" 11 | {{end}} 12 | ) 13 | 14 | {{range $k,$v := .MutiModels}} type {{$k | FirstUpper | ToCamel}}Model struct { 15 | {{range $vv := $v}}{{$vv | FirstUpper | ToCamel}} {{$vv}}.{{$vv | FirstUpper |ToCamel}}Model 16 | {{end}} 17 | } 18 | {{end}} 19 | 20 | type Model struct { 21 | {{range $v := .TablePackages}}{{$v | FirstUpper | ToCamel}} {{$v}}.{{$v | FirstUpper |ToCamel}}Model 22 | {{end}} 23 | } 24 | 25 | func NewModel(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) Model { 26 | return Model{ 27 | {{range $v := .TablePackages}}{{$v | FirstUpper | ToCamel}}: {{$v}}.New{{ $v | FirstUpper | ToCamel }}Model(conn, op...), 28 | {{end}} 29 | } 30 | } 31 | 32 | {{range $k,$v := .MutiModels}} func New{{$k | FirstUpper | ToCamel}}Model(conn sqlx.SqlConn, op ...opts.Opt[modelx.ModelOpts]) {{$k | FirstUpper | ToCamel}}Model { 33 | return {{$k | FirstUpper | ToCamel}}Model{ 34 | {{range $vv := $v}}{{$vv | FirstUpper | ToCamel}}: {{$vv}}.New{{ $vv | FirstUpper | ToCamel }}Model(conn, op...), 35 | {{end}} 36 | } 37 | } 38 | {{end}} 39 | -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/middleware_zrpc.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | 4 | import ( 5 | "context" 6 | 7 | "google.golang.org/grpc" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | ) 10 | 11 | func {{.Name | FirstUpper}}Middleware(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { 12 | if MatchRoute("{{.Name}}", info.FullMethod) { 13 | // do something before middleware 14 | logx.WithContext(ctx).Info("enter {{.Name}} before middleware") 15 | } 16 | hd, err := handler(ctx, req) 17 | if MatchRoute("{{.Name}}", info.FullMethod) { 18 | // do something after middleware 19 | logx.WithContext(ctx).Info("enter {{.Name}} after middleware") 20 | } 21 | return hd, err 22 | } 23 | 24 | func {{.Name | FirstUpper}}StreamMiddleware(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 25 | if MatchRoute("{{.Name}}", info.FullMethod) { 26 | // do something before middleware 27 | logx.WithContext(ss.Context()).Info("enter stream {{.Name}} before middleware") 28 | } 29 | hd := handler(srv, ss) 30 | if MatchRoute("{{.Name}}", info.FullMethod) { 31 | // do something after middleware 32 | logx.WithContext(ss.Context()).Info("enter stream {{.Name}} after middleware") 33 | } 34 | return hd 35 | } -------------------------------------------------------------------------------- /core/configcenter/configcenter.go: -------------------------------------------------------------------------------- 1 | package configcenter 2 | 3 | import ( 4 | configurator "github.com/zeromicro/go-zero/core/configcenter" 5 | "github.com/zeromicro/go-zero/core/configcenter/subscriber" 6 | "github.com/zeromicro/go-zero/core/logx" 7 | ) 8 | 9 | type Config configurator.Config 10 | 11 | type ConfigCenter[T any] interface { 12 | configurator.Configurator[T] 13 | MustGetConfig() T 14 | } 15 | 16 | type configCenter[T any] struct { 17 | configurator.Configurator[T] 18 | } 19 | 20 | func (c *configCenter[T]) MustGetConfig() T { 21 | config, err := c.Configurator.GetConfig() 22 | logx.Must(err) 23 | return config 24 | } 25 | 26 | func (c *configCenter[T]) GetConfig() (T, error) { 27 | return c.Configurator.GetConfig() 28 | } 29 | 30 | func (c *configCenter[T]) AddListener(listener func()) { 31 | c.Configurator.AddListener(listener) 32 | } 33 | 34 | func MustNewConfigCenter[T any](c Config, subscriber subscriber.Subscriber) ConfigCenter[T] { 35 | cc, err := NewConfigCenter[T](c, subscriber) 36 | logx.Must(err) 37 | return cc 38 | } 39 | 40 | func NewConfigCenter[T any](c Config, subscriber subscriber.Subscriber) (ConfigCenter[T], error) { 41 | cc := &configCenter[T]{} 42 | 43 | center, err := configurator.NewConfigCenter[T](configurator.Config(c), subscriber) 44 | if err != nil { 45 | return nil, err 46 | } 47 | cc.Configurator = center 48 | return cc, nil 49 | } 50 | -------------------------------------------------------------------------------- /cmd/jzero/.template/api/route2code.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package handler 4 | 5 | import ( 6 | "net/http" 7 | "path" 8 | "strings" 9 | "sync" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | "github.com/zeromicro/go-zero/core/search" 13 | ) 14 | 15 | var RoutesCodesMap = map[string]string{ 16 | {{ range $v := .Routes }}"{{ $v.Method | upper }}:{{ $v.Path }}":"{{ replace `/` `:` $v.Group | FirstLower }}:{{ $v.Handler | FirstLower}}", 17 | {{ end }} 18 | } 19 | 20 | var ( 21 | MST map[string]*search.Tree 22 | once sync.Once 23 | ) 24 | 25 | func Route2Code(r *http.Request) string { 26 | once.Do(func() { 27 | RegisterRoute2Code(RoutesCodesMap) 28 | }) 29 | if tree, ok := MST[strings.ToUpper(r.Method)]; ok { 30 | if result, ok := tree.Search(path.Clean(r.URL.Path)); ok { 31 | return result.Item.(string) 32 | } 33 | } 34 | 35 | return "unknown" 36 | } 37 | 38 | func RegisterRoute2Code(maps map[string]string) { 39 | if MST == nil { 40 | MST = make(map[string]*search.Tree) 41 | } 42 | for k, v := range maps { 43 | if splits := strings.Split(k, ":"); len(splits) >= 2 { 44 | if _, ok := MST[splits[0]]; ok { 45 | logx.Must(MST[splits[0]].Add(path.Clean(strings.Join(splits[1:], ":")), v)) 46 | } else { 47 | tree := search.NewTree() 48 | logx.Must(tree.Add(strings.Join(splits[1:], ":"), v)) 49 | MST[splits[0]] = tree 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/add/add.go: -------------------------------------------------------------------------------- 1 | package add 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/add/addapi" 7 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/add/addproto" 8 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/add/addsql" 9 | ) 10 | 11 | // addCmd represents the add command 12 | var addCmd = &cobra.Command{ 13 | Use: "add", 14 | Short: `Used to add api/proto/sql file`, 15 | SilenceUsage: true, 16 | } 17 | 18 | var addApiCmd = &cobra.Command{ 19 | Use: "api", 20 | Short: `Add api`, 21 | RunE: func(cmd *cobra.Command, args []string) error { 22 | return addapi.Run(args) 23 | }, 24 | SilenceUsage: true, 25 | } 26 | 27 | var addProtoCmd = &cobra.Command{ 28 | Use: "proto", 29 | Short: `Add proto`, 30 | RunE: func(cmd *cobra.Command, args []string) error { 31 | return addproto.Run(args) 32 | }, 33 | SilenceUsage: true, 34 | } 35 | 36 | var addSqlCmd = &cobra.Command{ 37 | Use: "sql", 38 | Short: `Add sql`, 39 | RunE: func(cmd *cobra.Command, args []string) error { 40 | return addsql.Run(args) 41 | }, 42 | SilenceUsage: true, 43 | } 44 | 45 | func GetCommand() *cobra.Command { 46 | addCmd.PersistentFlags().StringP("output", "o", "file", "Output format. One of: file | std") 47 | 48 | addCmd.AddCommand(addApiCmd) 49 | addCmd.AddCommand(addProtoCmd) 50 | addCmd.AddCommand(addSqlCmd) 51 | return addCmd 52 | } 53 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/gitstatus/status.go: -------------------------------------------------------------------------------- 1 | package gitstatus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os/exec" 7 | "path/filepath" 8 | "strings" 9 | ) 10 | 11 | func IsGitRepo(path string) bool { 12 | cmd := exec.Command("git", "rev-parse", "--is-inside-work-tree") 13 | cmd.Dir = path 14 | _, err := cmd.CombinedOutput() 15 | return err == nil 16 | } 17 | 18 | func ChangedFiles(path, ext string) ([]string, []string, error) { 19 | var m []string 20 | var d []string 21 | 22 | cmd := exec.Command("git", "status", "-su") 23 | // set working dir 24 | cmd.Dir = path 25 | data, err := cmd.CombinedOutput() 26 | if err != nil { 27 | return nil, nil, fmt.Errorf("exec ( git status -su ) with error: %w\n%s", err, data) 28 | } 29 | data = bytes.TrimSpace(data) 30 | lines := bytes.Split(data, []byte("\n")) 31 | for _, line := range lines { 32 | if ext != "" { 33 | if !bytes.HasSuffix(line, []byte(ext)) { 34 | continue 35 | } 36 | } 37 | 38 | arr := bytes.Split(line, []byte(" ")) 39 | filename := string(arr[len(arr)-1]) 40 | 41 | if strings.HasPrefix(filename, "..") { 42 | continue 43 | } 44 | 45 | if filename != "" { 46 | if bytes.HasPrefix(line, []byte("D")) { 47 | d = append(d, filepath.Join(path, filepath.Join(strings.Split(filename, "/")...))) 48 | } else { 49 | m = append(m, filepath.Join(path, filepath.Join(strings.Split(filename, "/")...))) 50 | } 51 | } 52 | } 53 | return m, d, nil 54 | } 55 | -------------------------------------------------------------------------------- /core/stores/modelx/sqlxconn.go: -------------------------------------------------------------------------------- 1 | package modelx 2 | 3 | import ( 4 | "github.com/huandu/go-sqlbuilder" 5 | _ "github.com/jackc/pgx/v5/stdlib" 6 | "github.com/zeromicro/go-zero/core/logx" 7 | "github.com/zeromicro/go-zero/core/stores/sqlc" 8 | "github.com/zeromicro/go-zero/core/stores/sqlx" 9 | _ "modernc.org/sqlite" 10 | 11 | "github.com/jzero-io/jzero/core/stores/cache" 12 | ) 13 | 14 | func MustNewConn(c sqlx.SqlConf) sqlx.SqlConn { 15 | sqlConn := sqlx.MustNewConn(c) 16 | db, err := sqlConn.RawDB() 17 | logx.Must(err) 18 | err = db.Ping() 19 | logx.Must(err) 20 | 21 | sqlbuilder.DefaultFlavor = getSqlbuilderFlavor(c.DriverName) 22 | return sqlConn 23 | } 24 | 25 | func MustNewConnAndSqlbuilderFlavor(c sqlx.SqlConf) (sqlx.SqlConn, sqlbuilder.Flavor) { 26 | sqlConn := sqlx.MustNewConn(c) 27 | db, err := sqlConn.RawDB() 28 | logx.Must(err) 29 | err = db.Ping() 30 | logx.Must(err) 31 | 32 | return sqlConn, getSqlbuilderFlavor(c.DriverName) 33 | } 34 | 35 | // NewConnWithCache returns a CachedConn with a custom cache. 36 | func NewConnWithCache(db sqlx.SqlConn, c cache.Cache) sqlc.CachedConn { 37 | return sqlc.NewConnWithCache(db, c) 38 | } 39 | 40 | func getSqlbuilderFlavor(driverName string) sqlbuilder.Flavor { 41 | switch driverName { 42 | case "mysql": 43 | return sqlbuilder.MySQL 44 | case "pgx": 45 | return sqlbuilder.PostgreSQL 46 | case "sqlite": 47 | return sqlbuilder.SQLite 48 | default: 49 | return sqlbuilder.DefaultFlavor 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/src/getting-started/genclient.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 生成客户端代码 3 | icon: clarity:thin-client-line 4 | order: 5 5 | --- 6 | 7 | ## 生成 Swagger 文档 8 | 9 | ### 使用方法 10 | 11 | ::: code-tabs#shell 12 | 13 | @tab jzero cli 14 | 15 | ```bash 16 | cd your_project 17 | jzero gen swagger 18 | ``` 19 | 20 | @tab jzero Docker 21 | ```bash 22 | cd your_project 23 | docker run --rm -v ${PWD}:/app ghcr.io/jzero-io/jzero:latest gen swagger 24 | ``` 25 | ::: 26 | 27 | **Swagger UI 地址**: `localhost:8001/swagger` 28 | 29 | ## 生成 Zrpc 客户端 30 | 31 | ::: code-tabs#shell 32 | 33 | @tab jzero 34 | 35 | ```bash 36 | cd your_project 37 | jzero gen zrpcclient --name simplerpcclient 38 | ``` 39 | 40 | @tab Docker 41 | ```bash 42 | cd your_project 43 | docker run --rm -v ${PWD}:/app ghcr.io/jzero-io/jzero:latest gen zrpcclient 44 | ``` 45 | ::: 46 | 47 | **代码示例**: 48 | 49 | ```go 50 | package main 51 | 52 | import ( 53 | "context" 54 | "fmt" 55 | "simplerpc/simlerpcclient" 56 | "simplerpc/simlerpcclient/typed/version" 57 | 58 | "github.com/zeromicro/go-zero/zrpc" 59 | ) 60 | 61 | func main() { 62 | cli, err := zrpc.NewClientWithTarget("localhost:8001") 63 | if err != nil { 64 | panic(err) 65 | } 66 | clientset, err := simlerpcclient.NewClientset(cli) 67 | if err != nil { 68 | panic(err) 69 | } 70 | versionResponse, err := clientset.Version().Version(context.Background(), &version.VersionRequest{}) 71 | if err != nil { 72 | panic(err) 73 | } 74 | fmt.Println(versionResponse) 75 | } 76 | ``` -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/cmd/version.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "{{ .APP }} version", 24 | Long: `{{ .APP }} version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("{{ .APP }} version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/cmd/version.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "{{ .APP }} version", 24 | Long: `{{ .APP }} version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("{{ .APP }} version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/cmd/version.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/spf13/cast" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var ( 15 | Version string 16 | Commit string 17 | Date string 18 | ) 19 | 20 | // versionCmd represents the version command 21 | var versionCmd = &cobra.Command{ 22 | Use: "version", 23 | Short: "{{ .APP }} version", 24 | Long: `{{ .APP }} version`, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | printVersion() 27 | }, 28 | } 29 | 30 | func printVersion() { 31 | var versionBuffer bytes.Buffer 32 | 33 | if Version == "" { 34 | Version = "unknown" 35 | } 36 | versionBuffer.WriteString(fmt.Sprintf("{{ .APP }} version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 37 | 38 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 39 | 40 | if Commit == "" { 41 | Commit = "unknown" 42 | } 43 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 44 | 45 | if Date != "" { 46 | Date = cast.ToString(cast.ToTimeInDefaultLocation(Date, time.Local)) 47 | } else { 48 | Date = "unknown" 49 | } 50 | versionBuffer.WriteString(fmt.Sprintf("Build date: %s\n", Date)) 51 | 52 | fmt.Print(versionBuffer.String()) 53 | } 54 | 55 | func init() { 56 | _ = os.Setenv("VERSION", Version) 57 | _ = os.Setenv("COMMIT", Commit) 58 | _ = os.Setenv("DATE", Date) 59 | 60 | rootCmd.AddCommand(versionCmd) 61 | } 62 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/add/addapi/addapi.go: -------------------------------------------------------------------------------- 1 | package addapi 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/zeromicro/go-zero/tools/goctl/api/format" 9 | 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 11 | "github.com/jzero-io/jzero/cmd/jzero/internal/desc" 12 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/filex" 14 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/templatex" 15 | ) 16 | 17 | func Run(args []string) error { 18 | baseDir := filepath.Join("desc", "api") 19 | 20 | service := desc.GetApiServiceName(filepath.Join("desc", "api")) 21 | 22 | apiName := args[0] 23 | 24 | template, err := templatex.ParseTemplate(filepath.Join("api", "template.api.tpl"), map[string]any{ 25 | "Service": service, 26 | "Group": apiName, 27 | }, embeded.ReadTemplateFile(filepath.Join("api", "template.api.tpl"))) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | if config.C.Add.Output == "file" { 33 | if filex.FileExists(filepath.Join(baseDir, apiName+".api")) { 34 | return fmt.Errorf("%s already exists", apiName) 35 | } 36 | 37 | _ = os.MkdirAll(filepath.Dir(filepath.Join(baseDir, apiName)), 0755) 38 | 39 | err = os.WriteFile(filepath.Join(baseDir, apiName+".api"), template, 0o644) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | // format 45 | return format.ApiFormatByPath(filepath.Join(baseDir, apiName+".api"), false) 46 | } 47 | fmt.Println(string(template)) 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/add/addproto/addproto.go: -------------------------------------------------------------------------------- 1 | package addproto 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 9 | "github.com/jzero-io/jzero/cmd/jzero/internal/desc" 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 11 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/filex" 12 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/stringx" 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/templatex" 14 | ) 15 | 16 | func Run(args []string) error { 17 | baseDir := filepath.Join("desc", "proto") 18 | 19 | protoName := args[0] 20 | 21 | frameType, _ := desc.GetFrameType() 22 | if frameType == "" { 23 | frameType = "rpc" 24 | } 25 | 26 | var template []byte 27 | 28 | template, err := templatex.ParseTemplate(filepath.Join(frameType, "template.proto.tpl"), map[string]any{ 29 | "Package": protoName, 30 | "Service": stringx.ToCamel(protoName), 31 | }, embeded.ReadTemplateFile(filepath.Join(frameType, "template.proto.tpl"))) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | if config.C.Add.Output == "file" { 37 | if filex.FileExists(filepath.Join(baseDir, protoName+".proto")) { 38 | return fmt.Errorf("%s already exists", protoName) 39 | } 40 | 41 | _ = os.MkdirAll(filepath.Dir(filepath.Join(baseDir, protoName)), 0755) 42 | 43 | err = os.WriteFile(filepath.Join(baseDir, protoName+".proto"), template, 0o644) 44 | if err != nil { 45 | return err 46 | } 47 | return nil 48 | } 49 | fmt.Println(string(template)) 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 jaronnie 3 | 4 | */ 5 | 6 | package version 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "runtime" 12 | "time" 13 | 14 | "github.com/spf13/cast" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | var ( 19 | Version string 20 | Commit string 21 | Date string 22 | ) 23 | 24 | // versionCmd represents the version command 25 | var versionCmd = &cobra.Command{ 26 | Use: "version", 27 | Short: `Print jzero version`, 28 | Run: func(cmd *cobra.Command, args []string) { 29 | GetVersion() 30 | }, 31 | } 32 | 33 | func GetVersion() { 34 | var versionBuffer bytes.Buffer 35 | 36 | if Version != "" { 37 | versionBuffer.WriteString(fmt.Sprintf("jzero version %s %s/%s\n", Version, runtime.GOOS, runtime.GOARCH)) 38 | } else { 39 | versionBuffer.WriteString(fmt.Sprintf("jzero version %s %s/%s\n", "unknown", runtime.GOOS, runtime.GOARCH)) 40 | } 41 | 42 | versionBuffer.WriteString(fmt.Sprintf("Go version %s\n", runtime.Version())) 43 | if Commit != "" { 44 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", Commit)) 45 | } else { 46 | versionBuffer.WriteString(fmt.Sprintf("Git commit %s\n", "unknown")) 47 | } 48 | 49 | if Date != "" { 50 | versionBuffer.WriteString(fmt.Sprintf("Build date %s\n", cast.ToTimeInDefaultLocation(Date, time.Local))) 51 | } else { 52 | versionBuffer.WriteString(fmt.Sprintf("Build date %s\n", "unknown")) 53 | } 54 | 55 | fmt.Print(versionBuffer.String()) 56 | } 57 | 58 | func GetCommand() *cobra.Command { 59 | return versionCmd 60 | } 61 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/serverless/serverless.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 jaronnie 3 | */ 4 | 5 | package serverless 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | 10 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/serverless/serverlessbuild" 11 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/serverless/serverlessdelete" 12 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 14 | ) 15 | 16 | // serverlessCmd represents the serverless command 17 | var serverlessCmd = &cobra.Command{ 18 | Use: "serverless", 19 | Short: "build serverless functions", 20 | } 21 | 22 | var serverlessBuildCmd = &cobra.Command{ 23 | Use: "build", 24 | Short: "jzero serverless build", 25 | Long: `jzero serverless build.`, 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | embeded.Home = config.C.Serverless.Home 28 | return serverlessbuild.Run() 29 | }, 30 | } 31 | 32 | var serverlessDeleteCmd = &cobra.Command{ 33 | Use: "delete", 34 | Short: "jzero serverless delete", 35 | Long: `jzero serverless delete.`, 36 | RunE: func(cmd *cobra.Command, args []string) error { 37 | embeded.Home = config.C.Serverless.Home 38 | return serverlessdelete.Run() 39 | }, 40 | } 41 | 42 | func GetCommand() *cobra.Command { 43 | serverlessCmd.AddCommand(serverlessBuildCmd) 44 | serverlessCmd.AddCommand(serverlessDeleteCmd) 45 | 46 | serverlessCmd.PersistentFlags().StringP("home", "", ".template", "set templates path") 47 | serverlessDeleteCmd.Flags().StringSliceP("plugin", "p", nil, "plugin name") 48 | 49 | return serverlessCmd 50 | } 51 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/template/templateinit/templateinit.go: -------------------------------------------------------------------------------- 1 | package templateinit 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "time" 9 | 10 | "github.com/go-git/go-git/v5" 11 | "github.com/go-git/go-git/v5/plumbing" 12 | 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 14 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 15 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/console" 16 | ) 17 | 18 | func Run() error { 19 | if config.C.Template.Init.Remote != "" && config.C.Template.Init.Branch != "" { 20 | target := filepath.Join(config.C.Template.Init.Output, config.C.Template.Init.Branch) 21 | _ = os.MkdirAll(target, 0o755) 22 | fmt.Printf("%s templates into '%s', please wait...\n", console.Green("Cloning"), target) 23 | 24 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 25 | defer cancel() 26 | _, err := git.PlainCloneContext(ctx, target, false, &git.CloneOptions{ 27 | SingleBranch: true, 28 | URL: config.C.Template.Init.Remote, 29 | Depth: 0, 30 | ReferenceName: plumbing.ReferenceName("refs/heads/" + config.C.Template.Init.Branch), 31 | }) 32 | if err != nil { 33 | return err 34 | } 35 | _ = os.RemoveAll(filepath.Join(target, ".git")) 36 | fmt.Println(console.Green("Done")) 37 | return nil 38 | } 39 | fmt.Printf("%s templates into '%s', please wait...\n", console.Green("Initializing embedded"), config.C.Template.Init.Output) 40 | err := embeded.WriteTemplateDir("", config.C.Template.Init.Output) 41 | if err != nil { 42 | return err 43 | } 44 | fmt.Println(console.Green("Done")) 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /cmd/jzero/.template/client/zrpcclient-go/clientset.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package {{.Package}} 4 | 5 | import ( 6 | "github.com/zeromicro/go-zero/zrpc" 7 | {{if .HasPlugins}}"{{.Module}}/plugins" 8 | 9 | {{end}}{{range $v := .Services}}{{$v | ToCamel | lower}} "{{$.Module}}/typed/{{$v | lower}}" 10 | {{end}} 11 | ) 12 | 13 | type Clientset interface { 14 | Direct() zrpc.Client 15 | 16 | {{range $v := .Services}}{{$v | ToCamel | FirstUpper}}() {{$v | ToCamel | lower}}.{{$v | ToCamel | FirstUpper}} 17 | {{end}}{{if .HasPlugins}} 18 | Plugins() plugins.Plugins 19 | {{end}} 20 | } 21 | 22 | type clientset struct { 23 | // direct client to request 24 | direct zrpc.Client 25 | 26 | {{range $v := .Services}}{{$v | ToCamel | FirstLower}} {{$v | ToCamel | lower}}.{{$v | ToCamel | FirstUpper}} 27 | {{end}}{{if .HasPlugins}} 28 | plugins plugins.Plugins 29 | {{end}} 30 | } 31 | 32 | func (cs *clientset) Direct() zrpc.Client { 33 | return cs.direct 34 | } 35 | 36 | {{range $v := .Services}}func (cs *clientset) {{$v | FirstUpper | ToCamel}}() {{$v | ToCamel |lower}}.{{$v | ToCamel | FirstUpper}} { 37 | return cs.{{$v | ToCamel | FirstLower}} 38 | } 39 | 40 | {{end}}{{if .HasPlugins}}func (cs *clientset) Plugins() plugins.Plugins { 41 | return cs.plugins 42 | } 43 | 44 | {{end}} 45 | 46 | func NewClientset(cli zrpc.Client) (Clientset, error) { 47 | cs := clientset{ 48 | direct: cli, 49 | {{range $v := .Services}}{{$v | ToCamel | FirstLower}}: {{$v | ToCamel | lower}}.New{{$v | ToCamel | FirstUpper}}(cli), 50 | {{end}}{{if .HasPlugins}}plugins: plugins.NewPlugins(cli), 51 | {{end}} 52 | } 53 | 54 | return &cs, nil 55 | } -------------------------------------------------------------------------------- /docs/src/community/contribute.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 欢迎贡献👏 3 | icon: ooui:user-contributions-ltr 4 | star: true 5 | order: 30 6 | category: contribute 7 | tag: 8 | - contribute 9 | --- 10 | 11 | 欢迎参与 jzero 的开发以及维护, 这是一件非常有意义的事情, 让我们一起让 jzero 变得更好. 12 | 13 | ## 步骤 14 | 15 | ### 1. fork jzero 16 | 17 | [点击这里 fork](https://github.com/jzero-io/jzero/fork) 18 | 19 | ### 2. clone 20 | 21 | ```shell 22 | git clone https://github.com/your_username/jzero 23 | ``` 24 | 25 | ### 3. checkout branch 26 | 27 | ```shell 28 | cd jzero 29 | 30 | git checkout -b feat/patch-1 31 | ``` 32 | 33 | ### 4. format the code what you changes 34 | 35 | ```shell 36 | jzero format 37 | ``` 38 | 39 | ### 5. lint codes 40 | 41 | ```shell 42 | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 43 | golangci-lint run --fix 44 | ``` 45 | 46 | ### 6. push 47 | 48 | ```shell 49 | git add . 50 | git commit -m "feat(xx): custom message" 51 | git push 52 | ``` 53 | 54 | ### 7. pull request 55 | 56 | Create your pull request!!! 57 | 58 | ## debug jzero 59 | 60 | 1. fork jzero 并 clone jzero 到本地后 61 | 62 | ```shell 63 | cd jzero 64 | go install 65 | ``` 66 | 67 | 2. new project with branch, e.g. `api` 68 | 69 | ```shell 70 | jzero new your_project --branch api 71 | ``` 72 | 73 | 3. run jzero gen with debug mode 74 | 75 | ```shell 76 | jzero gen --debug --debug-sleep-time 15 77 | ``` 78 | 79 | 4. attach jzero process 80 | 81 | 推荐采用 goland, 使用 attach 到 jzero 的进程中, 即可 debug, 如下所示: 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /cmd/jzero/.template/client/zrpcclient-go/plugin.go.tpl: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/zrpc" 5 | {{range $serviceName := .Services}} 6 | {{$.PluginName | ToCamel | FirstLower}}{{$serviceName | ToCamel | FirstUpper}} "{{$.Module}}/plugins/{{$.PluginName}}/typed/{{$serviceName | lower}}"{{end}} 7 | ) 8 | 9 | type {{.PluginName | ToCamel | FirstUpper}} interface { 10 | {{range $serviceName := .Services}} {{$serviceName | ToCamel | FirstUpper}}() {{$.PluginName | ToCamel | FirstLower}}{{$serviceName | ToCamel | FirstUpper}}.{{$serviceName | ToCamel | FirstUpper}} 11 | {{end}} 12 | } 13 | 14 | type {{.PluginName | ToCamel | FirstLower}}Client struct { 15 | conn zrpc.Client 16 | {{range $serviceName := .Services}} {{$serviceName | ToCamel | FirstLower}} {{$.PluginName | ToCamel | FirstLower}}{{$serviceName | ToCamel | FirstUpper}}.{{$serviceName | ToCamel | FirstUpper}} 17 | {{end}} 18 | } 19 | 20 | {{range $serviceName := .Services}}func (x *{{$.PluginName | ToCamel | FirstLower}}Client) {{$serviceName | ToCamel | FirstUpper}}() {{$.PluginName | ToCamel | FirstLower}}{{$serviceName | ToCamel | FirstUpper}}.{{$serviceName | ToCamel | FirstUpper}} { 21 | return x.{{$serviceName | ToCamel | FirstLower}} 22 | } 23 | 24 | {{end}} 25 | 26 | func New{{.PluginName | ToCamel | FirstUpper}}(conn zrpc.Client) {{.PluginName | ToCamel | FirstUpper}} { 27 | return &{{.PluginName | ToCamel | FirstLower}}Client{ 28 | conn: conn, 29 | {{range $serviceName := .Services}} {{$serviceName | ToCamel | FirstLower}}: {{$.PluginName | ToCamel | FirstLower}}{{$serviceName | ToCamel | FirstUpper}}.New{{$serviceName | ToCamel | FirstUpper}}(conn), 30 | {{end}} 31 | } 32 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/internal/svc/e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw=: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/jzero-io/jzero/core/configcenter" 5 | {{ if has "model" .Features }}"github.com/jzero-io/jzero/core/stores/modelx"{{ end }} 6 | {{ if has "redis" .Features }}"github.com/jzero-io/jzero/core/stores/cache" 7 | "github.com/zeromicro/go-zero/core/stores/redis" 8 | "github.com/pkg/errors"{{ end }} 9 | 10 | "{{ .Module }}/internal/config" 11 | {{ if has "model" .Features }}"{{ .Module }}/internal/model"{{ end }} 12 | ) 13 | 14 | type ServiceContext struct { 15 | ConfigCenter configcenter.ConfigCenter[config.Config] 16 | {{ if has "model" .Features }}SqlxConn sqlx.SqlConn 17 | Model model.Model{{ end }} 18 | {{ if has "redis" .Features }}RedisConn *redis.Redis 19 | Cache cache.Cache{{ end }} 20 | } 21 | 22 | func NewServiceContext(cc configcenter.ConfigCenter[config.Config]) *ServiceContext { 23 | svcCtx := &ServiceContext{ 24 | ConfigCenter: cc, 25 | } 26 | 27 | {{ if has "model" .Features }}svcCtx.SqlxConn = modelx.MustNewConn(cc.MustGetConfig().Sqlx.SqlConf){{ end }} 28 | {{ if has "redis" .Features }}svcCtx.RedisConn = redis.MustNewRedis(cc.MustGetConfig().Redis.RedisConf){{ end }} 29 | {{ if has "redis" .Features }}svcCtx.Cache = cache.NewRedisNode(svcCtx.RedisConn, errors.New("cache not found")){{ end }} 30 | {{ if and (has "model" .Features) (has "redis" .Features) }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn, modelx.WithCachedConn(modelx.NewConnWithCache(svcCtx.SqlxConn, svcCtx.Cache))){{else if has "model" .Features }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn){{ end }} 31 | svcCtx.SetConfigListener() 32 | return svcCtx 33 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/svc/e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw=: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/jzero-io/jzero/core/configcenter" 5 | {{ if has "model" .Features }}"github.com/jzero-io/jzero/core/stores/modelx"{{ end }} 6 | {{ if has "redis" .Features }}"github.com/jzero-io/jzero/core/stores/cache" 7 | "github.com/zeromicro/go-zero/core/stores/redis" 8 | "github.com/pkg/errors"{{ end }} 9 | 10 | "{{ .Module }}/internal/config" 11 | {{ if has "model" .Features }}"{{ .Module }}/internal/model"{{ end }} 12 | ) 13 | 14 | type ServiceContext struct { 15 | ConfigCenter configcenter.ConfigCenter[config.Config] 16 | {{ if has "model" .Features }}SqlxConn sqlx.SqlConn 17 | Model model.Model{{ end }} 18 | {{ if has "redis" .Features }}RedisConn *redis.Redis 19 | Cache cache.Cache{{ end }} 20 | } 21 | 22 | func NewServiceContext(cc configcenter.ConfigCenter[config.Config]) *ServiceContext { 23 | svcCtx := &ServiceContext{ 24 | ConfigCenter: cc, 25 | } 26 | 27 | {{ if has "model" .Features }}svcCtx.SqlxConn = modelx.MustNewConn(cc.MustGetConfig().Sqlx.SqlConf){{ end }} 28 | {{ if has "redis" .Features }}svcCtx.RedisConn = redis.MustNewRedis(cc.MustGetConfig().Redis.RedisConf){{ end }} 29 | {{ if has "redis" .Features }}svcCtx.Cache = cache.NewRedisNode(svcCtx.RedisConn, errors.New("cache not found")){{ end }} 30 | {{ if and (has "model" .Features) (has "redis" .Features) }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn, modelx.WithCachedConn(modelx.NewConnWithCache(svcCtx.SqlxConn, svcCtx.Cache))){{else if has "model" .Features }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn){{ end }} 31 | svcCtx.SetConfigListener() 32 | return svcCtx 33 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/delete.tpl: -------------------------------------------------------------------------------- 1 | {{if .withCache}} 2 | func (m *default{{.upperStartCamelObject}}Model) Delete(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error { 3 | {{if .withCache}}{{if .containsIndexCache}}data, err := m.FindOne(ctx, session, {{.lowerStartCamelPrimaryKey}}) 4 | if err != nil{ 5 | return err 6 | } 7 | 8 | {{end}} {{.keys}} 9 | _, err {{if .containsIndexCache}}={{else}}:={{end}} m.cachedConn.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { 10 | sb := sqlbuilder.DeleteFrom(m.table) 11 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), {{.lowerStartCamelPrimaryKey}})) 12 | statement, args := sb.BuildWithFlavor(m.flavor) 13 | if session != nil { 14 | return session.ExecCtx(ctx, statement, args...) 15 | } 16 | return conn.ExecCtx(ctx, statement, args...) 17 | }, {{.keyValues}}) 18 | return err{{else}}return m.Delete(ctx, session, {{.lowerStartCamelPrimaryKey}}){{end}} 19 | } 20 | {{else}} 21 | func (m *default{{.upperStartCamelObject}}Model) Delete(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error { 22 | sb := sqlbuilder.DeleteFrom(m.table) 23 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), {{.lowerStartCamelPrimaryKey}})) 24 | statement, args := sb.BuildWithFlavor(m.flavor) 25 | var err error 26 | if session != nil { 27 | _, err = session.ExecCtx(ctx, statement, args...) 28 | } else { 29 | _, err = m.conn.ExecCtx(ctx, statement, args...) 30 | } 31 | return err 32 | } 33 | {{end}} -------------------------------------------------------------------------------- /docs/src/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: false 3 | icon: fluent:home-heart-20-filled 4 | title: 首页 5 | --- 6 | 7 |
8 | 9 |
10 | 11 | ## 简介 12 | 13 | 基于 [go-zero框架](https://github.com/zeromicro/go-zero) 以及 [go-zero/goctl工具](https://github.com/zeromicro/go-zero/tree/master/tools/goctl) 开发的 [jzero](https://github.com/jzero-io/jzero) 框架, 可一键新增 api/gateway/rpc 项目, 并基于可描述文件(**api/proto/sql**)自动生成**服务端和客户端代码**代码, 降低开发心智, 解放双手! 14 | 15 | 具备以下特点: 16 | 17 | * 支持通过**配置文件/命令行参数/环境变量**组合的方式灵活控制 jzero 的各项配置, 极简指令生成代码, ai 友好 18 | * 支持基于 **git 对改动文件**生成代码, 支持对**指定描述文件**生成代码或**忽略指定描述文件**生成代码, 提升大型项目代码生成效率 19 | * 内置常用开发模板并增强模板特性, 支持**自定义模板**, 构建专属企业内部代码模板, 极大降低开发成本 20 | 21 | 更多详情请参阅:[https://docs.jzero.io](https://docs.jzero.io) 22 | 23 | ## 设计理念 24 | 25 | * **开发体验**: 提供简单好用的一站式生产可用的解决方案, 提升开发体验感 26 | * **模板驱动**: 所有代码生成均基于模板渲染, 默认生成即最佳实践, 且支持自定义模板内容 27 | * **生态兼容**: 不修改 go-zero 和 go-zero/goctl, 保持生态兼容, 同时解决已有的痛点问题并扩展新的功能 28 | * **团队开发**: 通过模块**分层**, **插件**设计, 团队开发友好 29 | * **接口设计**: 不依赖特定数据库/缓存/配置中心等基础设施, 根据实际需求自由选择 30 | 31 | ## 快速开始 32 | 33 | ::: code-tabs#shell 34 | @tab jzero cli 35 | 36 | ```bash 37 | # 安装 jzero 38 | go install github.com/jzero-io/jzero/cmd/jzero@latest 39 | # 一键安装所需的工具 40 | jzero check 41 | # 一键创建项目 42 | jzero new your_project 43 | cd your_project 44 | # 启动服务端程序 45 | go run main.go server 46 | # 访问 swagger ui 47 | http://localhost:8001/swagger 48 | ``` 49 | 50 | @tab jzero Docker 51 | 52 | ```bash 53 | # 一键创建项目 54 | docker run --rm -v ${PWD}:/app ghcr.io/jzero-io/jzero:latest new your_project 55 | cd your_project 56 | # 启动服务端程序 57 | go run main.go server 58 | # 访问 swagger ui 59 | http://localhost:8001/swagger 60 | ``` 61 | ::: 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/internal/svc/e3tGb3JtYXRTdHlsZSAuU3R5bGUgInNlcnZpY2VfY29udGV4dCJ9fS5nby50cGw=: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "github.com/jzero-io/jzero/core/configcenter" 5 | {{ if has "model" .Features }}"github.com/jzero-io/jzero/core/stores/modelx"{{ end }} 6 | {{ if has "redis" .Features }}"github.com/jzero-io/jzero/core/stores/cache" 7 | "github.com/zeromicro/go-zero/core/stores/redis" 8 | "github.com/pkg/errors"{{ end }} 9 | 10 | "{{ .Module }}/internal/config" 11 | "{{ .Module }}/internal/middleware" 12 | {{ if has "model" .Features }}"{{ .Module }}/internal/model"{{ end }} 13 | ) 14 | 15 | type ServiceContext struct { 16 | ConfigCenter configcenter.ConfigCenter[config.Config] 17 | Middleware 18 | {{ if has "model" .Features }}SqlxConn sqlx.SqlConn 19 | Model model.Model{{ end }} 20 | {{ if has "redis" .Features }}RedisConn *redis.Redis 21 | Cache cache.Cache{{ end }} 22 | } 23 | 24 | func NewServiceContext(cc configcenter.ConfigCenter[config.Config]) *ServiceContext { 25 | svcCtx := &ServiceContext{ 26 | ConfigCenter: cc, 27 | } 28 | 29 | {{ if has "model" .Features }}svcCtx.SqlxConn = modelx.MustNewConn(cc.MustGetConfig().Sqlx.SqlConf){{ end }} 30 | {{ if has "redis" .Features }}svcCtx.RedisConn = redis.MustNewRedis(cc.MustGetConfig().Redis.RedisConf){{ end }} 31 | {{ if has "redis" .Features }}svcCtx.Cache = cache.NewRedisNode(svcCtx.RedisConn, errors.New("cache not found")){{ end }} 32 | {{ if and (has "model" .Features) (has "redis" .Features) }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn, modelx.WithCachedConn(modelx.NewConnWithCache(svcCtx.SqlxConn, svcCtx.Cache))){{else if has "model" .Features }}svcCtx.Model = model.NewModel(svcCtx.SqlxConn){{ end }} 33 | svcCtx.SetConfigListener() 34 | svcCtx.Middleware = svcCtx.NewMiddleware() 35 | return svcCtx 36 | } -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/types.tpl: -------------------------------------------------------------------------------- 1 | type ( 2 | {{.lowerStartCamelObject}}Model interface{ 3 | {{.method}} 4 | 5 | // custom interface generated by jzero 6 | WithTable(f func(table string) string) {{.lowerStartCamelObject}}Model 7 | InsertV2(ctx context.Context, session sqlx.Session, data *{{.upperStartCamelObject}}) error 8 | BulkInsert(ctx context.Context, session sqlx.Session, datas []*{{.upperStartCamelObject}}) error 9 | FindByCondition(ctx context.Context, session sqlx.Session, conds ...condition.Condition) ([]*{{.upperStartCamelObject}}, error) 10 | FindSelectedColumnsByCondition(ctx context.Context, session sqlx.Session, columns []string, conds ...condition.Condition) ([]*{{.upperStartCamelObject}}, error) 11 | FindOneByCondition(ctx context.Context, session sqlx.Session, conds ...condition.Condition) (*{{.upperStartCamelObject}}, error) 12 | FindOneSelectedColumnsByCondition(ctx context.Context, session sqlx.Session, columns []string, conds ...condition.Condition) (*{{.upperStartCamelObject}}, error) 13 | CountByCondition(ctx context.Context, session sqlx.Session, conds ...condition.Condition) (int64, error) 14 | PageByCondition(ctx context.Context, session sqlx.Session, conds ...condition.Condition) ([]*{{.upperStartCamelObject}}, int64 ,error) 15 | UpdateFieldsByCondition(ctx context.Context, session sqlx.Session, field map[string]any, conds ...condition.Condition) error 16 | DeleteByCondition(ctx context.Context, session sqlx.Session, conds ...condition.Condition) error 17 | } 18 | 19 | default{{.upperStartCamelObject}}Model struct { 20 | cachedConn sqlc.CachedConn 21 | conn sqlx.SqlConn 22 | flavor sqlbuilder.Flavor 23 | table string 24 | } 25 | 26 | {{.upperStartCamelObject}} struct { 27 | {{.fields}} 28 | } 29 | ) 30 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/gogen/util.go: -------------------------------------------------------------------------------- 1 | package gogen 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "text/template" 7 | 8 | "github.com/zeromicro/go-zero/tools/goctl/api/spec" 9 | "github.com/zeromicro/go-zero/tools/goctl/pkg/golang" 10 | "github.com/zeromicro/go-zero/tools/goctl/util/pathx" 11 | ) 12 | 13 | type fileGenConfig struct { 14 | dir string 15 | subdir string 16 | filename string 17 | templateName string 18 | category string 19 | templateFile string 20 | builtinTemplate string 21 | data any 22 | } 23 | 24 | func genFileString(c fileGenConfig) (string, error) { 25 | var ( 26 | text string 27 | err error 28 | ) 29 | if len(c.category) == 0 || len(c.templateFile) == 0 { 30 | text = c.builtinTemplate 31 | } else { 32 | text, err = pathx.LoadTemplate(c.category, c.templateFile, c.builtinTemplate) 33 | if err != nil { 34 | return "", err 35 | } 36 | } 37 | 38 | t := template.Must(template.New(c.templateName).Parse(text)) 39 | buffer := new(bytes.Buffer) 40 | err = t.Execute(buffer, c.data) 41 | if err != nil { 42 | return "", err 43 | } 44 | 45 | code := golang.FormatCode(buffer.String()) 46 | return code, nil 47 | } 48 | 49 | func getDoc(doc string) string { 50 | if len(doc) == 0 { 51 | return "" 52 | } 53 | 54 | return "// " + strings.Trim(doc, "\"") 55 | } 56 | 57 | func getHandlerName(route spec.Route) string { 58 | handler, err := getHandlerBaseName(route) 59 | if err != nil { 60 | panic(err) 61 | } 62 | 63 | return handler + "Handler" 64 | } 65 | 66 | func getHandlerBaseName(route spec.Route) (string, error) { 67 | handler := route.Handler 68 | handler = strings.TrimSpace(handler) 69 | handler = strings.TrimSuffix(handler, "handler") 70 | handler = strings.TrimSuffix(handler, "Handler") 71 | 72 | return handler, nil 73 | } 74 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: deploy-docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'docs/**' 9 | - '.github/workflows/deploy-docs.yml' 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | deploy-gh-pages: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v6 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Set node 24 | uses: actions/setup-node@v6 25 | with: 26 | node-version: 20 27 | cache: npm 28 | cache-dependency-path: docs/pnpm-lock.yaml 29 | 30 | - uses: actions/setup-go@v6 31 | with: 32 | go-version: '1.24.3' 33 | 34 | - name: Build Docs 35 | env: 36 | NODE_OPTIONS: --max_old_space_size=8192 37 | run: |- 38 | cd docs 39 | npm i 40 | npm run docs:build 41 | > src/.vuepress/dist/.nojekyll 42 | 43 | - name: Deploy 44 | uses: JamesIves/github-pages-deploy-action@v4.7.6 45 | with: 46 | branch: gh-pages 47 | folder: docs/src/.vuepress/dist 48 | 49 | - name: Upload to jaronnie/jzero-docs-deploy-pages 50 | run: | 51 | go install github.com/jaronnie/grum@latest 52 | GITHUB_TOKEN=${{ secrets.ACCESS_TOKEN }} grum clone https://github.com/jaronnie/jzero-docs-deploy-pages 53 | cd jzero-docs-deploy-pages 54 | git config user.name "dependabot[bot]" 55 | git config user.email "49699333+dependabot[bot]@users.noreply.github.com" 56 | find . -mindepth 1 ! -name "api" ! -name ".git" ! -name "vercel.json" ! -path "./api/*" ! -path "./.git/*" -exec rm -rf {} + 57 | mv ../docs/src/.vuepress/dist/* ./ 58 | git add . 59 | git diff-index --quiet HEAD || git commit -m "chore(docs): update docs" 60 | git push -f -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/find-one.tpl: -------------------------------------------------------------------------------- 1 | {{if .withCache}} 2 | func (m *default{{.upperStartCamelObject}}Model) FindOne(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) { 3 | {{if .withCache}}{{.cacheKey}} 4 | var resp {{.upperStartCamelObject}} 5 | err := m.cachedConn.QueryRowCtx(ctx, &resp, {{.cacheKeyVariable}}, func(ctx context.Context, conn sqlx.SqlConn, v any) error { 6 | sb := sqlbuilder.Select({{.lowerStartCamelObject}}Rows).From(m.table) 7 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), {{.lowerStartCamelPrimaryKey}})) 8 | sql, args := sb.BuildWithFlavor(m.flavor) 9 | if session != nil { 10 | return session.QueryRowCtx(ctx, v, sql, args...) 11 | } 12 | return conn.QueryRowCtx(ctx, v, sql, args...) 13 | }) 14 | switch err { 15 | case nil: 16 | return &resp, nil 17 | case sqlc.ErrNotFound: 18 | return nil, ErrNotFound 19 | default: 20 | return nil, err 21 | }{{else}}return m.FindOne(ctx, session, {{.lowerStartCamelPrimaryKey}}){{end}} 22 | } 23 | {{else}} 24 | func (m *default{{.upperStartCamelObject}}Model) FindOne(ctx context.Context, session sqlx.Session, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) { 25 | sb := sqlbuilder.Select({{.lowerStartCamelObject}}Rows).From(m.table) 26 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), {{.lowerStartCamelPrimaryKey}})) 27 | sb.Limit(1) 28 | sql, args := sb.BuildWithFlavor(m.flavor) 29 | var resp {{.upperStartCamelObject}} 30 | var err error 31 | if session != nil { 32 | err = session.QueryRowCtx(ctx, &resp, sql, args...) 33 | } else { 34 | err = m.conn.QueryRowCtx(ctx, &resp, sql, args...) 35 | } 36 | switch err { 37 | case nil: 38 | return &resp, nil 39 | case sqlx.ErrNotFound: 40 | return nil, ErrNotFound 41 | default: 42 | return nil, err 43 | } 44 | } 45 | {{end}} -------------------------------------------------------------------------------- /cmd/jzero/internal/command/completion/completion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 jaronnie jaron@jaronnie.com 3 | 4 | */ 5 | 6 | package completion 7 | 8 | import ( 9 | "os" 10 | 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var completionCmd = &cobra.Command{ 15 | Use: "completion [bash|zsh|fish|powershell]", 16 | Short: "Generate completion script", 17 | Long: `To load completions: 18 | 19 | Bash: 20 | 21 | $ source <(jzero completion bash) 22 | 23 | # To load completions for each session, execute once: 24 | Linux: 25 | $ jzero completion bash > /etc/bash_completion.d/jzero 26 | MacOS: 27 | $ jzero completion bash > /usr/local/etc/bash_completion.d/jzero 28 | 29 | Zsh: 30 | 31 | # If shell completion is not already enabled in your environment you will need 32 | # to enable it. You can execute the following once: 33 | 34 | $ echo "autoload -U compinit; compinit" >> ~/.zshrc 35 | 36 | # To load completions for each session, execute once: 37 | $ jzero completion zsh > "${fpath[1]}/_jzero" 38 | 39 | # You will need to start a new shell for this setup to take effect. 40 | 41 | Fish: 42 | 43 | $ jzero completion fish | source 44 | 45 | # To load completions for each session, execute once: 46 | $ jzero completion fish > ~/.config/fish/completions/jzero.fish 47 | 48 | PowerShell: 49 | $ jzero completion powershell | Out-String | Invoke-Expression 50 | `, 51 | DisableFlagsInUseLine: true, 52 | ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, 53 | Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), 54 | Run: func(cmd *cobra.Command, args []string) { 55 | switch args[0] { 56 | case "bash": 57 | _ = cmd.Root().GenBashCompletion(os.Stdout) 58 | case "zsh": 59 | _ = cmd.Root().GenZshCompletion(os.Stdout) 60 | case "fish": 61 | _ = cmd.Root().GenFishCompletion(os.Stdout, true) 62 | case "powershell": 63 | _ = cmd.Root().GenPowerShellCompletion(os.Stdout) 64 | } 65 | }, 66 | } 67 | 68 | func GetCommand() *cobra.Command { 69 | return completionCmd 70 | } 71 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/format/formatgo/formatgo.go: -------------------------------------------------------------------------------- 1 | package formatgo 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | "regexp" 7 | 8 | "github.com/jzero-io/go_fmt/gofmtapi" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | "golang.org/x/sync/errgroup" 11 | 12 | "github.com/jzero-io/jzero/cmd/jzero/internal/config" 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/gitstatus" 14 | ) 15 | 16 | var rxCodeGenerated = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`) 17 | 18 | func Run() error { 19 | files := getFormatFiles() 20 | 21 | files = filterFiles(files) 22 | 23 | return FormatFiles(files) 24 | } 25 | 26 | func FormatFiles(files []string) error { 27 | gf := gofmtapi.NewFormatter() 28 | opt := gofmtapi.NewOptions() 29 | opt.BindFlags() 30 | 31 | opt.DisplayDiff = config.C.Format.DisplayDiff 32 | opt.Files = files 33 | 34 | if len(opt.Files) == 0 { 35 | return nil 36 | } 37 | logx.Debugf("format files: %v", opt.Files) 38 | return gf.Execute(opt) 39 | } 40 | 41 | func getFormatFiles() []string { 42 | if config.C.Format.GitChange { 43 | files, _, err := gitstatus.ChangedFiles(".", ".go") 44 | if err == nil { 45 | return files 46 | } 47 | return []string{"."} 48 | } 49 | return []string{"."} 50 | } 51 | 52 | func filterFiles(files []string) []string { 53 | var result []string 54 | 55 | var eg errgroup.Group 56 | eg.SetLimit(len(files)) 57 | for _, v := range files { 58 | eg.Go(func() error { 59 | line, _ := readFirstLine(v) 60 | if !rxCodeGenerated.MatchString(line) { 61 | result = append(result, v) 62 | } 63 | return nil 64 | }) 65 | } 66 | if err := eg.Wait(); err != nil { 67 | return nil 68 | } 69 | 70 | return result 71 | } 72 | 73 | func readFirstLine(filePath string) (string, error) { 74 | file, err := os.Open(filePath) 75 | if err != nil { 76 | return "", err 77 | } 78 | defer file.Close() 79 | 80 | scanner := bufio.NewScanner(file) 81 | if scanner.Scan() { 82 | return scanner.Text(), nil 83 | } 84 | 85 | return "", scanner.Err() 86 | } 87 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/desc/proto/third_party/grpc-gateway/protoc-gen-openapiv2/options/annotations.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | 4 | package grpc.gateway.protoc_gen_openapiv2.options; 5 | 6 | import "google/protobuf/descriptor.proto"; 7 | import "grpc-gateway/protoc-gen-openapiv2/options/openapiv2.proto"; 8 | 9 | option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"; 10 | 11 | extend google.protobuf.FileOptions { 12 | // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 13 | // 14 | // All IDs are the same, as assigned. It is okay that they are the same, as they extend 15 | // different descriptor messages. 16 | Swagger openapiv2_swagger = 1042; 17 | } 18 | extend google.protobuf.MethodOptions { 19 | // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 20 | // 21 | // All IDs are the same, as assigned. It is okay that they are the same, as they extend 22 | // different descriptor messages. 23 | Operation openapiv2_operation = 1042; 24 | } 25 | extend google.protobuf.MessageOptions { 26 | // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 27 | // 28 | // All IDs are the same, as assigned. It is okay that they are the same, as they extend 29 | // different descriptor messages. 30 | Schema openapiv2_schema = 1042; 31 | } 32 | extend google.protobuf.ServiceOptions { 33 | // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 34 | // 35 | // All IDs are the same, as assigned. It is okay that they are the same, as they extend 36 | // different descriptor messages. 37 | Tag openapiv2_tag = 1042; 38 | } 39 | extend google.protobuf.FieldOptions { 40 | // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 41 | // 42 | // All IDs are the same, as assigned. It is okay that they are the same, as they extend 43 | // different descriptor messages. 44 | JSONSchema openapiv2_field = 1042; 45 | } 46 | -------------------------------------------------------------------------------- /cmd/jzero/.template/rpc/middleware_gen.go.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by jzero. DO NOT EDIT. 2 | 3 | package middleware 4 | 5 | import ( 6 | "fmt" 7 | "context" 8 | "regexp" 9 | 10 | "github.com/zeromicro/go-zero/gateway" 11 | "github.com/zeromicro/go-zero/zrpc" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | var ( 16 | _ = fmt.Sprintf("middleware_gen.go") 17 | _ = context.Background() 18 | _ = grpc.SupportPackageIsVersion7 19 | ) 20 | 21 | func RegisterGen(zrpc *zrpc.RpcServer, gw *gateway.Server) { 22 | {{range $v := .HttpMiddlewares}}gw.Use({{$v.Name | FirstUpper}}Middleware) 23 | {{end}} 24 | {{range $v := .ZrpcMiddlewares}}zrpc.AddUnaryInterceptors({{$v.Name | FirstUpper}}Middleware) 25 | zrpc.AddStreamInterceptors({{$v.Name | FirstUpper}}StreamMiddleware){{end}} 26 | } 27 | 28 | // Define and compile routes 29 | var routesMap map[string][]*regexp.Regexp 30 | 31 | // loadRoute compiles and stores a route pattern. 32 | func loadRoutes(middleware string, patterns ...string) { 33 | if routesMap == nil { 34 | routesMap = make(map[string][]*regexp.Regexp) 35 | } 36 | 37 | re := regexp.MustCompile(`\{[^}]+\}`) 38 | var routes []*regexp.Regexp 39 | for _, pattern := range patterns { 40 | pattern = re.ReplaceAllString(pattern, "([^/]+)") 41 | compiledPattern := "^" + pattern + "$" 42 | routes = append(routes, regexp.MustCompile(compiledPattern)) 43 | } 44 | routesMap[middleware] = routes 45 | } 46 | 47 | // MatchRoute checks if a route matches any compiled route. 48 | func MatchRoute(middleware, route string) bool { 49 | if routesReg, ok := routesMap[middleware]; ok { 50 | for _, rr := range routesReg { 51 | if rr.MatchString(route) { 52 | return true 53 | } 54 | } 55 | } 56 | return false 57 | } 58 | 59 | func init() { 60 | {{range $v := .HttpMiddlewares}} 61 | loadRoutes("{{$v.Name}}", 62 | {{range $vv := $v.Routes}}"{{$vv}}", 63 | {{end}}) 64 | {{end}} 65 | 66 | {{range $v := .ZrpcMiddlewares}} 67 | loadRoutes("{{$v.Name}}", 68 | {{range $vv := $v.Routes}}"{{$vv}}", 69 | {{end}}) 70 | {{end}} 71 | } -------------------------------------------------------------------------------- /cmd/jzero/internal/command/gen/genmongo/plugins.go: -------------------------------------------------------------------------------- 1 | package genmongo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "slices" 8 | "strings" 9 | 10 | "github.com/rinchsan/gosimports" 11 | "github.com/zeromicro/go-zero/core/logx" 12 | "github.com/zeromicro/go-zero/tools/goctl/util/pathx" 13 | 14 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 15 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/templatex" 16 | ) 17 | 18 | func (jm *JzeroMongo) GenRegister(types []string) error { 19 | logx.Debugf("get register tables: %v", types) 20 | 21 | slices.Sort(types) 22 | 23 | var imports []string 24 | var typePackages []string 25 | 26 | mutiModels := make(map[string][]string) 27 | 28 | for _, t := range types { 29 | var isMutiModel bool 30 | if strings.Contains(t, ".") { 31 | t = filepath.Join(strings.Split(t, ".")...) 32 | isMutiModel = true 33 | } 34 | mf := filepath.Join("internal", "mongo", strings.ToLower(t)) 35 | if !pathx.FileExists(mf) { 36 | logx.Debugf("%s mongo model generated code not exists, skip", t) 37 | continue 38 | } 39 | 40 | imports = append(imports, fmt.Sprintf("%s/internal/mongo/%s", jm.Module, strings.ToLower(filepath.ToSlash(t)))) 41 | 42 | if isMutiModel { 43 | mutiModels[filepath.Dir(t)] = append(mutiModels[filepath.Dir(t)], strings.ToLower(filepath.Base(t))) 44 | } else { 45 | typePackages = append(typePackages, strings.ToLower(t)) 46 | } 47 | } 48 | 49 | logx.Debugf("get register imports: %v", imports) 50 | logx.Debugf("get register types packages: %v", typePackages) 51 | logx.Debugf("get register muti models: %v", mutiModels) 52 | 53 | template, err := templatex.ParseTemplate(filepath.Join("mongo", "model.go.tpl"), map[string]any{ 54 | "Imports": imports, 55 | "TypePackages": typePackages, 56 | "MutiModels": mutiModels, 57 | }, embeded.ReadTemplateFile(filepath.Join("mongo", "model.go.tpl"))) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | format, err := gosimports.Process("", template, nil) 63 | if err != nil { 64 | return err 65 | } 66 | return os.WriteFile(filepath.Join("internal", "mongo", "model.go"), format, 0o644) 67 | } 68 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/dsn/dsn_test.go: -------------------------------------------------------------------------------- 1 | package dsn 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestParseDSN(t *testing.T) { 9 | // Add tests for ParseDSN function 10 | t.Run("Test ParseDSN", func(t *testing.T) { 11 | // Add test cases for ParseDSN function 12 | t.Run("Test ParseDSN with mysql", func(t *testing.T) { 13 | // Add test cases for ParseDSN function with mysql 14 | t.Run("Test ParseDSN with mysql and valid dsn", func(t *testing.T) { 15 | // Add test cases for ParseDSN function with mysql and valid dsn 16 | meta, err := ParseDSN("mysql", "user:password@tcp(localhost:3306)/dbname") 17 | if err != nil { 18 | t.Errorf("ParseDSN() error = %v", err) 19 | } 20 | if meta[User] != "user" { 21 | t.Errorf("ParseDSN() user = %v, want %v", meta[User], "user") 22 | } 23 | if meta[Host] != "localhost" { 24 | t.Errorf("ParseDSN() host = %v, want %v", meta[Host], "localhost") 25 | } 26 | if meta[Port] != "3306" { 27 | t.Errorf("ParseDSN() port = %v, want %v", meta[Port], "3306") 28 | } 29 | if meta[Database] != "dbname" { 30 | t.Errorf("ParseDSN() dbname = %v, want %v", meta[Database], "dbname") 31 | } 32 | }) 33 | }) 34 | }) 35 | 36 | t.Run("Test ParseDSN with postgres", func(t *testing.T) { 37 | // Add test cases for ParseDSN function with postgres 38 | t.Run("Test ParseDSN with postgres and valid dsn", func(t *testing.T) { 39 | // Add test cases for ParseDSN function with postgres and valid dsn 40 | meta, err := ParseDSN("postgres", "postgres://user:password@localhost:5432/dbname") 41 | if err != nil { 42 | t.Errorf("ParseDSN() error = %v", err) 43 | } 44 | fmt.Println(meta) 45 | if meta[User] != "user" { 46 | t.Errorf("ParseDSN() user = %v, want %v", meta[User], "user") 47 | } 48 | if meta[Host] != "localhost" { 49 | t.Errorf("ParseDSN() host = %v, want %v", meta[Host], "localhost") 50 | } 51 | if meta[Port] != "5432" { 52 | t.Errorf("ParseDSN() port = %v, want %v", meta[Port], "5432") 53 | } 54 | if meta[Database] != "dbname" { 55 | t.Errorf("ParseDSN() dbname = %v, want %v", meta[Database], "dbname") 56 | } 57 | }) 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/find-one-by-field.tpl: -------------------------------------------------------------------------------- 1 | {{if .withCache}} 2 | func (m *default{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}(ctx context.Context, session sqlx.Session, {{.in}}) (*{{.upperStartCamelObject}}, error) { 3 | {{if .withCache}}{{.cacheKey}} 4 | var resp {{.upperStartCamelObject}} 5 | err := m.cachedConn.QueryRowIndexCtx(ctx, &resp, {{.cacheKeyVariable}}, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) { 6 | sb := sqlbuilder.Select({{.lowerStartCamelObject}}Rows).From(m.table) 7 | condition.SelectByWhereRawSqlWithFlavor(m.flavor, sb, "{{.originalField}}", {{.lowerStartCamelField}}) 8 | sb.Limit(1) 9 | sql, args := sb.BuildWithFlavor(m.flavor) 10 | var err error 11 | 12 | if session != nil { 13 | err = session.QueryRowCtx(ctx, &resp, sql, args...) 14 | } else { 15 | err = conn.QueryRowCtx(ctx, &resp, sql, args...) 16 | } 17 | if err != nil { 18 | return nil, err 19 | } 20 | return resp.{{.upperStartCamelPrimaryKey}}, nil 21 | }, m.queryPrimary) 22 | switch err { 23 | case nil: 24 | return &resp, nil 25 | case sqlc.ErrNotFound: 26 | return nil, ErrNotFound 27 | default: 28 | return nil, err 29 | }{{else}}return m.FindOneBy{{.upperField}}(ctx, session, {{.lowerStartCamelField}}){{end}} 30 | } 31 | {{else}} 32 | func (m *default{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}(ctx context.Context, session sqlx.Session, {{.in}}) (*{{.upperStartCamelObject}}, error) { 33 | var resp {{.upperStartCamelObject}} 34 | var err error 35 | 36 | sb := sqlbuilder.Select({{.lowerStartCamelObject}}Rows).From(m.table) 37 | condition.SelectByWhereRawSql(sb, "{{.originalField}}", {{.lowerStartCamelField}}) 38 | sb.Limit(1) 39 | 40 | sql, args := sb.BuildWithFlavor(m.flavor) 41 | 42 | if session != nil { 43 | err = session.QueryRowCtx(ctx, &resp, sql, args...) 44 | } else { 45 | err = m.conn.QueryRowCtx(ctx, &resp, sql, args...) 46 | } 47 | 48 | switch err { 49 | case nil: 50 | return &resp, nil 51 | case sqlx.ErrNotFound: 52 | return nil, ErrNotFound 53 | default: 54 | return nil, err 55 | } 56 | } 57 | {{end}} 58 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/gogen/testdata/example.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info( 4 | title: "demo title" 5 | desc: "demo desc" 6 | author: "keson.an" 7 | date: "2024-06-25" 8 | version: "v1" 9 | ) 10 | 11 | // empty structure 12 | type Foo { 13 | } 14 | 15 | // type lit 16 | type Bar { 17 | Foo int `json:"foo"` 18 | Bar bool `json:"bar"` 19 | Baz []string `json:"baz"` 20 | Qux map[string]string `json:"qux"` 21 | } 22 | 23 | type Baz { 24 | Foo `json:"foo"` 25 | // array type 26 | Arr [2]int `json:"arr"` 27 | // nested type 28 | Bar { 29 | Foo string `json:"foo"` 30 | Bar bool `json:"bar"` 31 | Baz { 32 | Foo string `json:"foo"` 33 | Bar bool `json:"bar"` 34 | } 35 | Qux { 36 | Foo string `json:"foo"` 37 | Bar bool `json:"bar"` 38 | } `json:"qux"` 39 | } `json:"bar"` 40 | } 41 | 42 | 43 | type UpdateReq { 44 | Arg1 string `json:"arg1"` 45 | } 46 | 47 | type ListItem { 48 | Value1 string `json:"value1"` 49 | } 50 | 51 | type LoginReq { 52 | Username string `json:"username"` 53 | Password string `json:"password"` 54 | } 55 | 56 | type LoginResp { 57 | Name string `json:"name"` 58 | } 59 | 60 | type FormExampleReq { 61 | Name string `form:"name"` 62 | } 63 | 64 | type PathExampleReq { 65 | ID string `path:"id"` 66 | } 67 | 68 | type PathExampleResp { 69 | Name string `json:"name"` 70 | } 71 | 72 | @server( 73 | jwt: Auth 74 | prefix: /v1 75 | group: g1 76 | timeout: 3s 77 | middleware: AuthInterceptor 78 | maxBytes: 1048576 79 | ) 80 | service Foo { 81 | @handler ping 82 | get /ping 83 | 84 | @handler update 85 | post /update (UpdateReq) 86 | 87 | @handler list 88 | get /list returns ([]ListItem) 89 | 90 | @handler login 91 | post /login (LoginReq) returns (LoginResp) 92 | 93 | @handler formExample 94 | post /form/example (FormExampleReq) 95 | 96 | @handler pathExample 97 | get /path/example/:id (PathExampleReq) returns (PathExampleResp) 98 | } 99 | 100 | -------------------------------------------------------------------------------- /cmd/jzero/internal/embeded/embeded.go: -------------------------------------------------------------------------------- 1 | package embeded 2 | 3 | import ( 4 | "embed" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | var ( 10 | Template embed.FS 11 | 12 | // Home template home 13 | Home string 14 | ) 15 | 16 | func ReadTemplateFile(filename string) []byte { 17 | if Home != "" { 18 | file, err := os.ReadFile(filepath.Join(Home, filename)) 19 | if err == nil { 20 | return file 21 | } 22 | } 23 | path := filepath.ToSlash(filepath.Join(".template", filename)) 24 | data, err := Template.ReadFile(path) 25 | if err != nil { 26 | return nil 27 | } 28 | return data 29 | } 30 | 31 | func ReadTemplateDir(dirname string) []os.DirEntry { 32 | if Home != "" { 33 | file, err := os.ReadDir(filepath.Join(Home, dirname)) 34 | if err == nil { 35 | return file 36 | } 37 | } 38 | path := filepath.ToSlash(filepath.Join(".template", dirname)) 39 | data, err := Template.ReadDir(path) 40 | if err != nil { 41 | return nil 42 | } 43 | return data 44 | } 45 | 46 | func WriteTemplateDir(sourceDir, targetDir string) error { 47 | err := os.MkdirAll(targetDir, 0o755) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | err = writeTemplateDirRecursive(sourceDir, targetDir) 53 | if err != nil { 54 | return err 55 | } 56 | 57 | return nil 58 | } 59 | 60 | func writeTemplateDirRecursive(sourceDir, targetDir string) error { 61 | entries, err := Template.ReadDir(filepath.ToSlash(filepath.Join(".template", sourceDir))) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | for _, entry := range entries { 67 | sourcePath := filepath.Join(sourceDir, entry.Name()) 68 | targetPath := filepath.Join(targetDir, entry.Name()) 69 | 70 | if entry.IsDir() { 71 | err := os.MkdirAll(targetPath, 0o755) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | err = writeTemplateDirRecursive(sourcePath, targetPath) 77 | if err != nil { 78 | return err 79 | } 80 | } else { 81 | data, err := Template.ReadFile(filepath.ToSlash(filepath.Join(".template", sourcePath))) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | err = os.WriteFile(targetPath, data, 0o644) 87 | if err != nil { 88 | return err 89 | } 90 | } 91 | } 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /cmd/jzero/internal/hooks/hooks.go: -------------------------------------------------------------------------------- 1 | package hooks 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | 8 | "github.com/pkg/errors" 9 | "github.com/spf13/cobra" 10 | "github.com/zeromicro/go-zero/core/logx" 11 | 12 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/console" 13 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/execx" 14 | ) 15 | 16 | func Run(cmd *cobra.Command, hookAction, hooksName string, hooks []string) error { 17 | wd, _ := os.Getwd() 18 | 19 | if os.Getenv("JZERO_HOOK_TRIGGERED") == "true" { 20 | return nil 21 | } 22 | 23 | if os.Getenv("JZERO_FORKED") == "true" && hooksName == "global" && hookAction == "Before" { 24 | return nil 25 | } 26 | 27 | if len(hooks) > 0 { 28 | fmt.Printf("%s\n", console.Green(fmt.Sprintf("Start %s %s hooks", hookAction, hooksName))) 29 | } 30 | 31 | for _, v := range hooks { 32 | fmt.Printf("%s command %s\n", console.Green("Run"), v) 33 | err := execx.Run(v, wd, "JZERO_HOOK_TRIGGERED=true") 34 | if err != nil { 35 | return err 36 | } 37 | } 38 | 39 | if len(hooks) > 0 { 40 | fmt.Printf("%s\n", console.Green("Done")) 41 | } 42 | 43 | // fork 一个子进程来运行后续的指令 44 | if len(hooks) > 0 && hookAction == "Before" && hooksName == "global" { 45 | logx.Debugf("Before hooks executed, forking a new process to continue") 46 | 47 | // 获取当前可执行文件路径 48 | executable, err := os.Executable() 49 | if err != nil { 50 | return fmt.Errorf("failed to get executable path: %v", err) 51 | } 52 | // 准备命令行参数 53 | args := os.Args[1:] 54 | 55 | // 设置环境变量,防止无限递归 56 | env := append(os.Environ(), "JZERO_FORKED=true") 57 | 58 | // 创建新进程 59 | fork := exec.Command(executable, args...) 60 | fork.Env = env 61 | fork.Stdin = os.Stdin 62 | fork.Stdout = os.Stdout 63 | fork.Stderr = os.Stderr 64 | 65 | // 启动新进程 66 | if err = fork.Start(); err != nil { 67 | return fmt.Errorf("failed to start forked process: %v", err) 68 | } 69 | // 等待新进程完成 70 | if err = fork.Wait(); err != nil { 71 | var exitErr *exec.ExitError 72 | if errors.As(err, &exitErr) { 73 | os.Exit(exitErr.ExitCode()) 74 | } 75 | return fmt.Errorf("forked process failed: %v", err) 76 | } 77 | // 子进程成功完成,退出当前进程 78 | os.Exit(0) 79 | } 80 | 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/api/app/cmd/server.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/common-nighthawk/go-figure" 5 | "github.com/jzero-io/jzero/core/configcenter" 6 | "github.com/jzero-io/jzero/core/configcenter/subscriber" 7 | "github.com/jzero-io/jzero/core/swaggerv2" 8 | "github.com/spf13/cobra" 9 | "github.com/zeromicro/go-zero/core/logx" 10 | "github.com/zeromicro/go-zero/core/service" 11 | "github.com/zeromicro/go-zero/rest" 12 | 13 | "{{ .Module }}/internal/config" 14 | "{{ .Module }}/internal/custom" 15 | "{{ .Module }}/internal/global" 16 | "{{ .Module }}/internal/middleware" 17 | "{{ .Module }}/internal/handler" 18 | "{{ .Module }}/internal/svc" 19 | {{ if not .Serverless }}"{{ .Module }}/plugins"{{end}} 20 | ) 21 | 22 | var serverCmd = &cobra.Command{ 23 | Use: "server", 24 | Short: "{{ .APP }} server", 25 | Long: "{{ .APP }} server", 26 | Run: func(cmd *cobra.Command, args []string) { 27 | cc := configcenter.MustNewConfigCenter[config.Config](configcenter.Config{ 28 | Type: "yaml", 29 | }, subscriber.MustNewFsnotifySubscriber(cmd.Flag("config").Value.String(), subscriber.WithUseEnv(true))) 30 | 31 | // set up logger 32 | logx.Must(logx.SetUp(cc.MustGetConfig().Log.LogConf)) 33 | 34 | // print banner 35 | printBanner(cc.MustGetConfig().Banner) 36 | // print version 37 | printVersion() 38 | 39 | // create service context 40 | svcCtx := svc.NewServiceContext(cc) 41 | 42 | // create rest server 43 | restServer := rest.MustNewServer(svcCtx.ConfigCenter.MustGetConfig().Rest.RestConf) 44 | // create custom server 45 | customServer := custom.New() 46 | 47 | // register auto generated routes 48 | handler.RegisterHandlers(restServer, svcCtx) 49 | // register swagger routes 50 | swaggerv2.RegisterRoutes(restServer) 51 | // register middleware 52 | middleware.Register(restServer) 53 | 54 | {{ if not .Serverless }}// load plugins 55 | plugins.LoadPlugins(restServer, svcCtx){{end}} 56 | 57 | group := service.NewServiceGroup() 58 | group.Add(restServer) 59 | group.Add(customServer) 60 | 61 | logx.Infof("Starting rest server at %s:%d...", cc.MustGetConfig().Rest.Host, cc.MustGetConfig().Rest.Port) 62 | group.Start() 63 | }, 64 | } 65 | 66 | func printBanner(c config.BannerConf) { 67 | figure.NewColorFigure(c.Text, c.FontName, c.Color, true).Print() 68 | } 69 | 70 | func init() { 71 | rootCmd.AddCommand(serverCmd) 72 | } 73 | -------------------------------------------------------------------------------- /cmd/jzero/internal/pkg/filex/filex.go: -------------------------------------------------------------------------------- 1 | package filex 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "io/fs" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | // FileExists check file exist 14 | func FileExists(path string) bool { 15 | info, err := os.Stat(path) 16 | if errors.Is(err, fs.ErrNotExist) { 17 | return false 18 | } 19 | return !info.IsDir() 20 | } 21 | 22 | func DirExists(path string) bool { 23 | info, err := os.Stat(path) 24 | if errors.Is(err, fs.ErrNotExist) { 25 | return false 26 | } 27 | return info.IsDir() 28 | } 29 | 30 | // IsYamlFile check YAML file 31 | func IsYamlFile(path string) bool { 32 | ext := strings.ToLower(filepath.Ext(path)) 33 | return ext == ".yaml" || ext == ".yml" 34 | } 35 | 36 | // EnsureDirExists create dir with check 37 | func EnsureDirExists(dirPath string) error { 38 | info, err := os.Stat(dirPath) 39 | if errors.Is(err, fs.ErrNotExist) { 40 | err = os.MkdirAll(dirPath, 0o755) 41 | if err != nil { 42 | return fmt.Errorf("failed to create directory: %w", err) 43 | } 44 | } else if err != nil { 45 | return fmt.Errorf("failed to check directory: %w", err) 46 | } else if !info.IsDir() { 47 | return fmt.Errorf("path exists but is not a directory: %s", dirPath) 48 | } 49 | return nil 50 | } 51 | 52 | // copyDir 递归复制目录,将 src 目录下的所有文件复制到 dst 目录,已存在的文件会被覆盖 53 | func CopyDir(src, dst string) error { 54 | return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 55 | if err != nil { 56 | return err 57 | } 58 | 59 | // 计算相对路径 60 | relPath, err := filepath.Rel(src, path) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // 计算目标路径 66 | dstPath := filepath.Join(dst, relPath) 67 | 68 | if info.IsDir() { 69 | // 创建目录 70 | return os.MkdirAll(dstPath, info.Mode()) 71 | } 72 | 73 | // 复制文件 74 | return CopyFile(path, dstPath) 75 | }) 76 | } 77 | 78 | // copyFile 复制单个文件 79 | func CopyFile(src, dst string) error { 80 | sourceFile, err := os.Open(src) 81 | if err != nil { 82 | return err 83 | } 84 | defer sourceFile.Close() 85 | 86 | // 确保目标目录存在 87 | if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil { 88 | return err 89 | } 90 | 91 | destFile, err := os.Create(dst) 92 | if err != nil { 93 | return err 94 | } 95 | defer destFile.Close() 96 | 97 | _, err = io.Copy(destFile, sourceFile) 98 | return err 99 | } 100 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/gateway/app/internal/middleware/response.go.tpl: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "net/http" 8 | "strings" 9 | 10 | "github.com/zeromicro/go-zero/core/logc" 11 | "github.com/zeromicro/go-zero/core/logx" 12 | "github.com/zeromicro/go-zero/rest/httpx" 13 | "google.golang.org/grpc/status" 14 | ) 15 | 16 | type Body struct { 17 | Data any `json:"data"` 18 | Code int `json:"code"` 19 | Message string `json:"msg"` 20 | } 21 | 22 | type responseWriter struct { 23 | http.ResponseWriter 24 | statusCode int 25 | body bytes.Buffer 26 | } 27 | 28 | func (rw *responseWriter) WriteHeader(statusCode int) { 29 | rw.statusCode = statusCode 30 | rw.ResponseWriter.WriteHeader(statusCode) 31 | } 32 | 33 | func (rw *responseWriter) Write(p []byte) (int, error) { 34 | return rw.body.Write(p) 35 | } 36 | 37 | func (rw *responseWriter) Body() []byte { 38 | return rw.body.Bytes() 39 | } 40 | 41 | func ErrorMiddleware(_ context.Context, err error) (int, any) { 42 | code := http.StatusInternalServerError 43 | message := err.Error() 44 | 45 | // from grpc error 46 | if st, ok := status.FromError(err); ok { 47 | code = int(st.Code()) 48 | message = st.Message() 49 | } 50 | 51 | return http.StatusOK, Body{ 52 | Data: nil, 53 | Code: code, 54 | Message: message, 55 | } 56 | } 57 | 58 | func ResponseMiddleware(next http.HandlerFunc) http.HandlerFunc { 59 | return func(w http.ResponseWriter, r *http.Request) { 60 | logCtx := logx.ContextWithFields(r.Context(), logx.Field("path", r.URL.Path)) 61 | 62 | rw := &responseWriter{ 63 | ResponseWriter: w, 64 | statusCode: http.StatusOK, 65 | } 66 | 67 | next.ServeHTTP(rw, r) 68 | 69 | if strings.Contains(strings.ToLower(w.Header().Get("Content-Type")), "application/json") { 70 | var resp map[string]any 71 | err := json.Unmarshal(rw.Body(), &resp) 72 | if err != nil { 73 | logc.Errorf(logCtx, "Unmarshal resp error: %s\n", err.Error()) 74 | return 75 | } 76 | 77 | if _, ok := resp["code"]; ok { 78 | httpx.OkJson(w, resp) 79 | return 80 | } 81 | 82 | wrappedResp := Body{ 83 | Data: resp, 84 | Code: http.StatusOK, 85 | Message: "success", 86 | } 87 | httpx.OkJson(w, wrappedResp) 88 | return 89 | } 90 | 91 | _, err := w.Write(rw.Body()) 92 | if err != nil { 93 | logc.Errorf(logCtx, "Write response error: %s\n", err.Error()) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/model/update.tpl: -------------------------------------------------------------------------------- 1 | {{if .withCache}} 2 | func (m *default{{.upperStartCamelObject}}Model) Update(ctx context.Context, session sqlx.Session, {{if .containsIndexCache}}newData{{else}}data{{end}} *{{.upperStartCamelObject}}) error { 3 | {{if .containsIndexCache}}data, err := m.FindOne(ctx, session, newData.{{.upperStartCamelPrimaryKey}}) 4 | if err != nil { 5 | return err 6 | } 7 | {{end}}{{.keys}} 8 | _, err = m.cachedConn.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { 9 | sb := sqlbuilder.Update(m.table) 10 | var assigns []string 11 | {{range $index, $v := .data.Fields}}if slices.Contains({{$.lowerStartCamelObject}}RowsExpectAutoFieldNames, condition.QuoteWithFlavor(m.flavor, "{{$v.Name.Source}}")) { 12 | assigns = append(assigns, sb.Assign(condition.QuoteWithFlavor(m.flavor, "{{$v.Name.Source}}"), {{if $.containsIndexCache}}newData{{else}}data{{end}}.{{$v.Name.ToCamel}})) 13 | } 14 | {{end}} 15 | sb.Set(assigns...) 16 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), {{if $.containsIndexCache}}newData{{else}}data{{end}}.{{.upperStartCamelPrimaryKey}})) 17 | statement, args := sb.BuildWithFlavor(m.flavor) 18 | if session != nil { 19 | return session.ExecCtx(ctx, statement, args...) 20 | } 21 | return conn.ExecCtx(ctx, statement, args...) 22 | }, {{.keyValues}}) 23 | return err 24 | } 25 | {{else}} 26 | func (m *default{{.upperStartCamelObject}}Model) Update(ctx context.Context, session sqlx.Session, data *{{.upperStartCamelObject}}) error { 27 | sb := sqlbuilder.Update(m.table) 28 | var assigns []string 29 | {{range $index, $v := .data.Fields}}if slices.Contains({{$.lowerStartCamelObject}}RowsExpectAutoFieldNames, condition.QuoteWithFlavor(m.flavor, "{{$v.Name.Source}}")) { 30 | assigns = append(assigns, sb.Assign(condition.QuoteWithFlavor(m.flavor, "{{$v.Name.Source}}"), data.{{$v.Name.ToCamel}})) 31 | } 32 | {{end}} 33 | sb.Set(assigns...) 34 | sb.Where(sb.EQ(condition.QuoteWithFlavor(m.flavor, "{{.originalPrimaryKey}}"), data.{{.upperStartCamelPrimaryKey}})) 35 | statement, args := sb.BuildWithFlavor(m.flavor) 36 | 37 | var err error 38 | if session != nil { 39 | _, err = session.ExecCtx(ctx, statement, args...) 40 | } else { 41 | _, err = m.conn.ExecCtx(ctx, statement, args...) 42 | } 43 | return err 44 | } 45 | {{end}} -------------------------------------------------------------------------------- /core/stores/condition/chain_test.go: -------------------------------------------------------------------------------- 1 | package condition 2 | 3 | import ( 4 | "testing" 5 | 6 | sqlbuilder "github.com/huandu/go-sqlbuilder" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestChain(t *testing.T) { 11 | sb := sqlbuilder.NewSelectBuilder().Select("name", "age").From("user") 12 | 13 | chain := NewChain() 14 | conds := chain. 15 | Equal("field1", "value1", WithSkip(true)). 16 | Equal("field2", "value2"). 17 | OrderByDesc("create_time"). 18 | OrderByAsc("sort"). 19 | Build() 20 | builder := SelectWithFlavor(sqlbuilder.MySQL, *sb, conds...) 21 | 22 | sql, args := builder.BuildWithFlavor(sqlbuilder.MySQL) 23 | assert.Equal(t, "SELECT name, age FROM user WHERE `field2` = ? ORDER BY `create_time` DESC, `sort` ASC", sql) 24 | assert.Equal(t, []any{"value2"}, args) 25 | } 26 | 27 | func TestChainJoin(t *testing.T) { 28 | sb := sqlbuilder.NewSelectBuilder().Select("user.name", "user.age").From("user") 29 | chain := NewChain() 30 | conds := chain. 31 | Equal("user.field", "value2"). 32 | Join(sqlbuilder.InnerJoin, "user_info", "user.id = user_info.user_id"). 33 | Build() 34 | builder := SelectWithFlavor(sqlbuilder.MySQL, *sb, conds...) 35 | sql, args := builder.BuildWithFlavor(sqlbuilder.MySQL) 36 | assert.Equal(t, "SELECT user.name, user.age FROM user INNER JOIN user_info ON user.id = user_info.user_id WHERE `user`.`field` = ?", sql) 37 | assert.Equal(t, []any{"value2"}, args) 38 | } 39 | 40 | func TestChainIsNull(t *testing.T) { 41 | sb := sqlbuilder.NewSelectBuilder().Select("user.name", "user.age").From("user") 42 | chain := NewChain() 43 | conds := chain. 44 | Equal("user.field", "value2"). 45 | IsNull("delete_at"). 46 | Build() 47 | builder := SelectWithFlavor(sqlbuilder.MySQL, *sb, conds...) 48 | sql, args := builder.BuildWithFlavor(sqlbuilder.MySQL) 49 | assert.Equal(t, "SELECT user.name, user.age FROM user WHERE `user`.`field` = ? AND `delete_at` IS NULL", sql) 50 | assert.Equal(t, []any{"value2"}, args) 51 | } 52 | 53 | func TestChainIsNotNull(t *testing.T) { 54 | sb := sqlbuilder.NewSelectBuilder().Select("user.name", "user.age").From("user") 55 | chain := NewChain() 56 | conds := chain. 57 | Equal("user.field", "value2"). 58 | IsNotNull("delete_at"). 59 | Build() 60 | builder := SelectWithFlavor(sqlbuilder.MySQL, *sb, conds...) 61 | sql, args := builder.BuildWithFlavor(sqlbuilder.MySQL) 62 | assert.Equal(t, "SELECT user.name, user.age FROM user WHERE `user`.`field` = ? AND `delete_at` IS NOT NULL", sql) 63 | assert.Equal(t, []any{"value2"}, args) 64 | } 65 | -------------------------------------------------------------------------------- /docs/src/.vuepress/theme.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { hopeTheme } from "vuepress-theme-hope"; 3 | import { enNavbar, zhNavbar } from "./navbar/index.js"; 4 | import sidebar from "./sidebar.js"; 5 | 6 | // @ts-ignore 7 | export default hopeTheme({ 8 | hostname: "https://docs.jzero.io", 9 | 10 | author: { 11 | name: "jaronnie", 12 | url: "https://github.com/jaronnie", 13 | }, 14 | 15 | iconAssets: "iconify", 16 | 17 | // made by https://gopherize.me 18 | // favicon.ico made by https://www.bitbug.net 19 | logo: "https://oss.jaronnie.com/hiking.svg", 20 | 21 | repo: "jzero-io/jzero", 22 | 23 | docsDir: "docs/src", 24 | 25 | locales: { 26 | "/": { 27 | // 导航栏 28 | navbar: zhNavbar, 29 | 30 | // 侧边栏 31 | sidebar, 32 | 33 | // 页脚 34 | footer: "", 35 | displayFooter: true, 36 | 37 | // Page meta 38 | metaLocales: { 39 | editLink: "在 GitHub 上编辑此页", 40 | }, 41 | }, 42 | "/en/": { 43 | // 导航栏 44 | navbar: enNavbar, 45 | 46 | // Page meta 47 | metaLocales: { 48 | editLink: "Edit this page on GitHub", 49 | }, 50 | }, 51 | }, 52 | 53 | // 在这里配置主题提供的插件 54 | plugins: { 55 | blog: { 56 | category: "category", 57 | tag: "tag", 58 | star: "star", 59 | }, 60 | comment: { 61 | provider: "Giscus", 62 | repo: "jzero-io/jzero", 63 | repoId: "R_kgDOLq1_9Q", 64 | category: "Announcements", 65 | categoryId: "DIC_kwDOLq1_9c4Cf5lp", 66 | }, 67 | 68 | components: { 69 | components: ["Badge", "VPCard"], 70 | }, 71 | 72 | // 此处开启了很多功能用于演示,你应仅保留用到的功能。 73 | mdEnhance: { 74 | align: true, 75 | attrs: true, 76 | codetabs: true, 77 | component: true, 78 | demo: true, 79 | figure: true, 80 | imgLazyload: true, 81 | imgSize: true, 82 | include: true, 83 | mark: true, 84 | stylize: [ 85 | { 86 | matcher: "Recommended", 87 | replacer: ({ tag }) => { 88 | if (tag === "em") 89 | return { 90 | tag: "Badge", 91 | attrs: { type: "tip" }, 92 | content: "Recommended", 93 | }; 94 | }, 95 | }, 96 | ], 97 | sub: true, 98 | sup: true, 99 | tabs: true, 100 | tasklist: true, 101 | vPre: true, 102 | }, 103 | }, 104 | }); 105 | -------------------------------------------------------------------------------- /cmd/jzero/internal/command/gen/genmodel/plugins.go: -------------------------------------------------------------------------------- 1 | package genmodel 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "slices" 8 | "strings" 9 | 10 | "github.com/rinchsan/gosimports" 11 | "github.com/samber/lo" 12 | "github.com/zeromicro/go-zero/core/logx" 13 | "github.com/zeromicro/go-zero/tools/goctl/util/pathx" 14 | 15 | "github.com/jzero-io/jzero/cmd/jzero/internal/embeded" 16 | "github.com/jzero-io/jzero/cmd/jzero/internal/pkg/templatex" 17 | ) 18 | 19 | func (jm *JzeroModel) GenRegister(tables []string) error { 20 | logx.Debugf("get register tables: %v", tables) 21 | 22 | slices.Sort(tables) 23 | 24 | var imports []string 25 | var tablePackages []string 26 | 27 | mutiModels := make(map[string][]string) 28 | 29 | for _, t := range tables { 30 | var isMutiModel bool 31 | if strings.Contains(t, ".") { 32 | t = filepath.Join(strings.Split(t, ".")...) 33 | isMutiModel = true 34 | } 35 | mf := filepath.Join("internal", "model", strings.ToLower(t)) 36 | if !pathx.FileExists(mf) { 37 | logx.Debugf("%s table generated code not exists, skip", t) 38 | continue 39 | } 40 | 41 | imports = append(imports, fmt.Sprintf("%s/internal/model/%s", jm.Module, strings.ToLower(filepath.ToSlash(t)))) 42 | 43 | if isMutiModel { 44 | imports = append(imports, fmt.Sprintf("%s/internal/model/%s", jm.Module, strings.ToLower(filepath.ToSlash(t)))) 45 | mutiModels[filepath.Dir(t)] = append(mutiModels[filepath.Dir(t)], strings.ToLower(filepath.Base(t))) 46 | } else { 47 | tablePackages = append(tablePackages, strings.ToLower(t)) 48 | } 49 | } 50 | 51 | logx.Debugf("get register imports: %v", imports) 52 | logx.Debugf("get register table packages: %v", tablePackages) 53 | logx.Debugf("get register muti models: %v", mutiModels) 54 | 55 | template, err := templatex.ParseTemplate(filepath.Join("model", "model.go.tpl"), map[string]any{ 56 | "Imports": imports, 57 | "TablePackages": tablePackages, 58 | "MutiModels": mutiModels, 59 | }, lo.If( 60 | // 兼容老版本 model 路径 61 | // TODO: wait to remove 62 | embeded.ReadTemplateFile(filepath.Join("plugins", "model", "model.go.tpl")) != nil, 63 | embeded.ReadTemplateFile(filepath.Join("plugins", "model", "model.go.tpl"))). 64 | Else( 65 | embeded.ReadTemplateFile(filepath.Join("model", "model.go.tpl")), 66 | ), 67 | ) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | format, err := gosimports.Process("", template, nil) 73 | if err != nil { 74 | return err 75 | } 76 | return os.WriteFile(filepath.Join("internal", "model", "model.go"), format, 0o644) 77 | } 78 | -------------------------------------------------------------------------------- /cmd/jzero/.template/frame/rpc/app/cmd/server.go.tpl: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/common-nighthawk/go-figure" 5 | "github.com/jzero-io/jzero/core/configcenter" 6 | "github.com/jzero-io/jzero/core/configcenter/subscriber" 7 | "github.com/spf13/cobra" 8 | "github.com/zeromicro/go-zero/core/logx" 9 | "github.com/zeromicro/go-zero/core/service" 10 | "github.com/zeromicro/go-zero/zrpc" 11 | "google.golang.org/grpc" 12 | "google.golang.org/grpc/reflection" 13 | 14 | "{{ .Module }}/internal/config" 15 | "{{ .Module }}/internal/custom" 16 | "{{ .Module }}/internal/middleware" 17 | "{{ .Module }}/internal/server" 18 | "{{ .Module }}/internal/svc" 19 | {{ if not .Serverless }}"{{ .Module }}/plugins"{{end}} 20 | ) 21 | 22 | // serverCmd represents the server command 23 | var serverCmd = &cobra.Command{ 24 | Use: "server", 25 | Short: "{{ .APP }} server", 26 | Long: "{{ .APP }} server", 27 | Run: func(cmd *cobra.Command, args []string) { 28 | cc := configcenter.MustNewConfigCenter[config.Config](configcenter.Config{ 29 | Type: "yaml", 30 | }, subscriber.MustNewFsnotifySubscriber(cmd.Flag("config").Value.String(), subscriber.WithUseEnv(true))) 31 | 32 | // set up logger 33 | logx.Must(logx.SetUp(cc.MustGetConfig().Log.LogConf)) 34 | 35 | printBanner(cc.MustGetConfig().Banner) 36 | printVersion() 37 | 38 | // create service context 39 | svcCtx := svc.NewServiceContext(cc) 40 | // create zrpc server 41 | zrpcServer := zrpc.MustNewServer(cc.MustGetConfig().Zrpc.RpcServerConf, func(grpcServer *grpc.Server) { 42 | server.RegisterZrpcServer(grpcServer, svcCtx) 43 | {{if not .Serverless }}// register plugins 44 | plugins.LoadPlugins(grpcServer, svcCtx){{end}} 45 | if cc.MustGetConfig().Zrpc.Mode == service.DevMode || cc.MustGetConfig().Zrpc.Mode == service.TestMode { 46 | reflection.Register(grpcServer) 47 | } 48 | }) 49 | // create custom server 50 | customServer := custom.New() 51 | // register middleware 52 | middleware.Register(zrpcServer) 53 | 54 | group := service.NewServiceGroup() 55 | group.Add(zrpcServer) 56 | group.Add(customServer) 57 | 58 | logx.Infof("Starting rpc server at %s...", cc.MustGetConfig().Zrpc.ListenOn) 59 | group.Start() 60 | }, 61 | } 62 | 63 | func printBanner(c config.BannerConf) { 64 | figure.NewColorFigure(c.Text, c.FontName, c.Color, true).Print() 65 | } 66 | 67 | func init() { 68 | rootCmd.AddCommand(serverCmd) 69 | } 70 | -------------------------------------------------------------------------------- /cmd/jzero/.template/go-zero/api/handler.tpl: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. Templates Edited by jzero. DO NOT EDIT. 2 | 3 | package {{.PkgName}} 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/zeromicro/go-zero/rest/httpx" 9 | 10 | {{.ImportPackages}} 11 | ) 12 | 13 | {{if .HasDoc}}{{.Doc}}{{end}} 14 | func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { 15 | {{ if and .HasRequest .HasResp }}return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.{{.RequestType}} 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.ErrorCtx(r.Context(), w, err) 19 | return 20 | } 21 | 22 | l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx, r) 23 | resp, err := l.{{.Call}}(&req) 24 | if err != nil { 25 | httpx.ErrorCtx(r.Context(), w, err) 26 | } else { 27 | httpx.OkJsonCtx(r.Context(), w, resp) 28 | } 29 | } {{else if and .HasRequest (not .HasResp)}}return func(w http.ResponseWriter, r *http.Request) { 30 | var req types.{{.RequestType}} 31 | if err := httpx.Parse(r, &req); err != nil { 32 | httpx.ErrorCtx(r.Context(), w, err) 33 | return 34 | } 35 | 36 | l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx, r, w) 37 | err := l.{{.Call}}(&req) 38 | if err != nil { 39 | httpx.ErrorCtx(r.Context(), w, err) 40 | } else { 41 | httpx.Ok(w) 42 | } 43 | } {{else if and (not .HasRequest) .HasResp}}return func(w http.ResponseWriter, r *http.Request) { 44 | l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx, r) 45 | resp, err := l.{{.Call}}() 46 | if err != nil { 47 | httpx.ErrorCtx(r.Context(), w, err) 48 | } else { 49 | httpx.OkJsonCtx(r.Context(), w, resp) 50 | } 51 | } {{else}}return func(w http.ResponseWriter, r *http.Request) { 52 | l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx, r, w) 53 | err := l.{{.Call}}() 54 | if err != nil { 55 | httpx.ErrorCtx(r.Context(), w, err) 56 | } else { 57 | httpx.Ok(w) 58 | } 59 | }{{end}} 60 | } -------------------------------------------------------------------------------- /cmd/jzero/internal/command/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2025 jaronnie 3 | */ 4 | 5 | package migrate 6 | 7 | import ( 8 | "fmt" 9 | 10 | _ "github.com/golang-migrate/migrate/v4/database/mysql" 11 | _ "github.com/golang-migrate/migrate/v4/database/pgx/v5" 12 | _ "github.com/golang-migrate/migrate/v4/database/sqlite" 13 | _ "github.com/golang-migrate/migrate/v4/source/file" 14 | "github.com/spf13/cobra" 15 | 16 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/migrate/migratedown" 17 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/migrate/migrategoto" 18 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/migrate/migrateup" 19 | "github.com/jzero-io/jzero/cmd/jzero/internal/command/migrate/migrateversion" 20 | ) 21 | 22 | // migrateCmd represents the migrate command 23 | var migrateCmd = &cobra.Command{ 24 | Use: "migrate", 25 | Short: "migrate model by desc/sql_migration", 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | fmt.Println(cmd.UsageString()) 28 | return nil 29 | }, 30 | } 31 | 32 | var migrateUpCmd = &cobra.Command{ 33 | Use: "up", 34 | Short: "migrate up", 35 | RunE: func(cmd *cobra.Command, args []string) error { 36 | return migrateup.Run(args) 37 | }, 38 | } 39 | 40 | var migrateDownCmd = &cobra.Command{ 41 | Use: "down", 42 | Short: "migrate down", 43 | RunE: func(cmd *cobra.Command, args []string) error { 44 | return migratedown.Run(args) 45 | }, 46 | } 47 | 48 | var migrateGotoCmd = &cobra.Command{ 49 | Use: "goto", 50 | Short: "migrate goto", 51 | RunE: func(cmd *cobra.Command, args []string) error { 52 | return migrategoto.Run(args) 53 | }, 54 | } 55 | 56 | var migrateVersionCmd = &cobra.Command{ 57 | Use: "version", 58 | Short: "migrate version", 59 | RunE: func(cmd *cobra.Command, args []string) error { 60 | return migrateversion.Run(args) 61 | }, 62 | } 63 | 64 | func GetCommand() *cobra.Command { 65 | migrateCmd.PersistentFlags().StringP("source", "", "file://desc/sql_migration", "migrate source") 66 | _ = migrateCmd.MarkFlagRequired("source") 67 | migrateCmd.PersistentFlags().StringP("datasource-url", "", "", "migrate datasource url") 68 | _ = migrateCmd.MarkFlagRequired("datasource-url") 69 | migrateCmd.PersistentFlags().StringP("x-migrations-table", "", "schema_migrations", "migrate table name") 70 | migrateCmd.PersistentFlags().BoolP("source-append-driver", "", false, "migrate source append driver") 71 | 72 | migrateCmd.AddCommand(migrateUpCmd) 73 | migrateCmd.AddCommand(migrateDownCmd) 74 | migrateCmd.AddCommand(migrateGotoCmd) 75 | migrateCmd.AddCommand(migrateVersionCmd) 76 | return migrateCmd 77 | } 78 | --------------------------------------------------------------------------------