diff --git a/examples/go.mod b/examples/go.mod index f4c97ce6e..c1f60ba52 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -45,6 +45,8 @@ require ( google.golang.org/grpc v1.44.0 google.golang.org/grpc/examples v0.0.0-20220105183818-2fb1ac854b20 // indirect google.golang.org/protobuf v1.27.1 + gorm.io/driver/mysql v1.3.2 + gorm.io/gorm v1.23.1 ) replace ( diff --git a/examples/go.sum b/examples/go.sum index 63b77d855..ba3a76044 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -215,7 +215,6 @@ github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/stdr v1.2.0 h1:j4LrlVXgrbIWO83mmQUnK0Hi+YnbD+vzrE1z/EphbFE= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -334,7 +333,6 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -435,6 +433,10 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= @@ -507,7 +509,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -556,7 +557,6 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -680,7 +680,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -849,7 +848,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1302,6 +1300,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.3.2 h1:QJryWiqQ91EvZ0jZL48NOpdlPdMjdip1hQ8bTgo4H7I= +gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= +gorm.io/gorm v1.23.1 h1:aj5IlhDzEPsoIyOPtTRVI+SyaN1u6k613sbt4pwbxG0= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/examples/transaction/gorm/Makefile b/examples/transaction/gorm/Makefile new file mode 100644 index 000000000..99f8034de --- /dev/null +++ b/examples/transaction/gorm/Makefile @@ -0,0 +1,79 @@ +GOPATH:=$(shell go env GOPATH) +VERSION=$(shell git describe --tags --always) +INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) +API_PROTO_FILES=$(shell find api -name *.proto) + +.PHONY: init +# init env +init: + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + go install github.com/go-kratos/kratos/cmd/kratos/v2@latest + go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest + go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2@latest + go install github.com/google/gnostic/cmd/protoc-gen-openapi@v0.6.1 + +.PHONY: errors +# generate errors code +errors: + protoc --proto_path=. \ + --proto_path=./third_party \ + --go_out=paths=source_relative:. \ + --go-errors_out=paths=source_relative:. \ + $(API_PROTO_FILES) + +.PHONY: config +# generate internal proto +config: + protoc --proto_path=. \ + --proto_path=./third_party \ + --go_out=paths=source_relative:. \ + $(INTERNAL_PROTO_FILES) + +.PHONY: api +# generate api proto +api: + protoc --proto_path=. \ + --proto_path=./third_party \ + --go_out=paths=source_relative:. \ + --go-http_out=paths=source_relative:. \ + --go-grpc_out=paths=source_relative:. \ + --openapi_out==paths=source_relative:. \ + $(API_PROTO_FILES) + +.PHONY: build +# build +build: + mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... + +.PHONY: generate +# generate +generate: + go generate ./... + +.PHONY: all +# generate all +all: + make api; + make errors; + make config; + make generate; + +# show help +help: + @echo '' + @echo 'Usage:' + @echo ' make [target]' + @echo '' + @echo 'Targets:' + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^# (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ + printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + +.DEFAULT_GOAL := help diff --git a/examples/transaction/gorm/README.md b/examples/transaction/gorm/README.md new file mode 100644 index 000000000..4c85ae7cb --- /dev/null +++ b/examples/transaction/gorm/README.md @@ -0,0 +1,19 @@ +# How to run this blog example server +1. You should ensure that your mysql server is running. +2. Ensure that the database named `testdb` has been created, + otherwise you should execute the following database script: +```mysql +create database testdb; +``` +3. Modify the `configs/config.yaml` file and add your mysql information in the data source: +```yaml +data: + database: + driver: mysql + source: root:password@tcp(127.0.0.1:3306)/testdb?parseTime=True +``` +4. Run your blog server: +```bash +$ go generate ./... +$ kratos run +``` diff --git a/examples/transaction/gorm/cmd/gorm/main.go b/examples/transaction/gorm/cmd/gorm/main.go new file mode 100644 index 000000000..2b5ad97d1 --- /dev/null +++ b/examples/transaction/gorm/cmd/gorm/main.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "os" + + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/v2" + "github.com/go-kratos/kratos/v2/config" + "github.com/go-kratos/kratos/v2/config/file" + "github.com/go-kratos/kratos/v2/log" + "github.com/go-kratos/kratos/v2/transport/grpc" + "github.com/go-kratos/kratos/v2/transport/http" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/sdk/resource" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" +) + +// go build -ldflags "-X main.Version=x.y.z" +var ( + // Name is the name of the compiled software. + Name string + // Version is the version of the compiled software. + Version string + // flagconf is the config flag. + flagconf string +) + +func init() { + flag.StringVar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml") +} + +func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App { + return kratos.New( + kratos.Name(Name), + kratos.Version(Version), + kratos.Metadata(map[string]string{}), + kratos.Logger(logger), + kratos.Server( + hs, + gs, + ), + ) +} + +// Set global trace provider +func setTracerProvider(url string) error { + // Create the Jaeger exporter + exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url))) + if err != nil { + return err + } + tp := tracesdk.NewTracerProvider( + // Set the sampling rate based on the parent span to 100% + tracesdk.WithSampler(tracesdk.ParentBased(tracesdk.TraceIDRatioBased(1.0))), + // Always be sure to batch in production. + tracesdk.WithBatcher(exp), + // Record information about this application in an Resource. + tracesdk.WithResource(resource.NewSchemaless( + semconv.ServiceNameKey.String(Name), + attribute.String("env", "dev"), + )), + ) + otel.SetTracerProvider(tp) + return nil +} + +func main() { + flag.Parse() + logger := log.NewStdLogger(os.Stdout) + + cfg := config.New( + config.WithSource( + file.NewSource(flagconf), + ), + ) + if err := cfg.Load(); err != nil { + panic(err) + } + + var bc conf.Bootstrap + if err := cfg.Scan(&bc); err != nil { + panic(err) + } + + if err := setTracerProvider(bc.Trace.Endpoint); err != nil { + panic(err) + } + + app, cleanup, err := initApp(bc.Server, bc.Data, logger) + if err != nil { + panic(err) + } + defer cleanup() + + // start and wait for stop signal + if err := app.Run(); err != nil { + panic(err) + } +} diff --git a/examples/transaction/gorm/cmd/gorm/wire.go b/examples/transaction/gorm/cmd/gorm/wire.go new file mode 100644 index 000000000..1c2baa371 --- /dev/null +++ b/examples/transaction/gorm/cmd/gorm/wire.go @@ -0,0 +1,22 @@ +//go:build wireinject +// +build wireinject + +// The build tag makes sure the stub is not built in the final build. + +package main + +import ( + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/data" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/server" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/service" + "github.com/go-kratos/kratos/v2" + "github.com/go-kratos/kratos/v2/log" + "github.com/google/wire" +) + +// initApp init kratos application. +func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) { + panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp)) +} diff --git a/examples/transaction/gorm/cmd/gorm/wire_gen.go b/examples/transaction/gorm/cmd/gorm/wire_gen.go new file mode 100644 index 000000000..bd0cefe78 --- /dev/null +++ b/examples/transaction/gorm/cmd/gorm/wire_gen.go @@ -0,0 +1,39 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject + +package main + +import ( + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/data" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/server" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/service" + "github.com/go-kratos/kratos/v2" + "github.com/go-kratos/kratos/v2/log" +) + +// Injectors from wire.go: + +// initApp init kratos application. +func initApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) { + db := data.NewDB(confData, logger) + dataData, cleanup, err := data.NewData(db, logger) + if err != nil { + return nil, nil, err + } + userRepo := data.NewUserRepo(dataData, logger) + cardRepo := data.NewCardRepo(dataData, logger) + transaction := data.NewTransaction(dataData) + userUsecase := biz.NewUserUsecase(userRepo, cardRepo, transaction, logger) + transactionService := service.NewTransactionService(userUsecase, logger) + httpServer := server.NewHTTPServer(confServer, logger, transactionService) + grpcServer := server.NewGRPCServer(confServer, logger, transactionService) + app := newApp(logger, httpServer, grpcServer) + return app, func() { + cleanup() + }, nil +} diff --git a/examples/transaction/gorm/configs/config.yaml b/examples/transaction/gorm/configs/config.yaml new file mode 100644 index 000000000..971033aa3 --- /dev/null +++ b/examples/transaction/gorm/configs/config.yaml @@ -0,0 +1,18 @@ +trace: + endpoint: http://127.0.0.1:14268/api/traces +server: + http: + addr: 0.0.0.0:8000 + timeout: 1s + grpc: + addr: 0.0.0.0:9000 + timeout: 1s +data: + database: + driver: mysql + source: root:root@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local + redis: + addr: 127.0.0.1:6379 + dial_timeout: 1s + read_timeout: 0.4s + write_timeout: 0.6s \ No newline at end of file diff --git a/examples/transaction/gorm/generate.go b/examples/transaction/gorm/generate.go new file mode 100644 index 000000000..4aac2aa9f --- /dev/null +++ b/examples/transaction/gorm/generate.go @@ -0,0 +1,3 @@ +package generate + +//go:generate kratos proto client . diff --git a/examples/transaction/gorm/internal/biz/README.md b/examples/transaction/gorm/internal/biz/README.md new file mode 100644 index 000000000..26a66b630 --- /dev/null +++ b/examples/transaction/gorm/internal/biz/README.md @@ -0,0 +1 @@ +# Biz diff --git a/examples/transaction/gorm/internal/biz/biz.go b/examples/transaction/gorm/internal/biz/biz.go new file mode 100644 index 000000000..f2ca2350f --- /dev/null +++ b/examples/transaction/gorm/internal/biz/biz.go @@ -0,0 +1,14 @@ +package biz + +import ( + "context" + + "github.com/google/wire" +) + +// ProviderSet is biz providers. +var ProviderSet = wire.NewSet(NewUserUsecase) + +type Transaction interface { + ExecTx(context.Context, func(ctx context.Context) error) error +} diff --git a/examples/transaction/gorm/internal/biz/transaction.go b/examples/transaction/gorm/internal/biz/transaction.go new file mode 100644 index 000000000..a0ed8001c --- /dev/null +++ b/examples/transaction/gorm/internal/biz/transaction.go @@ -0,0 +1,52 @@ +package biz + +import ( + "context" + + "github.com/go-kratos/kratos/v2/log" +) + +type User struct { + Name string + Email string +} + +type UserRepo interface { + CreateUser(ctx context.Context, a *User) (int64, error) +} + +type CardRepo interface { + CreateCard(ctx context.Context, id int64) (int64, error) +} + +type UserUsecase struct { + userRepo UserRepo + cardRepo CardRepo + tm Transaction +} + +func NewUserUsecase(user UserRepo, card CardRepo, tm Transaction, logger log.Logger) *UserUsecase { + return &UserUsecase{userRepo: user, cardRepo: card, tm: tm} +} + +func (u *UserUsecase) CreateUser(ctx context.Context, m *User) (int, error) { + var ( + err error + id int64 + ) + err = u.tm.ExecTx(ctx, func(ctx context.Context) error { + id, err = u.userRepo.CreateUser(ctx, m) + if err != nil { + return err + } + _, err = u.cardRepo.CreateCard(ctx, id) + if err != nil { + return err + } + return nil + }) + if err != nil { + return 0, err + } + return int(id), nil +} diff --git a/examples/transaction/gorm/internal/conf/conf.pb.go b/examples/transaction/gorm/internal/conf/conf.pb.go new file mode 100644 index 000000000..e57b932f2 --- /dev/null +++ b/examples/transaction/gorm/internal/conf/conf.pb.go @@ -0,0 +1,763 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.8 +// source: conf.proto + +package conf + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Bootstrap struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Trace *Trace `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` + Server *Server `protobuf:"bytes,2,opt,name=server,proto3" json:"server,omitempty"` + Data *Data `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Bootstrap) Reset() { + *x = Bootstrap{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bootstrap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bootstrap) ProtoMessage() {} + +func (x *Bootstrap) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bootstrap.ProtoReflect.Descriptor instead. +func (*Bootstrap) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{0} +} + +func (x *Bootstrap) GetTrace() *Trace { + if x != nil { + return x.Trace + } + return nil +} + +func (x *Bootstrap) GetServer() *Server { + if x != nil { + return x.Server + } + return nil +} + +func (x *Bootstrap) GetData() *Data { + if x != nil { + return x.Data + } + return nil +} + +type Server struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Http *Server_HTTP `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"` + Grpc *Server_GRPC `protobuf:"bytes,2,opt,name=grpc,proto3" json:"grpc,omitempty"` +} + +func (x *Server) Reset() { + *x = Server{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Server) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server) ProtoMessage() {} + +func (x *Server) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server.ProtoReflect.Descriptor instead. +func (*Server) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{1} +} + +func (x *Server) GetHttp() *Server_HTTP { + if x != nil { + return x.Http + } + return nil +} + +func (x *Server) GetGrpc() *Server_GRPC { + if x != nil { + return x.Grpc + } + return nil +} + +type Data struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Database *Data_Database `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"` + Redis *Data_Redis `protobuf:"bytes,2,opt,name=redis,proto3" json:"redis,omitempty"` +} + +func (x *Data) Reset() { + *x = Data{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Data) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data) ProtoMessage() {} + +func (x *Data) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data.ProtoReflect.Descriptor instead. +func (*Data) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{2} +} + +func (x *Data) GetDatabase() *Data_Database { + if x != nil { + return x.Database + } + return nil +} + +func (x *Data) GetRedis() *Data_Redis { + if x != nil { + return x.Redis + } + return nil +} + +type Trace struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Endpoint string `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"` +} + +func (x *Trace) Reset() { + *x = Trace{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Trace) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Trace) ProtoMessage() {} + +func (x *Trace) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Trace.ProtoReflect.Descriptor instead. +func (*Trace) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{3} +} + +func (x *Trace) GetEndpoint() string { + if x != nil { + return x.Endpoint + } + return "" +} + +type Server_HTTP struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` +} + +func (x *Server_HTTP) Reset() { + *x = Server_HTTP{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Server_HTTP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server_HTTP) ProtoMessage() {} + +func (x *Server_HTTP) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server_HTTP.ProtoReflect.Descriptor instead. +func (*Server_HTTP) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *Server_HTTP) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Server_HTTP) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Server_HTTP) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +type Server_GRPC struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` +} + +func (x *Server_GRPC) Reset() { + *x = Server_GRPC{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Server_GRPC) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server_GRPC) ProtoMessage() {} + +func (x *Server_GRPC) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server_GRPC.ProtoReflect.Descriptor instead. +func (*Server_GRPC) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *Server_GRPC) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Server_GRPC) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Server_GRPC) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +type Data_Database struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Driver string `protobuf:"bytes,1,opt,name=driver,proto3" json:"driver,omitempty"` + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *Data_Database) Reset() { + *x = Data_Database{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Data_Database) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data_Database) ProtoMessage() {} + +func (x *Data_Database) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data_Database.ProtoReflect.Descriptor instead. +func (*Data_Database) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *Data_Database) GetDriver() string { + if x != nil { + return x.Driver + } + return "" +} + +func (x *Data_Database) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +type Data_Redis struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + Db int32 `protobuf:"varint,4,opt,name=db,proto3" json:"db,omitempty"` + DialTimeout *durationpb.Duration `protobuf:"bytes,5,opt,name=dial_timeout,json=dialTimeout,proto3" json:"dial_timeout,omitempty"` + ReadTimeout *durationpb.Duration `protobuf:"bytes,6,opt,name=read_timeout,json=readTimeout,proto3" json:"read_timeout,omitempty"` + WriteTimeout *durationpb.Duration `protobuf:"bytes,7,opt,name=write_timeout,json=writeTimeout,proto3" json:"write_timeout,omitempty"` +} + +func (x *Data_Redis) Reset() { + *x = Data_Redis{} + if protoimpl.UnsafeEnabled { + mi := &file_conf_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Data_Redis) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data_Redis) ProtoMessage() {} + +func (x *Data_Redis) ProtoReflect() protoreflect.Message { + mi := &file_conf_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data_Redis.ProtoReflect.Descriptor instead. +func (*Data_Redis) Descriptor() ([]byte, []int) { + return file_conf_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *Data_Redis) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Data_Redis) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Data_Redis) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *Data_Redis) GetDb() int32 { + if x != nil { + return x.Db + } + return 0 +} + +func (x *Data_Redis) GetDialTimeout() *durationpb.Duration { + if x != nil { + return x.DialTimeout + } + return nil +} + +func (x *Data_Redis) GetReadTimeout() *durationpb.Duration { + if x != nil { + return x.ReadTimeout + } + return nil +} + +func (x *Data_Redis) GetWriteTimeout() *durationpb.Duration { + if x != nil { + return x.WriteTimeout + } + return nil +} + +var File_conf_proto protoreflect.FileDescriptor + +var file_conf_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x6b, 0x72, + 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, + 0x6e, 0x66, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xa4, 0x01, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, + 0x12, 0x31, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x05, 0x74, 0x72, + 0x61, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xcc, 0x02, 0x0a, 0x06, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x35, 0x0a, 0x04, 0x67, + 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6b, 0x72, 0x61, 0x74, + 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, 0x72, + 0x70, 0x63, 0x1a, 0x69, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, 0x69, 0x0a, + 0x04, 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, + 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, + 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xdb, 0x03, 0x0a, 0x04, 0x44, 0x61, 0x74, + 0x61, 0x12, 0x3f, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x72, 0x65, 0x64, 0x69, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, + 0x64, 0x69, 0x73, 0x52, 0x05, 0x72, 0x65, 0x64, 0x69, 0x73, 0x1a, 0x3a, 0x0a, 0x08, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0x9d, 0x02, 0x0a, 0x05, 0x52, 0x65, 0x64, 0x69, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x62, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x62, 0x12, 0x3c, 0x0a, 0x0c, 0x64, 0x69, + 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x69, 0x61, + 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x77, 0x72, 0x69, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x23, 0x0a, 0x05, 0x54, 0x72, 0x61, 0x63, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x3e, 0x5a, 0x3c, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, + 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_conf_proto_rawDescOnce sync.Once + file_conf_proto_rawDescData = file_conf_proto_rawDesc +) + +func file_conf_proto_rawDescGZIP() []byte { + file_conf_proto_rawDescOnce.Do(func() { + file_conf_proto_rawDescData = protoimpl.X.CompressGZIP(file_conf_proto_rawDescData) + }) + return file_conf_proto_rawDescData +} + +var file_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_conf_proto_goTypes = []interface{}{ + (*Bootstrap)(nil), // 0: kratos.internal.conf.Bootstrap + (*Server)(nil), // 1: kratos.internal.conf.Server + (*Data)(nil), // 2: kratos.internal.conf.Data + (*Trace)(nil), // 3: kratos.internal.conf.Trace + (*Server_HTTP)(nil), // 4: kratos.internal.conf.Server.HTTP + (*Server_GRPC)(nil), // 5: kratos.internal.conf.Server.GRPC + (*Data_Database)(nil), // 6: kratos.internal.conf.Data.Database + (*Data_Redis)(nil), // 7: kratos.internal.conf.Data.Redis + (*durationpb.Duration)(nil), // 8: google.protobuf.Duration +} +var file_conf_proto_depIdxs = []int32{ + 3, // 0: kratos.internal.conf.Bootstrap.trace:type_name -> kratos.internal.conf.Trace + 1, // 1: kratos.internal.conf.Bootstrap.server:type_name -> kratos.internal.conf.Server + 2, // 2: kratos.internal.conf.Bootstrap.data:type_name -> kratos.internal.conf.Data + 4, // 3: kratos.internal.conf.Server.http:type_name -> kratos.internal.conf.Server.HTTP + 5, // 4: kratos.internal.conf.Server.grpc:type_name -> kratos.internal.conf.Server.GRPC + 6, // 5: kratos.internal.conf.Data.database:type_name -> kratos.internal.conf.Data.Database + 7, // 6: kratos.internal.conf.Data.redis:type_name -> kratos.internal.conf.Data.Redis + 8, // 7: kratos.internal.conf.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 8, // 8: kratos.internal.conf.Server.GRPC.timeout:type_name -> google.protobuf.Duration + 8, // 9: kratos.internal.conf.Data.Redis.dial_timeout:type_name -> google.protobuf.Duration + 8, // 10: kratos.internal.conf.Data.Redis.read_timeout:type_name -> google.protobuf.Duration + 8, // 11: kratos.internal.conf.Data.Redis.write_timeout:type_name -> google.protobuf.Duration + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_conf_proto_init() } +func file_conf_proto_init() { + if File_conf_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_conf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bootstrap); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Server); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Data); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Trace); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Server_HTTP); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Server_GRPC); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Data_Database); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_conf_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Data_Redis); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_conf_proto_rawDesc, + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_conf_proto_goTypes, + DependencyIndexes: file_conf_proto_depIdxs, + MessageInfos: file_conf_proto_msgTypes, + }.Build() + File_conf_proto = out.File + file_conf_proto_rawDesc = nil + file_conf_proto_goTypes = nil + file_conf_proto_depIdxs = nil +} diff --git a/examples/transaction/gorm/internal/conf/conf.proto b/examples/transaction/gorm/internal/conf/conf.proto new file mode 100644 index 000000000..491c21a13 --- /dev/null +++ b/examples/transaction/gorm/internal/conf/conf.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; +package kratos.internal.conf; + +option go_package = "github.com/go-kratos/kratos/examples/blog/internal/conf;conf"; + +import "google/protobuf/duration.proto"; + +message Bootstrap { + Trace trace = 1; + Server server = 2; + Data data = 3; +} + +message Server { + message HTTP { + string network = 1; + string addr = 2; + google.protobuf.Duration timeout = 3; + } + message GRPC { + string network = 1; + string addr = 2; + google.protobuf.Duration timeout = 3; + } + HTTP http = 1; + GRPC grpc = 2; +} + +message Data { + message Database { + string driver = 1; + string source = 2; + } + message Redis { + string network = 1; + string addr = 2; + string password = 3; + int32 db = 4; + google.protobuf.Duration dial_timeout = 5; + google.protobuf.Duration read_timeout = 6; + google.protobuf.Duration write_timeout = 7; + } + Database database = 1; + Redis redis = 2; +} + +message Trace { + string endpoint = 1; +} \ No newline at end of file diff --git a/examples/transaction/gorm/internal/data/README.md b/examples/transaction/gorm/internal/data/README.md new file mode 100644 index 000000000..a9f7e8dad --- /dev/null +++ b/examples/transaction/gorm/internal/data/README.md @@ -0,0 +1,5 @@ +# Data + +``` +go generate ./ent +``` \ No newline at end of file diff --git a/examples/transaction/gorm/internal/data/data.go b/examples/transaction/gorm/internal/data/data.go new file mode 100644 index 000000000..031e4bb96 --- /dev/null +++ b/examples/transaction/gorm/internal/data/data.go @@ -0,0 +1,71 @@ +package data + +import ( + "context" + + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/v2/log" + "github.com/google/wire" + "gorm.io/driver/mysql" + "gorm.io/gorm" + + // init mysql driver + _ "github.com/go-sql-driver/mysql" +) + +// ProviderSet is data providers. +var ProviderSet = wire.NewSet(NewData, NewDB, NewTransaction, NewUserRepo, NewCardRepo) + +// Data . +type Data struct { + db *gorm.DB + log *log.Helper +} + +type contextTxKey struct{} + +func (d *Data) ExecTx(ctx context.Context, fn func(ctx context.Context) error) error { + return d.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + ctx = context.WithValue(ctx, contextTxKey{}, tx) + return fn(ctx) + }) +} + +func (d *Data) DB(ctx context.Context) *gorm.DB { + tx, ok := ctx.Value(contextTxKey{}).(*gorm.DB) + if ok { + return tx + } + return d.db +} + +// NewTransaction . +func NewTransaction(d *Data) biz.Transaction { + return d +} + +// NewData . +func NewData(db *gorm.DB, logger log.Logger) (*Data, func(), error) { + l := log.NewHelper(log.With(logger, "module", "transaction/data")) + d := &Data{ + db: db, + log: l, + } + return d, func() { + }, nil +} + +// NewDB gorm Connecting to a Database +func NewDB(conf *conf.Data, logger log.Logger) *gorm.DB { + log := log.NewHelper(log.With(logger, "module", "order-service/data/gorm")) + + db, err := gorm.Open(mysql.Open(conf.Database.Source), &gorm.Config{}) + if err != nil { + log.Fatalf("failed opening connection to mysql: %v", err) + } + if err := db.AutoMigrate(&User{}, &Card{}); err != nil { + log.Fatal(err) + } + return db +} diff --git a/examples/transaction/gorm/internal/data/transaction.go b/examples/transaction/gorm/internal/data/transaction.go new file mode 100644 index 000000000..6e4b1d3c7 --- /dev/null +++ b/examples/transaction/gorm/internal/data/transaction.go @@ -0,0 +1,64 @@ +package data + +import ( + "context" + "time" + + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + "github.com/go-kratos/kratos/v2/log" +) + +type userRepo struct { + data *Data + log *log.Helper +} + +type cardRepo struct { + data *Data + log *log.Helper +} + +type User struct { + ID int64 + Name string + Email string + CreatedAt time.Time + UpdatedAt time.Time +} + +type Card struct { + ID int64 + UserID int64 + Money int64 + CreatedAt time.Time + UpdatedAt time.Time +} + +// NewUserRepo . +func NewUserRepo(data *Data, logger log.Logger) biz.UserRepo { + return &userRepo{ + data: data, + log: log.NewHelper(logger), + } +} + +func (u *userRepo) CreateUser(ctx context.Context, m *biz.User) (int64, error) { + user := User{Name: m.Name, Email: m.Email} + result := u.data.DB(ctx).Create(&user) + return user.ID, result.Error +} + +func NewCardRepo(data *Data, logger log.Logger) biz.CardRepo { + return &cardRepo{ + data: data, + log: log.NewHelper(logger), + } +} + +func (c *cardRepo) CreateCard(ctx context.Context, id int64) (int64, error) { + var card Card + card.UserID = id + card.Money = 1000 + result := c.data.DB(ctx).Save(&card) + return card.ID, result.Error +} diff --git a/examples/transaction/gorm/internal/server/grpc.go b/examples/transaction/gorm/internal/server/grpc.go new file mode 100644 index 000000000..44c568f94 --- /dev/null +++ b/examples/transaction/gorm/internal/server/grpc.go @@ -0,0 +1,37 @@ +package server + +import ( + v1 "github.com/go-kratos/kratos/examples/transaction/api/transaction/v1" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/service" + "github.com/go-kratos/kratos/v2/log" + "github.com/go-kratos/kratos/v2/middleware/logging" + "github.com/go-kratos/kratos/v2/middleware/recovery" + "github.com/go-kratos/kratos/v2/middleware/tracing" + "github.com/go-kratos/kratos/v2/middleware/validate" + "github.com/go-kratos/kratos/v2/transport/grpc" +) + +// NewGRPCServer new a gRPC server. +func NewGRPCServer(c *conf.Server, logger log.Logger, transaction *service.TransactionService) *grpc.Server { + opts := []grpc.ServerOption{ + grpc.Middleware( + recovery.Recovery(), + tracing.Server(), + logging.Server(logger), + validate.Validator(), + ), + } + if c.Grpc.Network != "" { + opts = append(opts, grpc.Network(c.Grpc.Network)) + } + if c.Grpc.Addr != "" { + opts = append(opts, grpc.Address(c.Grpc.Addr)) + } + if c.Grpc.Timeout != nil { + opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) + } + srv := grpc.NewServer(opts...) + v1.RegisterTransactionServiceServer(srv, transaction) + return srv +} diff --git a/examples/transaction/gorm/internal/server/http.go b/examples/transaction/gorm/internal/server/http.go new file mode 100644 index 000000000..2de797f2e --- /dev/null +++ b/examples/transaction/gorm/internal/server/http.go @@ -0,0 +1,37 @@ +package server + +import ( + v1 "github.com/go-kratos/kratos/examples/transaction/api/transaction/v1" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/conf" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/service" + "github.com/go-kratos/kratos/v2/log" + "github.com/go-kratos/kratos/v2/middleware/logging" + "github.com/go-kratos/kratos/v2/middleware/recovery" + "github.com/go-kratos/kratos/v2/middleware/tracing" + "github.com/go-kratos/kratos/v2/middleware/validate" + "github.com/go-kratos/kratos/v2/transport/http" +) + +// NewHTTPServer new a HTTP server. +func NewHTTPServer(c *conf.Server, logger log.Logger, transaction *service.TransactionService) *http.Server { + opts := []http.ServerOption{ + http.Middleware( + recovery.Recovery(), + tracing.Server(), + logging.Server(logger), + validate.Validator(), + ), + } + if c.Http.Network != "" { + opts = append(opts, http.Network(c.Http.Network)) + } + if c.Http.Addr != "" { + opts = append(opts, http.Address(c.Http.Addr)) + } + if c.Http.Timeout != nil { + opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) + } + srv := http.NewServer(opts...) + v1.RegisterTransactionServiceHTTPServer(srv, transaction) + return srv +} diff --git a/examples/transaction/gorm/internal/server/server.go b/examples/transaction/gorm/internal/server/server.go new file mode 100644 index 000000000..4d267a7a3 --- /dev/null +++ b/examples/transaction/gorm/internal/server/server.go @@ -0,0 +1,8 @@ +package server + +import ( + "github.com/google/wire" +) + +// ProviderSet is server providers. +var ProviderSet = wire.NewSet(NewHTTPServer, NewGRPCServer) diff --git a/examples/transaction/gorm/internal/service/README.md b/examples/transaction/gorm/internal/service/README.md new file mode 100644 index 000000000..42321b7b1 --- /dev/null +++ b/examples/transaction/gorm/internal/service/README.md @@ -0,0 +1 @@ +# Service diff --git a/examples/transaction/gorm/internal/service/service.go b/examples/transaction/gorm/internal/service/service.go new file mode 100644 index 000000000..ad3e067d3 --- /dev/null +++ b/examples/transaction/gorm/internal/service/service.go @@ -0,0 +1,20 @@ +package service + +import ( + pb "github.com/go-kratos/kratos/examples/transaction/api/transaction/v1" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + + "github.com/go-kratos/kratos/v2/log" + "github.com/google/wire" +) + +// ProviderSet is service providers. +var ProviderSet = wire.NewSet(NewTransactionService) + +type TransactionService struct { + pb.UnimplementedTransactionServiceServer + + log *log.Helper + + user *biz.UserUsecase +} diff --git a/examples/transaction/gorm/internal/service/transaction.go b/examples/transaction/gorm/internal/service/transaction.go new file mode 100644 index 000000000..69d075481 --- /dev/null +++ b/examples/transaction/gorm/internal/service/transaction.go @@ -0,0 +1,31 @@ +package service + +import ( + "context" + "strconv" + + pb "github.com/go-kratos/kratos/examples/transaction/api/transaction/v1" + "github.com/go-kratos/kratos/examples/transaction/gorm/internal/biz" + + "github.com/go-kratos/kratos/v2/log" +) + +func NewTransactionService(user *biz.UserUsecase, logger log.Logger) *TransactionService { + return &TransactionService{ + user: user, + log: log.NewHelper(logger), + } +} + +func (b *TransactionService) CreateUser(ctx context.Context, in *pb.CreateUserRequest) (*pb.CreateUserReply, error) { + id, err := b.user.CreateUser(ctx, &biz.User{ + Name: in.Name, + Email: in.Email, + }) + if err != nil { + return nil, err + } + return &pb.CreateUserReply{ + Id: strconv.Itoa(id), + }, nil +} diff --git a/examples/transaction/gorm/openapi.yaml b/examples/transaction/gorm/openapi.yaml new file mode 100644 index 000000000..c4afd3ba2 --- /dev/null +++ b/examples/transaction/gorm/openapi.yaml @@ -0,0 +1,126 @@ +# Generated with protoc-gen-openapi +# https://github.com/google/gnostic/tree/master/apps/protoc-gen-openapi + +openapi: 3.0.3 +info: + title: BlogService + version: 0.0.1 +paths: + /v1/article/: + get: + operationId: BlogService_ListArticle + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ListArticleReply' + post: + operationId: BlogService_CreateArticle + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateArticleRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CreateArticleReply' + /v1/article/{id}: + get: + operationId: BlogService_GetArticle + parameters: + - name: id + in: query + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/GetArticleReply' + put: + operationId: BlogService_UpdateArticle + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateArticleRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateArticleReply' + delete: + operationId: BlogService_DeleteArticle + parameters: + - name: id + in: query + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/DeleteArticleReply' +components: + schemas: + Article: + properties: + id: + type: integer + format: int64 + title: + type: string + content: + type: string + like: + type: integer + format: int64 + CreateArticleReply: + properties: + Article: + $ref: '#/components/schemas/Article' + CreateArticleRequest: + properties: + title: + type: string + content: + type: string + DeleteArticleReply: + properties: {} + GetArticleReply: + properties: + Article: + $ref: '#/components/schemas/Article' + ListArticleReply: + properties: + results: + type: array + items: + $ref: '#/components/schemas/Article' + UpdateArticleReply: + properties: + Article: + $ref: '#/components/schemas/Article' + UpdateArticleRequest: + properties: + id: + type: integer + format: int64 + title: + type: string + content: + type: string