├── .air.toml ├── .gitignore ├── Makefile ├── account.http ├── api ├── Makefile ├── buf.gen.yaml ├── buf.lock ├── buf.yaml └── proto │ └── v1 │ ├── account.pb.go │ ├── account.pb.gw.go │ ├── account.proto │ ├── account.swagger.json │ └── account_grpc.pb.go ├── cmd └── main.go ├── db ├── fixtures │ └── 20230309130154_create_test_account.sql ├── gen │ └── account │ │ └── public │ │ ├── model │ │ └── account.go │ │ └── table │ │ └── account.go └── migrations │ └── 20230225133922_create_account_table.sql ├── go.mod ├── go.sum ├── infrastructure └── local │ ├── .env │ ├── Dockerfile │ └── docker-compose.yaml ├── internal └── account │ ├── adapters │ ├── controllers │ │ ├── account-handler.go │ │ └── converters.go │ └── repositories │ │ ├── account-repository.go │ │ └── converters.go │ ├── domain │ └── account.go │ ├── services │ └── account-service.go │ └── usecases │ ├── account.go │ ├── create-account.go │ └── get-account-by-id.go ├── readme.md └── tests ├── account_test.go ├── create-account_test.go └── get-account-by-id_test.go /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | testdata_dir = "testdata" 3 | tmp_dir = "tmp" 4 | 5 | [build] 6 | args_bin = [] 7 | bin = "./tmp/main" 8 | cmd = "go build -o ./tmp/main ./cmd" 9 | delay = 0 10 | exclude_dir = ["assets", "tmp", "vendor", "testdata","db","tests","infrastructure"] 11 | exclude_file = [] 12 | exclude_regex = ["_test.go"] 13 | exclude_unchanged = false 14 | follow_symlink = false 15 | full_bin = "" 16 | include_dir = [] 17 | include_ext = ["go", "tpl", "tmpl", "html"] 18 | include_file = [] 19 | kill_delay = "0s" 20 | log = "build-errors.log" 21 | rerun = false 22 | rerun_delay = 500 23 | send_interrupt = false 24 | stop_on_error = false 25 | 26 | [color] 27 | app = "" 28 | build = "yellow" 29 | main = "magenta" 30 | runner = "green" 31 | watcher = "cyan" 32 | 33 | [log] 34 | main_only = false 35 | time = false 36 | 37 | [misc] 38 | clean_on_exit = false 39 | 40 | [screen] 41 | clear_on_rebuild = false 42 | keep_scroll = true 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /.vscode/ 3 | /tmp/ 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include infrastructure/local/.env 2 | 3 | GOOSE_RUN := go run github.com/pressly/goose/cmd/goose@latest 4 | JET_RUN:= go run github.com/go-jet/jet/v2/cmd/jet@latest 5 | POSTGRES_URI = "postgresql://$(DB_USER):$(DB_PASSWORD)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=$(DB_SSL_MODE)" 6 | 7 | .PHONY:up 8 | up: 9 | docker compose -f ./infrastructure/local/docker-compose.yaml up 10 | 11 | .PHONY: add-migration 12 | add-migration: 13 | $(GOOSE_RUN) -dir db/migrations postgres $(POSTGRES_URI) create new-migration sql 14 | 15 | .PHONY: add-fixture 16 | add-fixture: 17 | $(GOOSE_RUN) -dir db/fixtures postgres $(POSTGRES_URI) create new-fixture sql 18 | 19 | .PHONY:migrate-up 20 | migrate-up: 21 | $(GOOSE_RUN) -dir db/migrations postgres $(POSTGRES_URI) up 22 | 23 | .PHONY:fixtures-up 24 | fixtures-up: 25 | $(GOOSE_RUN) -dir db/fixtures postgres $(POSTGRES_URI) up 26 | 27 | .PHONY:gen-db 28 | gen-db: 29 | $(JET_RUN) -dsn=$(POSTGRES_URI) -schema=public -ignore-tables goose_db_version -path=db/gen 30 | -------------------------------------------------------------------------------- /account.http: -------------------------------------------------------------------------------- 1 | ### create new account 2 | POST http://localhost:8090/api/v1/account 3 | Content-Encoding: application/json; 4 | 5 | { 6 | "name": "test_name" 7 | } 8 | 9 | ### get account by id 10 | GET http://localhost:8090/api/v1/account/2 11 | -------------------------------------------------------------------------------- /api/Makefile: -------------------------------------------------------------------------------- 1 | OUT = ../../pkg/grpc_client 2 | SWAGGER = ../api 3 | INCLUDEDIR = $(CURDIR)/includes 4 | PROTOS = $(shell find . -type f -name '*.proto') 5 | 6 | BUF_VERSION:=v1.9.0 7 | SWAGGER_UI_VERSION:=v4.15.5 8 | 9 | 10 | all: gen 11 | 12 | .PHONY: gen 13 | gen: gen/proto 14 | 15 | gen/proto: 16 | go run github.com/bufbuild/buf/cmd/buf@$(BUF_VERSION) generate 17 | gen/swagger-ui: 18 | SWAGGER_UI_VERSION=$(SWAGGER_UI_VERSION) ./scripts/generate-swagger-ui.sh -------------------------------------------------------------------------------- /api/buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | managed: 3 | enabled: true 4 | go_package_prefix: 5 | default: github.com/sadensmol/article_my_clean_architecture_go_application 6 | except: 7 | - buf.build/googleapis/googleapis 8 | - buf.build/grpc-ecosystem/grpc-gateway 9 | plugins: 10 | - remote: buf.build/protocolbuffers/plugins/go:v1.28.0-1 11 | out: . 12 | opt: paths=source_relative 13 | - remote: buf.build/grpc/plugins/go:v1.2.0-1 14 | out: . 15 | opt: paths=source_relative,require_unimplemented_servers=false 16 | - remote: buf.build/grpc-ecosystem/plugins/grpc-gateway:v2.7.2-1 17 | out: . 18 | opt: paths=source_relative 19 | - remote: buf.build/grpc-ecosystem/plugins/openapiv2:v2.7.2-1 20 | out: . -------------------------------------------------------------------------------- /api/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v1 3 | deps: 4 | - remote: buf.build 5 | owner: googleapis 6 | repository: googleapis 7 | commit: 75b4300737fb4efca0831636be94e517 8 | - remote: buf.build 9 | owner: grpc-ecosystem 10 | repository: grpc-gateway 11 | commit: a1ecdc58eccd49aa8bea2a7a9022dc27 12 | -------------------------------------------------------------------------------- /api/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | name: buf.build/sadensmol/article_my_clean_architecture_go_application 3 | deps: 4 | - buf.build/googleapis/googleapis 5 | - buf.build/grpc-ecosystem/grpc-gateway 6 | lint: 7 | use: 8 | - DEFAULT 9 | -------------------------------------------------------------------------------- /api/proto/v1/account.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0-devel 4 | // protoc (unknown) 5 | // source: proto/v1/account.proto 6 | 7 | package contractv1 8 | 9 | import ( 10 | _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" 11 | _ "google.golang.org/genproto/googleapis/api/annotations" 12 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 13 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 14 | timestamppb "google.golang.org/protobuf/types/known/timestamppb" 15 | reflect "reflect" 16 | sync "sync" 17 | ) 18 | 19 | const ( 20 | // Verify that this generated code is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 22 | // Verify that runtime/protoimpl is sufficiently up-to-date. 23 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 24 | ) 25 | 26 | type AccountStatus int32 27 | 28 | const ( 29 | AccountStatus_ACCOUNT_STATUS_UNKNOWN AccountStatus = 0 30 | AccountStatus_ACCOUNT_STATUS_NEW AccountStatus = 1 31 | AccountStatus_ACCOUNT_STATUS_OPEN AccountStatus = 2 32 | AccountStatus_ACCOUNT_STATUS_CLOSED AccountStatus = 3 33 | ) 34 | 35 | // Enum value maps for AccountStatus. 36 | var ( 37 | AccountStatus_name = map[int32]string{ 38 | 0: "ACCOUNT_STATUS_UNKNOWN", 39 | 1: "ACCOUNT_STATUS_NEW", 40 | 2: "ACCOUNT_STATUS_OPEN", 41 | 3: "ACCOUNT_STATUS_CLOSED", 42 | } 43 | AccountStatus_value = map[string]int32{ 44 | "ACCOUNT_STATUS_UNKNOWN": 0, 45 | "ACCOUNT_STATUS_NEW": 1, 46 | "ACCOUNT_STATUS_OPEN": 2, 47 | "ACCOUNT_STATUS_CLOSED": 3, 48 | } 49 | ) 50 | 51 | func (x AccountStatus) Enum() *AccountStatus { 52 | p := new(AccountStatus) 53 | *p = x 54 | return p 55 | } 56 | 57 | func (x AccountStatus) String() string { 58 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 59 | } 60 | 61 | func (AccountStatus) Descriptor() protoreflect.EnumDescriptor { 62 | return file_proto_v1_account_proto_enumTypes[0].Descriptor() 63 | } 64 | 65 | func (AccountStatus) Type() protoreflect.EnumType { 66 | return &file_proto_v1_account_proto_enumTypes[0] 67 | } 68 | 69 | func (x AccountStatus) Number() protoreflect.EnumNumber { 70 | return protoreflect.EnumNumber(x) 71 | } 72 | 73 | // Deprecated: Use AccountStatus.Descriptor instead. 74 | func (AccountStatus) EnumDescriptor() ([]byte, []int) { 75 | return file_proto_v1_account_proto_rawDescGZIP(), []int{0} 76 | } 77 | 78 | type AccessLevel int32 79 | 80 | const ( 81 | AccessLevel_ACCOUNT_ACCESS_LEVEL_UNKNOWN AccessLevel = 0 82 | AccessLevel_ACCOUNT_ACCESS_LEVEL_FULL_ACCESS AccessLevel = 1 83 | AccessLevel_ACCOUNT_ACCESS_LEVEL_READ_ONLY AccessLevel = 2 84 | AccessLevel_ACCOUNT_ACCESS_LEVEL_NO_ACCESS AccessLevel = 3 85 | ) 86 | 87 | // Enum value maps for AccessLevel. 88 | var ( 89 | AccessLevel_name = map[int32]string{ 90 | 0: "ACCOUNT_ACCESS_LEVEL_UNKNOWN", 91 | 1: "ACCOUNT_ACCESS_LEVEL_FULL_ACCESS", 92 | 2: "ACCOUNT_ACCESS_LEVEL_READ_ONLY", 93 | 3: "ACCOUNT_ACCESS_LEVEL_NO_ACCESS", 94 | } 95 | AccessLevel_value = map[string]int32{ 96 | "ACCOUNT_ACCESS_LEVEL_UNKNOWN": 0, 97 | "ACCOUNT_ACCESS_LEVEL_FULL_ACCESS": 1, 98 | "ACCOUNT_ACCESS_LEVEL_READ_ONLY": 2, 99 | "ACCOUNT_ACCESS_LEVEL_NO_ACCESS": 3, 100 | } 101 | ) 102 | 103 | func (x AccessLevel) Enum() *AccessLevel { 104 | p := new(AccessLevel) 105 | *p = x 106 | return p 107 | } 108 | 109 | func (x AccessLevel) String() string { 110 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 111 | } 112 | 113 | func (AccessLevel) Descriptor() protoreflect.EnumDescriptor { 114 | return file_proto_v1_account_proto_enumTypes[1].Descriptor() 115 | } 116 | 117 | func (AccessLevel) Type() protoreflect.EnumType { 118 | return &file_proto_v1_account_proto_enumTypes[1] 119 | } 120 | 121 | func (x AccessLevel) Number() protoreflect.EnumNumber { 122 | return protoreflect.EnumNumber(x) 123 | } 124 | 125 | // Deprecated: Use AccessLevel.Descriptor instead. 126 | func (AccessLevel) EnumDescriptor() ([]byte, []int) { 127 | return file_proto_v1_account_proto_rawDescGZIP(), []int{1} 128 | } 129 | 130 | type Account struct { 131 | state protoimpl.MessageState 132 | sizeCache protoimpl.SizeCache 133 | unknownFields protoimpl.UnknownFields 134 | 135 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 136 | Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` 137 | Status AccountStatus `protobuf:"varint,3,opt,name=status,proto3,enum=me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountStatus" json:"status,omitempty"` 138 | OpenedDate *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=opened_date,json=openedDate,proto3" json:"opened_date,omitempty"` 139 | ClosedDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=closed_date,json=closedDate,proto3" json:"closed_date,omitempty"` 140 | AccessLevel AccessLevel `protobuf:"varint,6,opt,name=access_level,json=accessLevel,proto3,enum=me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel" json:"access_level,omitempty"` 141 | } 142 | 143 | func (x *Account) Reset() { 144 | *x = Account{} 145 | if protoimpl.UnsafeEnabled { 146 | mi := &file_proto_v1_account_proto_msgTypes[0] 147 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 148 | ms.StoreMessageInfo(mi) 149 | } 150 | } 151 | 152 | func (x *Account) String() string { 153 | return protoimpl.X.MessageStringOf(x) 154 | } 155 | 156 | func (*Account) ProtoMessage() {} 157 | 158 | func (x *Account) ProtoReflect() protoreflect.Message { 159 | mi := &file_proto_v1_account_proto_msgTypes[0] 160 | if protoimpl.UnsafeEnabled && x != nil { 161 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 162 | if ms.LoadMessageInfo() == nil { 163 | ms.StoreMessageInfo(mi) 164 | } 165 | return ms 166 | } 167 | return mi.MessageOf(x) 168 | } 169 | 170 | // Deprecated: Use Account.ProtoReflect.Descriptor instead. 171 | func (*Account) Descriptor() ([]byte, []int) { 172 | return file_proto_v1_account_proto_rawDescGZIP(), []int{0} 173 | } 174 | 175 | func (x *Account) GetId() int64 { 176 | if x != nil { 177 | return x.Id 178 | } 179 | return 0 180 | } 181 | 182 | func (x *Account) GetName() string { 183 | if x != nil { 184 | return x.Name 185 | } 186 | return "" 187 | } 188 | 189 | func (x *Account) GetStatus() AccountStatus { 190 | if x != nil { 191 | return x.Status 192 | } 193 | return AccountStatus_ACCOUNT_STATUS_UNKNOWN 194 | } 195 | 196 | func (x *Account) GetOpenedDate() *timestamppb.Timestamp { 197 | if x != nil { 198 | return x.OpenedDate 199 | } 200 | return nil 201 | } 202 | 203 | func (x *Account) GetClosedDate() *timestamppb.Timestamp { 204 | if x != nil { 205 | return x.ClosedDate 206 | } 207 | return nil 208 | } 209 | 210 | func (x *Account) GetAccessLevel() AccessLevel { 211 | if x != nil { 212 | return x.AccessLevel 213 | } 214 | return AccessLevel_ACCOUNT_ACCESS_LEVEL_UNKNOWN 215 | } 216 | 217 | type CreateAccountRequest struct { 218 | state protoimpl.MessageState 219 | sizeCache protoimpl.SizeCache 220 | unknownFields protoimpl.UnknownFields 221 | 222 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 223 | AccessLevel AccessLevel `protobuf:"varint,2,opt,name=accessLevel,proto3,enum=me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel" json:"accessLevel,omitempty"` 224 | } 225 | 226 | func (x *CreateAccountRequest) Reset() { 227 | *x = CreateAccountRequest{} 228 | if protoimpl.UnsafeEnabled { 229 | mi := &file_proto_v1_account_proto_msgTypes[1] 230 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 231 | ms.StoreMessageInfo(mi) 232 | } 233 | } 234 | 235 | func (x *CreateAccountRequest) String() string { 236 | return protoimpl.X.MessageStringOf(x) 237 | } 238 | 239 | func (*CreateAccountRequest) ProtoMessage() {} 240 | 241 | func (x *CreateAccountRequest) ProtoReflect() protoreflect.Message { 242 | mi := &file_proto_v1_account_proto_msgTypes[1] 243 | if protoimpl.UnsafeEnabled && x != nil { 244 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 245 | if ms.LoadMessageInfo() == nil { 246 | ms.StoreMessageInfo(mi) 247 | } 248 | return ms 249 | } 250 | return mi.MessageOf(x) 251 | } 252 | 253 | // Deprecated: Use CreateAccountRequest.ProtoReflect.Descriptor instead. 254 | func (*CreateAccountRequest) Descriptor() ([]byte, []int) { 255 | return file_proto_v1_account_proto_rawDescGZIP(), []int{1} 256 | } 257 | 258 | func (x *CreateAccountRequest) GetName() string { 259 | if x != nil { 260 | return x.Name 261 | } 262 | return "" 263 | } 264 | 265 | func (x *CreateAccountRequest) GetAccessLevel() AccessLevel { 266 | if x != nil { 267 | return x.AccessLevel 268 | } 269 | return AccessLevel_ACCOUNT_ACCESS_LEVEL_UNKNOWN 270 | } 271 | 272 | type CreateAccountResponse struct { 273 | state protoimpl.MessageState 274 | sizeCache protoimpl.SizeCache 275 | unknownFields protoimpl.UnknownFields 276 | 277 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 278 | } 279 | 280 | func (x *CreateAccountResponse) Reset() { 281 | *x = CreateAccountResponse{} 282 | if protoimpl.UnsafeEnabled { 283 | mi := &file_proto_v1_account_proto_msgTypes[2] 284 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 285 | ms.StoreMessageInfo(mi) 286 | } 287 | } 288 | 289 | func (x *CreateAccountResponse) String() string { 290 | return protoimpl.X.MessageStringOf(x) 291 | } 292 | 293 | func (*CreateAccountResponse) ProtoMessage() {} 294 | 295 | func (x *CreateAccountResponse) ProtoReflect() protoreflect.Message { 296 | mi := &file_proto_v1_account_proto_msgTypes[2] 297 | if protoimpl.UnsafeEnabled && x != nil { 298 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 299 | if ms.LoadMessageInfo() == nil { 300 | ms.StoreMessageInfo(mi) 301 | } 302 | return ms 303 | } 304 | return mi.MessageOf(x) 305 | } 306 | 307 | // Deprecated: Use CreateAccountResponse.ProtoReflect.Descriptor instead. 308 | func (*CreateAccountResponse) Descriptor() ([]byte, []int) { 309 | return file_proto_v1_account_proto_rawDescGZIP(), []int{2} 310 | } 311 | 312 | func (x *CreateAccountResponse) GetId() int64 { 313 | if x != nil { 314 | return x.Id 315 | } 316 | return 0 317 | } 318 | 319 | type GetAccountRequest struct { 320 | state protoimpl.MessageState 321 | sizeCache protoimpl.SizeCache 322 | unknownFields protoimpl.UnknownFields 323 | 324 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 325 | } 326 | 327 | func (x *GetAccountRequest) Reset() { 328 | *x = GetAccountRequest{} 329 | if protoimpl.UnsafeEnabled { 330 | mi := &file_proto_v1_account_proto_msgTypes[3] 331 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 332 | ms.StoreMessageInfo(mi) 333 | } 334 | } 335 | 336 | func (x *GetAccountRequest) String() string { 337 | return protoimpl.X.MessageStringOf(x) 338 | } 339 | 340 | func (*GetAccountRequest) ProtoMessage() {} 341 | 342 | func (x *GetAccountRequest) ProtoReflect() protoreflect.Message { 343 | mi := &file_proto_v1_account_proto_msgTypes[3] 344 | if protoimpl.UnsafeEnabled && x != nil { 345 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 346 | if ms.LoadMessageInfo() == nil { 347 | ms.StoreMessageInfo(mi) 348 | } 349 | return ms 350 | } 351 | return mi.MessageOf(x) 352 | } 353 | 354 | // Deprecated: Use GetAccountRequest.ProtoReflect.Descriptor instead. 355 | func (*GetAccountRequest) Descriptor() ([]byte, []int) { 356 | return file_proto_v1_account_proto_rawDescGZIP(), []int{3} 357 | } 358 | 359 | func (x *GetAccountRequest) GetId() int64 { 360 | if x != nil { 361 | return x.Id 362 | } 363 | return 0 364 | } 365 | 366 | type GetAccountResponse struct { 367 | state protoimpl.MessageState 368 | sizeCache protoimpl.SizeCache 369 | unknownFields protoimpl.UnknownFields 370 | 371 | Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 372 | Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` 373 | Status AccountStatus `protobuf:"varint,3,opt,name=status,proto3,enum=me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountStatus" json:"status,omitempty"` 374 | AccessLevel AccessLevel `protobuf:"varint,4,opt,name=accessLevel,proto3,enum=me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel" json:"accessLevel,omitempty"` 375 | OpenedDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=opened_date,json=openedDate,proto3" json:"opened_date,omitempty"` 376 | ClosedDate *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=closed_date,json=closedDate,proto3" json:"closed_date,omitempty"` 377 | } 378 | 379 | func (x *GetAccountResponse) Reset() { 380 | *x = GetAccountResponse{} 381 | if protoimpl.UnsafeEnabled { 382 | mi := &file_proto_v1_account_proto_msgTypes[4] 383 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 384 | ms.StoreMessageInfo(mi) 385 | } 386 | } 387 | 388 | func (x *GetAccountResponse) String() string { 389 | return protoimpl.X.MessageStringOf(x) 390 | } 391 | 392 | func (*GetAccountResponse) ProtoMessage() {} 393 | 394 | func (x *GetAccountResponse) ProtoReflect() protoreflect.Message { 395 | mi := &file_proto_v1_account_proto_msgTypes[4] 396 | if protoimpl.UnsafeEnabled && x != nil { 397 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 398 | if ms.LoadMessageInfo() == nil { 399 | ms.StoreMessageInfo(mi) 400 | } 401 | return ms 402 | } 403 | return mi.MessageOf(x) 404 | } 405 | 406 | // Deprecated: Use GetAccountResponse.ProtoReflect.Descriptor instead. 407 | func (*GetAccountResponse) Descriptor() ([]byte, []int) { 408 | return file_proto_v1_account_proto_rawDescGZIP(), []int{4} 409 | } 410 | 411 | func (x *GetAccountResponse) GetId() int64 { 412 | if x != nil { 413 | return x.Id 414 | } 415 | return 0 416 | } 417 | 418 | func (x *GetAccountResponse) GetName() string { 419 | if x != nil { 420 | return x.Name 421 | } 422 | return "" 423 | } 424 | 425 | func (x *GetAccountResponse) GetStatus() AccountStatus { 426 | if x != nil { 427 | return x.Status 428 | } 429 | return AccountStatus_ACCOUNT_STATUS_UNKNOWN 430 | } 431 | 432 | func (x *GetAccountResponse) GetAccessLevel() AccessLevel { 433 | if x != nil { 434 | return x.AccessLevel 435 | } 436 | return AccessLevel_ACCOUNT_ACCESS_LEVEL_UNKNOWN 437 | } 438 | 439 | func (x *GetAccountResponse) GetOpenedDate() *timestamppb.Timestamp { 440 | if x != nil { 441 | return x.OpenedDate 442 | } 443 | return nil 444 | } 445 | 446 | func (x *GetAccountResponse) GetClosedDate() *timestamppb.Timestamp { 447 | if x != nil { 448 | return x.ClosedDate 449 | } 450 | return nil 451 | } 452 | 453 | var File_proto_v1_account_proto protoreflect.FileDescriptor 454 | 455 | var file_proto_v1_account_proto_rawDesc = []byte{ 456 | 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 457 | 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x45, 0x6d, 0x65, 0x2e, 0x73, 0x61, 0x64, 458 | 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x5f, 0x6d, 459 | 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 460 | 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 461 | 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x1a, 462 | 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 463 | 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 464 | 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 465 | 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 466 | 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 467 | 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 468 | 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8c, 469 | 0x03, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 470 | 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 471 | 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x6c, 472 | 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x54, 473 | 0x2e, 0x6d, 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 474 | 0x74, 0x69, 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 475 | 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 476 | 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 477 | 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x74, 478 | 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 479 | 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 480 | 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 481 | 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6f, 482 | 0x70, 0x65, 0x6e, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 483 | 0x73, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 484 | 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 485 | 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x73, 486 | 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x75, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 487 | 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x52, 0x2e, 0x6d, 488 | 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 489 | 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 490 | 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 491 | 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 492 | 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 493 | 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xa0, 0x01, 494 | 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 495 | 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 496 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x74, 0x0a, 0x0b, 0x61, 0x63, 497 | 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 498 | 0x52, 0x2e, 0x6d, 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 499 | 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 500 | 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 501 | 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 502 | 0x72, 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 503 | 0x76, 0x65, 0x6c, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 504 | 0x22, 0x27, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 505 | 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 506 | 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x23, 0x0a, 0x11, 0x47, 0x65, 0x74, 507 | 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 508 | 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x96, 509 | 0x03, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 510 | 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 511 | 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 512 | 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x6c, 0x0a, 0x06, 0x73, 0x74, 0x61, 513 | 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x54, 0x2e, 0x6d, 0x65, 0x2e, 0x73, 514 | 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 515 | 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 516 | 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 517 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x76, 518 | 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 519 | 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x74, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 520 | 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x52, 0x2e, 0x6d, 521 | 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 522 | 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 523 | 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 524 | 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 525 | 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 526 | 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x3b, 0x0a, 527 | 0x0b, 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 528 | 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 529 | 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 530 | 0x6f, 0x70, 0x65, 0x6e, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6c, 531 | 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 532 | 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 533 | 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 534 | 0x73, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x2a, 0x77, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 535 | 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x43, 0x43, 0x4f, 536 | 0x55, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 537 | 0x57, 0x4e, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 538 | 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, 0x45, 0x57, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 539 | 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 540 | 0x50, 0x45, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 541 | 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 542 | 0x2a, 0x9d, 0x01, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 543 | 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 544 | 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 545 | 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x43, 546 | 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x46, 0x55, 0x4c, 0x4c, 0x5f, 547 | 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x41, 0x43, 0x43, 0x4f, 548 | 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 549 | 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x22, 0x0a, 0x1e, 550 | 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 551 | 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x4e, 0x4f, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, 552 | 0x32, 0xd1, 0x03, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 553 | 0x69, 0x63, 0x65, 0x12, 0xdf, 0x01, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x5b, 554 | 0x2e, 0x6d, 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 555 | 0x74, 0x69, 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 556 | 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 557 | 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 558 | 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 559 | 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x5c, 0x2e, 0x6d, 0x65, 560 | 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 561 | 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 562 | 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 563 | 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 564 | 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 565 | 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 566 | 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 567 | 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xdc, 0x01, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 568 | 0x64, 0x12, 0x58, 0x2e, 0x6d, 0x65, 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 569 | 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 570 | 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 571 | 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 572 | 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 573 | 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x59, 0x2e, 0x6d, 0x65, 574 | 0x2e, 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 575 | 0x6c, 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 576 | 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 577 | 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 578 | 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 579 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 580 | 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 581 | 0x7b, 0x69, 0x64, 0x7d, 0x42, 0xfb, 0x03, 0x0a, 0x49, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x2e, 582 | 0x73, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 583 | 0x65, 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 584 | 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 585 | 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 586 | 0x76, 0x31, 0x42, 0x0c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 587 | 0x50, 0x01, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 588 | 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 589 | 0x5f, 0x6d, 0x79, 0x5f, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 590 | 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 591 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x3b, 0x63, 592 | 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x04, 0x4d, 0x53, 0x41, 0x43, 593 | 0xaa, 0x02, 0x40, 0x4d, 0x65, 0x2e, 0x53, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x2e, 594 | 0x41, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x4d, 0x79, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x41, 0x72, 595 | 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x47, 0x6f, 0x41, 0x70, 0x70, 0x6c, 596 | 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 597 | 0x2e, 0x56, 0x31, 0xca, 0x02, 0x40, 0x4d, 0x65, 0x5c, 0x53, 0x61, 0x64, 0x65, 0x6e, 0x73, 0x6d, 598 | 0x6f, 0x6c, 0x5c, 0x41, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x4d, 0x79, 0x43, 0x6c, 0x65, 0x61, 599 | 0x6e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x47, 0x6f, 0x41, 600 | 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x43, 0x6f, 0x6e, 0x74, 0x72, 601 | 0x61, 0x63, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x4c, 0x4d, 0x65, 0x5c, 0x53, 0x61, 0x64, 0x65, 602 | 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x5c, 0x41, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x4d, 0x79, 0x43, 603 | 0x6c, 0x65, 0x61, 0x6e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 604 | 0x47, 0x6f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x43, 0x6f, 605 | 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 606 | 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x44, 0x4d, 0x65, 0x3a, 0x3a, 0x53, 0x61, 0x64, 0x65, 607 | 0x6e, 0x73, 0x6d, 0x6f, 0x6c, 0x3a, 0x3a, 0x41, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x4d, 0x79, 608 | 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 609 | 0x65, 0x47, 0x6f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 610 | 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x92, 0x41, 0x23, 0x12, 611 | 0x05, 0x32, 0x03, 0x31, 0x2e, 0x30, 0x2a, 0x01, 0x01, 0x72, 0x17, 0x12, 0x15, 0x68, 0x74, 0x74, 612 | 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x38, 0x30, 613 | 0x38, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 614 | } 615 | 616 | var ( 617 | file_proto_v1_account_proto_rawDescOnce sync.Once 618 | file_proto_v1_account_proto_rawDescData = file_proto_v1_account_proto_rawDesc 619 | ) 620 | 621 | func file_proto_v1_account_proto_rawDescGZIP() []byte { 622 | file_proto_v1_account_proto_rawDescOnce.Do(func() { 623 | file_proto_v1_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_v1_account_proto_rawDescData) 624 | }) 625 | return file_proto_v1_account_proto_rawDescData 626 | } 627 | 628 | var file_proto_v1_account_proto_enumTypes = make([]protoimpl.EnumInfo, 2) 629 | var file_proto_v1_account_proto_msgTypes = make([]protoimpl.MessageInfo, 5) 630 | var file_proto_v1_account_proto_goTypes = []interface{}{ 631 | (AccountStatus)(0), // 0: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountStatus 632 | (AccessLevel)(0), // 1: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel 633 | (*Account)(nil), // 2: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.Account 634 | (*CreateAccountRequest)(nil), // 3: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.CreateAccountRequest 635 | (*CreateAccountResponse)(nil), // 4: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.CreateAccountResponse 636 | (*GetAccountRequest)(nil), // 5: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountRequest 637 | (*GetAccountResponse)(nil), // 6: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse 638 | (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp 639 | } 640 | var file_proto_v1_account_proto_depIdxs = []int32{ 641 | 0, // 0: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.Account.status:type_name -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountStatus 642 | 7, // 1: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.Account.opened_date:type_name -> google.protobuf.Timestamp 643 | 7, // 2: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.Account.closed_date:type_name -> google.protobuf.Timestamp 644 | 1, // 3: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.Account.access_level:type_name -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel 645 | 1, // 4: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.CreateAccountRequest.accessLevel:type_name -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel 646 | 0, // 5: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse.status:type_name -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountStatus 647 | 1, // 6: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse.accessLevel:type_name -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccessLevel 648 | 7, // 7: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse.opened_date:type_name -> google.protobuf.Timestamp 649 | 7, // 8: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse.closed_date:type_name -> google.protobuf.Timestamp 650 | 3, // 9: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService.Create:input_type -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.CreateAccountRequest 651 | 5, // 10: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService.GetById:input_type -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountRequest 652 | 4, // 11: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService.Create:output_type -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.CreateAccountResponse 653 | 6, // 12: me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService.GetById:output_type -> me.sadensmol.article_my_clean_architecture_go_application.contract.v1.GetAccountResponse 654 | 11, // [11:13] is the sub-list for method output_type 655 | 9, // [9:11] is the sub-list for method input_type 656 | 9, // [9:9] is the sub-list for extension type_name 657 | 9, // [9:9] is the sub-list for extension extendee 658 | 0, // [0:9] is the sub-list for field type_name 659 | } 660 | 661 | func init() { file_proto_v1_account_proto_init() } 662 | func file_proto_v1_account_proto_init() { 663 | if File_proto_v1_account_proto != nil { 664 | return 665 | } 666 | if !protoimpl.UnsafeEnabled { 667 | file_proto_v1_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 668 | switch v := v.(*Account); i { 669 | case 0: 670 | return &v.state 671 | case 1: 672 | return &v.sizeCache 673 | case 2: 674 | return &v.unknownFields 675 | default: 676 | return nil 677 | } 678 | } 679 | file_proto_v1_account_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 680 | switch v := v.(*CreateAccountRequest); i { 681 | case 0: 682 | return &v.state 683 | case 1: 684 | return &v.sizeCache 685 | case 2: 686 | return &v.unknownFields 687 | default: 688 | return nil 689 | } 690 | } 691 | file_proto_v1_account_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 692 | switch v := v.(*CreateAccountResponse); i { 693 | case 0: 694 | return &v.state 695 | case 1: 696 | return &v.sizeCache 697 | case 2: 698 | return &v.unknownFields 699 | default: 700 | return nil 701 | } 702 | } 703 | file_proto_v1_account_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 704 | switch v := v.(*GetAccountRequest); i { 705 | case 0: 706 | return &v.state 707 | case 1: 708 | return &v.sizeCache 709 | case 2: 710 | return &v.unknownFields 711 | default: 712 | return nil 713 | } 714 | } 715 | file_proto_v1_account_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 716 | switch v := v.(*GetAccountResponse); i { 717 | case 0: 718 | return &v.state 719 | case 1: 720 | return &v.sizeCache 721 | case 2: 722 | return &v.unknownFields 723 | default: 724 | return nil 725 | } 726 | } 727 | } 728 | type x struct{} 729 | out := protoimpl.TypeBuilder{ 730 | File: protoimpl.DescBuilder{ 731 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 732 | RawDescriptor: file_proto_v1_account_proto_rawDesc, 733 | NumEnums: 2, 734 | NumMessages: 5, 735 | NumExtensions: 0, 736 | NumServices: 1, 737 | }, 738 | GoTypes: file_proto_v1_account_proto_goTypes, 739 | DependencyIndexes: file_proto_v1_account_proto_depIdxs, 740 | EnumInfos: file_proto_v1_account_proto_enumTypes, 741 | MessageInfos: file_proto_v1_account_proto_msgTypes, 742 | }.Build() 743 | File_proto_v1_account_proto = out.File 744 | file_proto_v1_account_proto_rawDesc = nil 745 | file_proto_v1_account_proto_goTypes = nil 746 | file_proto_v1_account_proto_depIdxs = nil 747 | } 748 | -------------------------------------------------------------------------------- /api/proto/v1/account.pb.gw.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. 2 | // source: proto/v1/account.proto 3 | 4 | /* 5 | Package contractv1 is a reverse proxy. 6 | 7 | It translates gRPC into RESTful JSON APIs. 8 | */ 9 | package contractv1 10 | 11 | import ( 12 | "context" 13 | "io" 14 | "net/http" 15 | 16 | "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 17 | "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" 18 | "google.golang.org/grpc" 19 | "google.golang.org/grpc/codes" 20 | "google.golang.org/grpc/grpclog" 21 | "google.golang.org/grpc/metadata" 22 | "google.golang.org/grpc/status" 23 | "google.golang.org/protobuf/proto" 24 | ) 25 | 26 | // Suppress "imported and not used" errors 27 | var _ codes.Code 28 | var _ io.Reader 29 | var _ status.Status 30 | var _ = runtime.String 31 | var _ = utilities.NewDoubleArray 32 | var _ = metadata.Join 33 | 34 | func request_AccountService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 35 | var protoReq CreateAccountRequest 36 | var metadata runtime.ServerMetadata 37 | 38 | newReader, berr := utilities.IOReaderFactory(req.Body) 39 | if berr != nil { 40 | return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) 41 | } 42 | if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { 43 | return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) 44 | } 45 | 46 | msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) 47 | return msg, metadata, err 48 | 49 | } 50 | 51 | func local_request_AccountService_Create_0(ctx context.Context, marshaler runtime.Marshaler, server AccountServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 52 | var protoReq CreateAccountRequest 53 | var metadata runtime.ServerMetadata 54 | 55 | newReader, berr := utilities.IOReaderFactory(req.Body) 56 | if berr != nil { 57 | return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) 58 | } 59 | if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { 60 | return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) 61 | } 62 | 63 | msg, err := server.Create(ctx, &protoReq) 64 | return msg, metadata, err 65 | 66 | } 67 | 68 | func request_AccountService_GetById_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 69 | var protoReq GetAccountRequest 70 | var metadata runtime.ServerMetadata 71 | 72 | var ( 73 | val string 74 | ok bool 75 | err error 76 | _ = err 77 | ) 78 | 79 | val, ok = pathParams["id"] 80 | if !ok { 81 | return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") 82 | } 83 | 84 | protoReq.Id, err = runtime.Int64(val) 85 | if err != nil { 86 | return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) 87 | } 88 | 89 | msg, err := client.GetById(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) 90 | return msg, metadata, err 91 | 92 | } 93 | 94 | func local_request_AccountService_GetById_0(ctx context.Context, marshaler runtime.Marshaler, server AccountServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 95 | var protoReq GetAccountRequest 96 | var metadata runtime.ServerMetadata 97 | 98 | var ( 99 | val string 100 | ok bool 101 | err error 102 | _ = err 103 | ) 104 | 105 | val, ok = pathParams["id"] 106 | if !ok { 107 | return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") 108 | } 109 | 110 | protoReq.Id, err = runtime.Int64(val) 111 | if err != nil { 112 | return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) 113 | } 114 | 115 | msg, err := server.GetById(ctx, &protoReq) 116 | return msg, metadata, err 117 | 118 | } 119 | 120 | // RegisterAccountServiceHandlerServer registers the http handlers for service AccountService to "mux". 121 | // UnaryRPC :call AccountServiceServer directly. 122 | // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. 123 | // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterAccountServiceHandlerFromEndpoint instead. 124 | func RegisterAccountServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AccountServiceServer) error { 125 | 126 | mux.Handle("POST", pattern_AccountService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 127 | ctx, cancel := context.WithCancel(req.Context()) 128 | defer cancel() 129 | var stream runtime.ServerTransportStream 130 | ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) 131 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 132 | rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/Create", runtime.WithHTTPPathPattern("/api/v1/account")) 133 | if err != nil { 134 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 135 | return 136 | } 137 | resp, md, err := local_request_AccountService_Create_0(rctx, inboundMarshaler, server, req, pathParams) 138 | md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) 139 | ctx = runtime.NewServerMetadataContext(ctx, md) 140 | if err != nil { 141 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 142 | return 143 | } 144 | 145 | forward_AccountService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 146 | 147 | }) 148 | 149 | mux.Handle("GET", pattern_AccountService_GetById_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 150 | ctx, cancel := context.WithCancel(req.Context()) 151 | defer cancel() 152 | var stream runtime.ServerTransportStream 153 | ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) 154 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 155 | rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/GetById", runtime.WithHTTPPathPattern("/api/v1/account/{id}")) 156 | if err != nil { 157 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 158 | return 159 | } 160 | resp, md, err := local_request_AccountService_GetById_0(rctx, inboundMarshaler, server, req, pathParams) 161 | md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) 162 | ctx = runtime.NewServerMetadataContext(ctx, md) 163 | if err != nil { 164 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 165 | return 166 | } 167 | 168 | forward_AccountService_GetById_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 169 | 170 | }) 171 | 172 | return nil 173 | } 174 | 175 | // RegisterAccountServiceHandlerFromEndpoint is same as RegisterAccountServiceHandler but 176 | // automatically dials to "endpoint" and closes the connection when "ctx" gets done. 177 | func RegisterAccountServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { 178 | conn, err := grpc.Dial(endpoint, opts...) 179 | if err != nil { 180 | return err 181 | } 182 | defer func() { 183 | if err != nil { 184 | if cerr := conn.Close(); cerr != nil { 185 | grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) 186 | } 187 | return 188 | } 189 | go func() { 190 | <-ctx.Done() 191 | if cerr := conn.Close(); cerr != nil { 192 | grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) 193 | } 194 | }() 195 | }() 196 | 197 | return RegisterAccountServiceHandler(ctx, mux, conn) 198 | } 199 | 200 | // RegisterAccountServiceHandler registers the http handlers for service AccountService to "mux". 201 | // The handlers forward requests to the grpc endpoint over "conn". 202 | func RegisterAccountServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { 203 | return RegisterAccountServiceHandlerClient(ctx, mux, NewAccountServiceClient(conn)) 204 | } 205 | 206 | // RegisterAccountServiceHandlerClient registers the http handlers for service AccountService 207 | // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AccountServiceClient". 208 | // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AccountServiceClient" 209 | // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in 210 | // "AccountServiceClient" to call the correct interceptors. 211 | func RegisterAccountServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AccountServiceClient) error { 212 | 213 | mux.Handle("POST", pattern_AccountService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 214 | ctx, cancel := context.WithCancel(req.Context()) 215 | defer cancel() 216 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 217 | rctx, err := runtime.AnnotateContext(ctx, mux, req, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/Create", runtime.WithHTTPPathPattern("/api/v1/account")) 218 | if err != nil { 219 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 220 | return 221 | } 222 | resp, md, err := request_AccountService_Create_0(rctx, inboundMarshaler, client, req, pathParams) 223 | ctx = runtime.NewServerMetadataContext(ctx, md) 224 | if err != nil { 225 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 226 | return 227 | } 228 | 229 | forward_AccountService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 230 | 231 | }) 232 | 233 | mux.Handle("GET", pattern_AccountService_GetById_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 234 | ctx, cancel := context.WithCancel(req.Context()) 235 | defer cancel() 236 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 237 | rctx, err := runtime.AnnotateContext(ctx, mux, req, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/GetById", runtime.WithHTTPPathPattern("/api/v1/account/{id}")) 238 | if err != nil { 239 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 240 | return 241 | } 242 | resp, md, err := request_AccountService_GetById_0(rctx, inboundMarshaler, client, req, pathParams) 243 | ctx = runtime.NewServerMetadataContext(ctx, md) 244 | if err != nil { 245 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 246 | return 247 | } 248 | 249 | forward_AccountService_GetById_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 250 | 251 | }) 252 | 253 | return nil 254 | } 255 | 256 | var ( 257 | pattern_AccountService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "account"}, "")) 258 | 259 | pattern_AccountService_GetById_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "account", "id"}, "")) 260 | ) 261 | 262 | var ( 263 | forward_AccountService_Create_0 = runtime.ForwardResponseMessage 264 | 265 | forward_AccountService_GetById_0 = runtime.ForwardResponseMessage 266 | ) 267 | -------------------------------------------------------------------------------- /api/proto/v1/account.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package me.sadensmol.article_my_clean_architecture_go_application.contract.v1; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | import "google/api/annotations.proto"; 7 | import "protoc-gen-openapiv2/options/annotations.proto"; 8 | 9 | option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { 10 | info: {version: "1.0"}; 11 | external_docs: { 12 | url: "http://localhost:8081"; 13 | } 14 | schemes: HTTP; 15 | }; 16 | 17 | message Account { 18 | int64 id = 1; 19 | string name = 2; 20 | AccountStatus status = 3; 21 | google.protobuf.Timestamp opened_date = 4; 22 | google.protobuf.Timestamp closed_date = 5; 23 | AccessLevel access_level = 6; 24 | } 25 | 26 | enum AccountStatus { 27 | ACCOUNT_STATUS_UNKNOWN = 0; 28 | ACCOUNT_STATUS_NEW = 1; 29 | ACCOUNT_STATUS_OPEN = 2; 30 | ACCOUNT_STATUS_CLOSED = 3; 31 | } 32 | 33 | enum AccessLevel { 34 | ACCOUNT_ACCESS_LEVEL_UNKNOWN = 0; 35 | ACCOUNT_ACCESS_LEVEL_FULL_ACCESS = 1; 36 | ACCOUNT_ACCESS_LEVEL_READ_ONLY = 2; 37 | ACCOUNT_ACCESS_LEVEL_NO_ACCESS = 3; 38 | } 39 | 40 | 41 | message CreateAccountRequest { 42 | string name =1; 43 | AccessLevel accessLevel =2; 44 | } 45 | 46 | message CreateAccountResponse { 47 | int64 id = 1; 48 | } 49 | 50 | message GetAccountRequest { 51 | int64 id =1; 52 | } 53 | 54 | message GetAccountResponse { 55 | int64 id =1; 56 | string name = 2; 57 | AccountStatus status = 3; 58 | AccessLevel accessLevel =4; 59 | google.protobuf.Timestamp opened_date = 5; 60 | google.protobuf.Timestamp closed_date = 6; 61 | } 62 | 63 | service AccountService { 64 | rpc Create(CreateAccountRequest) returns (CreateAccountResponse) { 65 | option (google.api.http) = { 66 | post: "/api/v1/account" 67 | body: "*" 68 | }; 69 | } 70 | 71 | rpc GetById(GetAccountRequest) returns (GetAccountResponse) { 72 | option (google.api.http) = { 73 | get: "/api/v1/account/{id}" 74 | }; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /api/proto/v1/account.swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "proto/v1/account.proto", 5 | "version": "1.0" 6 | }, 7 | "tags": [ 8 | { 9 | "name": "AccountService" 10 | } 11 | ], 12 | "schemes": [ 13 | "http" 14 | ], 15 | "consumes": [ 16 | "application/json" 17 | ], 18 | "produces": [ 19 | "application/json" 20 | ], 21 | "paths": { 22 | "/api/v1/account": { 23 | "post": { 24 | "operationId": "AccountService_Create", 25 | "responses": { 26 | "200": { 27 | "description": "A successful response.", 28 | "schema": { 29 | "$ref": "#/definitions/v1CreateAccountResponse" 30 | } 31 | }, 32 | "default": { 33 | "description": "An unexpected error response.", 34 | "schema": { 35 | "$ref": "#/definitions/rpcStatus" 36 | } 37 | } 38 | }, 39 | "parameters": [ 40 | { 41 | "name": "body", 42 | "in": "body", 43 | "required": true, 44 | "schema": { 45 | "$ref": "#/definitions/v1CreateAccountRequest" 46 | } 47 | } 48 | ], 49 | "tags": [ 50 | "AccountService" 51 | ] 52 | } 53 | }, 54 | "/api/v1/account/{id}": { 55 | "get": { 56 | "operationId": "AccountService_GetById", 57 | "responses": { 58 | "200": { 59 | "description": "A successful response.", 60 | "schema": { 61 | "$ref": "#/definitions/v1GetAccountResponse" 62 | } 63 | }, 64 | "default": { 65 | "description": "An unexpected error response.", 66 | "schema": { 67 | "$ref": "#/definitions/rpcStatus" 68 | } 69 | } 70 | }, 71 | "parameters": [ 72 | { 73 | "name": "id", 74 | "in": "path", 75 | "required": true, 76 | "type": "string", 77 | "format": "int64" 78 | } 79 | ], 80 | "tags": [ 81 | "AccountService" 82 | ] 83 | } 84 | } 85 | }, 86 | "definitions": { 87 | "protobufAny": { 88 | "type": "object", 89 | "properties": { 90 | "@type": { 91 | "type": "string" 92 | } 93 | }, 94 | "additionalProperties": {} 95 | }, 96 | "rpcStatus": { 97 | "type": "object", 98 | "properties": { 99 | "code": { 100 | "type": "integer", 101 | "format": "int32" 102 | }, 103 | "message": { 104 | "type": "string" 105 | }, 106 | "details": { 107 | "type": "array", 108 | "items": { 109 | "$ref": "#/definitions/protobufAny" 110 | } 111 | } 112 | } 113 | }, 114 | "v1AccessLevel": { 115 | "type": "string", 116 | "enum": [ 117 | "ACCOUNT_ACCESS_LEVEL_UNKNOWN", 118 | "ACCOUNT_ACCESS_LEVEL_FULL_ACCESS", 119 | "ACCOUNT_ACCESS_LEVEL_READ_ONLY", 120 | "ACCOUNT_ACCESS_LEVEL_NO_ACCESS" 121 | ], 122 | "default": "ACCOUNT_ACCESS_LEVEL_UNKNOWN" 123 | }, 124 | "v1AccountStatus": { 125 | "type": "string", 126 | "enum": [ 127 | "ACCOUNT_STATUS_UNKNOWN", 128 | "ACCOUNT_STATUS_NEW", 129 | "ACCOUNT_STATUS_OPEN", 130 | "ACCOUNT_STATUS_CLOSED" 131 | ], 132 | "default": "ACCOUNT_STATUS_UNKNOWN" 133 | }, 134 | "v1CreateAccountRequest": { 135 | "type": "object", 136 | "properties": { 137 | "name": { 138 | "type": "string" 139 | }, 140 | "accessLevel": { 141 | "$ref": "#/definitions/v1AccessLevel" 142 | } 143 | } 144 | }, 145 | "v1CreateAccountResponse": { 146 | "type": "object", 147 | "properties": { 148 | "id": { 149 | "type": "string", 150 | "format": "int64" 151 | } 152 | } 153 | }, 154 | "v1GetAccountResponse": { 155 | "type": "object", 156 | "properties": { 157 | "id": { 158 | "type": "string", 159 | "format": "int64" 160 | }, 161 | "name": { 162 | "type": "string" 163 | }, 164 | "status": { 165 | "$ref": "#/definitions/v1AccountStatus" 166 | }, 167 | "accessLevel": { 168 | "$ref": "#/definitions/v1AccessLevel" 169 | }, 170 | "openedDate": { 171 | "type": "string", 172 | "format": "date-time" 173 | }, 174 | "closedDate": { 175 | "type": "string", 176 | "format": "date-time" 177 | } 178 | } 179 | } 180 | }, 181 | "externalDocs": { 182 | "url": "http://localhost:8081" 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /api/proto/v1/account_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc (unknown) 5 | // source: proto/v1/account.proto 6 | 7 | package contractv1 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // AccountServiceClient is the client API for AccountService service. 22 | // 23 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 24 | type AccountServiceClient interface { 25 | Create(ctx context.Context, in *CreateAccountRequest, opts ...grpc.CallOption) (*CreateAccountResponse, error) 26 | GetById(ctx context.Context, in *GetAccountRequest, opts ...grpc.CallOption) (*GetAccountResponse, error) 27 | } 28 | 29 | type accountServiceClient struct { 30 | cc grpc.ClientConnInterface 31 | } 32 | 33 | func NewAccountServiceClient(cc grpc.ClientConnInterface) AccountServiceClient { 34 | return &accountServiceClient{cc} 35 | } 36 | 37 | func (c *accountServiceClient) Create(ctx context.Context, in *CreateAccountRequest, opts ...grpc.CallOption) (*CreateAccountResponse, error) { 38 | out := new(CreateAccountResponse) 39 | err := c.cc.Invoke(ctx, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/Create", in, out, opts...) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return out, nil 44 | } 45 | 46 | func (c *accountServiceClient) GetById(ctx context.Context, in *GetAccountRequest, opts ...grpc.CallOption) (*GetAccountResponse, error) { 47 | out := new(GetAccountResponse) 48 | err := c.cc.Invoke(ctx, "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/GetById", in, out, opts...) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return out, nil 53 | } 54 | 55 | // AccountServiceServer is the server API for AccountService service. 56 | // All implementations should embed UnimplementedAccountServiceServer 57 | // for forward compatibility 58 | type AccountServiceServer interface { 59 | Create(context.Context, *CreateAccountRequest) (*CreateAccountResponse, error) 60 | GetById(context.Context, *GetAccountRequest) (*GetAccountResponse, error) 61 | } 62 | 63 | // UnimplementedAccountServiceServer should be embedded to have forward compatible implementations. 64 | type UnimplementedAccountServiceServer struct { 65 | } 66 | 67 | func (UnimplementedAccountServiceServer) Create(context.Context, *CreateAccountRequest) (*CreateAccountResponse, error) { 68 | return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") 69 | } 70 | func (UnimplementedAccountServiceServer) GetById(context.Context, *GetAccountRequest) (*GetAccountResponse, error) { 71 | return nil, status.Errorf(codes.Unimplemented, "method GetById not implemented") 72 | } 73 | 74 | // UnsafeAccountServiceServer may be embedded to opt out of forward compatibility for this service. 75 | // Use of this interface is not recommended, as added methods to AccountServiceServer will 76 | // result in compilation errors. 77 | type UnsafeAccountServiceServer interface { 78 | mustEmbedUnimplementedAccountServiceServer() 79 | } 80 | 81 | func RegisterAccountServiceServer(s grpc.ServiceRegistrar, srv AccountServiceServer) { 82 | s.RegisterService(&AccountService_ServiceDesc, srv) 83 | } 84 | 85 | func _AccountService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 86 | in := new(CreateAccountRequest) 87 | if err := dec(in); err != nil { 88 | return nil, err 89 | } 90 | if interceptor == nil { 91 | return srv.(AccountServiceServer).Create(ctx, in) 92 | } 93 | info := &grpc.UnaryServerInfo{ 94 | Server: srv, 95 | FullMethod: "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/Create", 96 | } 97 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 98 | return srv.(AccountServiceServer).Create(ctx, req.(*CreateAccountRequest)) 99 | } 100 | return interceptor(ctx, in, info, handler) 101 | } 102 | 103 | func _AccountService_GetById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 104 | in := new(GetAccountRequest) 105 | if err := dec(in); err != nil { 106 | return nil, err 107 | } 108 | if interceptor == nil { 109 | return srv.(AccountServiceServer).GetById(ctx, in) 110 | } 111 | info := &grpc.UnaryServerInfo{ 112 | Server: srv, 113 | FullMethod: "/me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService/GetById", 114 | } 115 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 116 | return srv.(AccountServiceServer).GetById(ctx, req.(*GetAccountRequest)) 117 | } 118 | return interceptor(ctx, in, info, handler) 119 | } 120 | 121 | // AccountService_ServiceDesc is the grpc.ServiceDesc for AccountService service. 122 | // It's only intended for direct use with grpc.RegisterService, 123 | // and not to be introspected or modified (even as a copy) 124 | var AccountService_ServiceDesc = grpc.ServiceDesc{ 125 | ServiceName: "me.sadensmol.article_my_clean_architecture_go_application.contract.v1.AccountService", 126 | HandlerType: (*AccountServiceServer)(nil), 127 | Methods: []grpc.MethodDesc{ 128 | { 129 | MethodName: "Create", 130 | Handler: _AccountService_Create_Handler, 131 | }, 132 | { 133 | MethodName: "GetById", 134 | Handler: _AccountService_GetById_Handler, 135 | }, 136 | }, 137 | Streams: []grpc.StreamDesc{}, 138 | Metadata: "proto/v1/account.proto", 139 | } 140 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "flag" 7 | "fmt" 8 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/adapters/controllers" 9 | handler "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/adapters/repositories" 10 | "log" 11 | "net" 12 | "net/http" 13 | "os" 14 | 15 | "github.com/golang/glog" 16 | "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 17 | "github.com/joho/godotenv" 18 | _ "github.com/lib/pq" 19 | gw "github.com/sadensmol/article_my_clean_architecture_go_application/api/proto/v1" 20 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/services" 21 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/usecases" 22 | "google.golang.org/grpc" 23 | "google.golang.org/grpc/credentials/insecure" 24 | ) 25 | 26 | var ( 27 | grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:9090", "gRPC server endpoint") 28 | ) 29 | 30 | func main() { 31 | flag.Parse() 32 | defer glog.Flush() 33 | 34 | err := godotenv.Load("infrastructure/local/.env") 35 | if err != nil { 36 | log.Fatal("Error loading .env file") 37 | } 38 | var connectString = fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", os.Getenv("DB_HOST"), 39 | os.Getenv("DB_PORT"), os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME")) 40 | db, err := sql.Open("postgres", connectString) 41 | if err != nil { 42 | log.Fatalf("Failed to connect to database %v", err) 43 | } 44 | defer db.Close() 45 | 46 | ctx := context.Background() 47 | ctx, cancel := context.WithCancel(ctx) 48 | defer cancel() 49 | 50 | lis, err := net.Listen("tcp", ":9090") 51 | if err != nil { 52 | log.Fatalln("Failed to listen:", err) 53 | } 54 | 55 | s := grpc.NewServer() 56 | 57 | accountRepository := handler.NewAccountRepository(db) 58 | accountService := services.NewAccountService(accountRepository) 59 | accountUsecases := usecases.NewAccountUsecases(accountService) 60 | accountHandler := controllers.NewAccountHandler(accountUsecases) 61 | 62 | gw.RegisterAccountServiceServer(s, accountHandler) 63 | 64 | // Serve gRPC server 65 | log.Println("Serving gRPC on 0.0.0.0:9090") 66 | go func() { 67 | log.Fatalln(s.Serve(lis)) 68 | }() 69 | 70 | // Register gRPC server endpoint 71 | // Note: Make sure the gRPC server is running properly and accessible 72 | mux := runtime.NewServeMux() 73 | opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} 74 | err = gw.RegisterAccountServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts) 75 | if err != nil { 76 | log.Fatalln("Failed to listen:", err) 77 | } 78 | 79 | gwServer := &http.Server{ 80 | Addr: ":8090", 81 | Handler: mux, 82 | } 83 | 84 | log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090") 85 | log.Fatalln(gwServer.ListenAndServe()) 86 | } 87 | -------------------------------------------------------------------------------- /db/fixtures/20230309130154_create_test_account.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | insert into account(id, name, status, access_level, opened_at) 4 | values (1, 'test_account','open','full',now()); 5 | ALTER SEQUENCE account_id_seq RESTART WITH 10; 6 | 7 | -- +goose StatementEnd 8 | 9 | -- +goose Down 10 | -- +goose StatementBegin 11 | 12 | -- +goose StatementEnd 13 | -------------------------------------------------------------------------------- /db/gen/account/public/model/account.go: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by go-jet DO NOT EDIT. 3 | // 4 | // WARNING: Changes to this file may cause incorrect behavior 5 | // and will be lost if the code is regenerated 6 | // 7 | 8 | package model 9 | 10 | import ( 11 | "time" 12 | ) 13 | 14 | type Account struct { 15 | ID int64 `sql:"primary_key"` 16 | Name string 17 | Status string 18 | AccessLevel string 19 | OpenedAt time.Time 20 | ClosedAt *time.Time 21 | } 22 | -------------------------------------------------------------------------------- /db/gen/account/public/table/account.go: -------------------------------------------------------------------------------- 1 | // 2 | // Code generated by go-jet DO NOT EDIT. 3 | // 4 | // WARNING: Changes to this file may cause incorrect behavior 5 | // and will be lost if the code is regenerated 6 | // 7 | 8 | package table 9 | 10 | import ( 11 | "github.com/go-jet/jet/v2/postgres" 12 | ) 13 | 14 | var Account = newAccountTable("public", "account", "") 15 | 16 | type accountTable struct { 17 | postgres.Table 18 | 19 | //Columns 20 | ID postgres.ColumnInteger 21 | Name postgres.ColumnString 22 | Status postgres.ColumnString 23 | AccessLevel postgres.ColumnString 24 | OpenedAt postgres.ColumnTimestampz 25 | ClosedAt postgres.ColumnTimestampz 26 | 27 | AllColumns postgres.ColumnList 28 | MutableColumns postgres.ColumnList 29 | } 30 | 31 | type AccountTable struct { 32 | accountTable 33 | 34 | EXCLUDED accountTable 35 | } 36 | 37 | // AS creates new AccountTable with assigned alias 38 | func (a AccountTable) AS(alias string) *AccountTable { 39 | return newAccountTable(a.SchemaName(), a.TableName(), alias) 40 | } 41 | 42 | // Schema creates new AccountTable with assigned schema name 43 | func (a AccountTable) FromSchema(schemaName string) *AccountTable { 44 | return newAccountTable(schemaName, a.TableName(), a.Alias()) 45 | } 46 | 47 | // WithPrefix creates new AccountTable with assigned table prefix 48 | func (a AccountTable) WithPrefix(prefix string) *AccountTable { 49 | return newAccountTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) 50 | } 51 | 52 | // WithSuffix creates new AccountTable with assigned table suffix 53 | func (a AccountTable) WithSuffix(suffix string) *AccountTable { 54 | return newAccountTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) 55 | } 56 | 57 | func newAccountTable(schemaName, tableName, alias string) *AccountTable { 58 | return &AccountTable{ 59 | accountTable: newAccountTableImpl(schemaName, tableName, alias), 60 | EXCLUDED: newAccountTableImpl("", "excluded", ""), 61 | } 62 | } 63 | 64 | func newAccountTableImpl(schemaName, tableName, alias string) accountTable { 65 | var ( 66 | IDColumn = postgres.IntegerColumn("id") 67 | NameColumn = postgres.StringColumn("name") 68 | StatusColumn = postgres.StringColumn("status") 69 | AccessLevelColumn = postgres.StringColumn("access_level") 70 | OpenedAtColumn = postgres.TimestampzColumn("opened_at") 71 | ClosedAtColumn = postgres.TimestampzColumn("closed_at") 72 | allColumns = postgres.ColumnList{IDColumn, NameColumn, StatusColumn, AccessLevelColumn, OpenedAtColumn, ClosedAtColumn} 73 | mutableColumns = postgres.ColumnList{NameColumn, StatusColumn, AccessLevelColumn, OpenedAtColumn, ClosedAtColumn} 74 | ) 75 | 76 | return accountTable{ 77 | Table: postgres.NewTable(schemaName, tableName, alias, allColumns...), 78 | 79 | //Columns 80 | ID: IDColumn, 81 | Name: NameColumn, 82 | Status: StatusColumn, 83 | AccessLevel: AccessLevelColumn, 84 | OpenedAt: OpenedAtColumn, 85 | ClosedAt: ClosedAtColumn, 86 | 87 | AllColumns: allColumns, 88 | MutableColumns: mutableColumns, 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /db/migrations/20230225133922_create_account_table.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | -- +goose StatementBegin 3 | create table account ( 4 | id bigserial primary key , 5 | name text not null, 6 | status text not null default 'new', 7 | access_level text not null default 'none', 8 | opened_at timestamptz not null default now(), 9 | closed_at timestamptz 10 | ); 11 | -- +goose StatementEnd 12 | 13 | -- +goose Down 14 | -- +goose StatementBegin 15 | -- +goose StatementEnd 16 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sadensmol/article_my_clean_architecture_go_application 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/go-jet/jet/v2 v2.9.0 7 | github.com/golang/glog v1.0.0 8 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 9 | github.com/joho/godotenv v1.5.1 10 | github.com/lib/pq v1.10.5 11 | github.com/steinfletcher/apitest v1.5.14 12 | github.com/steinfletcher/apitest-jsonpath v1.7.1 13 | github.com/stretchr/testify v1.7.0 14 | google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 15 | google.golang.org/grpc v1.51.0 16 | google.golang.org/protobuf v1.28.1 17 | ) 18 | 19 | require ( 20 | github.com/PaesslerAG/gval v1.0.0 // indirect 21 | github.com/PaesslerAG/jsonpath v0.1.1 // indirect 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/golang/protobuf v1.5.2 // indirect 24 | github.com/google/uuid v1.1.2 // indirect 25 | github.com/kr/text v0.2.0 // indirect 26 | github.com/pmezard/go-difflib v1.0.0 // indirect 27 | golang.org/x/net v0.3.0 // indirect 28 | golang.org/x/sys v0.3.0 // indirect 29 | golang.org/x/text v0.5.0 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 3 | github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8= 4 | github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= 5 | github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= 6 | github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk= 7 | github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= 8 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 9 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 10 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 11 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 12 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 15 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= 17 | github.com/go-jet/jet/v2 v2.9.0 h1:WhZc3kBWrH/2jk9a3ZYhr9zWeD2cbOwXRCfKCao3hhI= 18 | github.com/go-jet/jet/v2 v2.9.0/go.mod h1:VBDVqwkUOj2mSXe9s2dM6TJAcJ1rgopiiWz9ITLn4PM= 19 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 20 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 21 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 22 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 23 | github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 24 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 25 | github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= 26 | github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 27 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 28 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 29 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 30 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 31 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 32 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 33 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 34 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 35 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 36 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 37 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A= 38 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0= 39 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 40 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 41 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 42 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 43 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 44 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 45 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 46 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 47 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 48 | github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= 49 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 50 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 51 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 52 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 53 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 54 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 55 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 56 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 57 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 58 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 59 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 60 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 61 | github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 62 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 63 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 64 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 65 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 66 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 67 | github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 68 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 69 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 70 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 71 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 72 | github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= 73 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 74 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 75 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 76 | github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 77 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 78 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 79 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 80 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 81 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 82 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 83 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 84 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 85 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 86 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 87 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 88 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 89 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 90 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 91 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 92 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 93 | github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= 94 | github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 95 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 96 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 97 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 98 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 99 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 100 | github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 101 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 102 | github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= 103 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 104 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 105 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 106 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 107 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 108 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 109 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 110 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 111 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 112 | github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 113 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 114 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 115 | github.com/steinfletcher/apitest v1.5.10/go.mod h1:cf7Bneo52IIAgpqhP8xaLlzWgAiQ9fHtsDMjeDnZ3so= 116 | github.com/steinfletcher/apitest v1.5.14 h1:18t0UtxdKf0OPfeP5omB85m23l1E3/tN3i93Rtw9Kp4= 117 | github.com/steinfletcher/apitest v1.5.14/go.mod h1:mF+KnYaIkuHM0C4JgGzkIIOJAEjo+EA5tTjJ+bHXnQc= 118 | github.com/steinfletcher/apitest-jsonpath v1.7.1 h1:dj0Z/7DJt2Ts/R52OeVbnMp+gegcf2X7F+/l75HBfsY= 119 | github.com/steinfletcher/apitest-jsonpath v1.7.1/go.mod h1:FzU2i3ZIyIdF6yBI8a0DZ10gCC6jhiD1yAdU0nCz5Do= 120 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 121 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 122 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 123 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 124 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 125 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 126 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 127 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 128 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 129 | github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= 130 | github.com/volatiletech/null/v8 v8.1.2/go.mod h1:98DbwNoKEpRrYtGjWFctievIfm4n4MxG0A6EBUcoS5g= 131 | github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= 132 | github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= 133 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 134 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 135 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 136 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 137 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 138 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 139 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 140 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 141 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 142 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 143 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 144 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 145 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 146 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 147 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 148 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 149 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 150 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 151 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 152 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 153 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 154 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 155 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 156 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 157 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 158 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 159 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 160 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 161 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 162 | golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= 163 | golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= 164 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 165 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 166 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 167 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 168 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 169 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 170 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 171 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 172 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 173 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 174 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 175 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 176 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 177 | golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= 178 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 179 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 180 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 181 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 182 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 183 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 184 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 185 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 186 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 187 | golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= 188 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 189 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 190 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 191 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 192 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 193 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 194 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 195 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 196 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 197 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 198 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 199 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 200 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 201 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 202 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 203 | google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 h1:jmIfw8+gSvXcZSgaFAGyInDXeWzUhvYH57G/5GKMn70= 204 | google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= 205 | google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= 206 | google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= 207 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 208 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 209 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 210 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 211 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 212 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 213 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 214 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 215 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 216 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 217 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 218 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 219 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 220 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 221 | -------------------------------------------------------------------------------- /infrastructure/local/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=postgres 2 | DB_PORT=5432 3 | DB_USER=postgres 4 | DB_PASSWORD=postgres 5 | DB_NAME=account 6 | DB_SSL_MODE=disable 7 | -------------------------------------------------------------------------------- /infrastructure/local/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.20-alpine 2 | WORKDIR /app 3 | 4 | COPY go.mod go.sum ./ 5 | RUN go mod download 6 | COPY infrastructure/local/.env . 7 | 8 | RUN apk add --no-cache gcc musl-dev make 9 | RUN go install github.com/cosmtrek/air@latest 10 | -------------------------------------------------------------------------------- /infrastructure/local/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | postgres: 4 | image: bitnami/postgresql:latest 5 | ports: 6 | - 5432:5432 7 | restart: always 8 | env_file: 9 | - .env 10 | environment: 11 | POSTGRESQL_USERNAME: ${DB_USER} 12 | POSTGRESQL_PASSWORD: ${DB_PASSWORD} 13 | POSTGRESQL_DATABASE: ${DB_NAME} 14 | healthcheck: 15 | test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"] 16 | interval: 1s 17 | timeout: 5s 18 | retries: 5 19 | 20 | account: 21 | build: 22 | context: ../../. 23 | dockerfile: infrastructure/local/Dockerfile 24 | volumes: 25 | - ../..:$PWD 26 | working_dir: $PWD 27 | ports: 28 | - 8090:8090 29 | - 9090:9090 30 | restart: on-failure 31 | depends_on: 32 | postgres: 33 | condition: service_healthy 34 | env_file: 35 | - .env 36 | command: ["sh","-c","go mod download && make migrate-up && make fixtures-up && air"] 37 | 38 | -------------------------------------------------------------------------------- /internal/account/adapters/controllers/account-handler.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "context" 5 | "google.golang.org/protobuf/reflect/protoregistry" 6 | "google.golang.org/protobuf/types/known/timestamppb" 7 | "log" 8 | 9 | contractv1 "github.com/sadensmol/article_my_clean_architecture_go_application/api/proto/v1" 10 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 11 | ) 12 | 13 | type AccountHandler struct { 14 | accountUsecases AccountUsecases 15 | } 16 | 17 | type AccountUsecases interface { 18 | Create(account domain.Account) (*domain.Account, error) 19 | GetByID(ID int64) (*domain.Account, error) 20 | } 21 | 22 | func NewAccountHandler(accountUsecases AccountUsecases) *AccountHandler { 23 | return &AccountHandler{accountUsecases: accountUsecases} 24 | } 25 | 26 | func (h *AccountHandler) Create(ctx context.Context, request *contractv1.CreateAccountRequest) (*contractv1.CreateAccountResponse, error) { 27 | log.Println("create was called!!!") 28 | account, err := h.accountUsecases.Create(domain.Account{ 29 | Name: request.Name, 30 | Status: domain.AccountStatusNew, 31 | AccessLevel: AccountHandlerAccessLevel(request.AccessLevel).ToDomain(), 32 | }) 33 | 34 | if err != nil { 35 | log.Fatalf("Error occurred %v", err) 36 | } 37 | 38 | return &contractv1.CreateAccountResponse{Id: account.ID}, nil 39 | } 40 | func (h *AccountHandler) GetById(ctx context.Context, request *contractv1.GetAccountRequest) (*contractv1.GetAccountResponse, error) { 41 | account, err := h.accountUsecases.GetByID(request.GetId()) 42 | if err != nil { 43 | log.Fatalf("Error occurred %v", err) 44 | } 45 | 46 | if account == nil { 47 | return nil, protoregistry.NotFound 48 | } 49 | 50 | return &contractv1.GetAccountResponse{ 51 | Id: account.ID, 52 | Name: account.Name, 53 | Status: AccountStatusFromDomain(account.Status), 54 | AccessLevel: AccountAccessLevelFromDomain(account.AccessLevel), 55 | OpenedDate: timestamppb.New(account.OpenedAt), 56 | ClosedDate: func() *timestamppb.Timestamp { 57 | if account.ClosedAt != nil { 58 | return timestamppb.New(*account.ClosedAt) 59 | } else { 60 | return nil 61 | } 62 | }(), 63 | }, nil 64 | } 65 | -------------------------------------------------------------------------------- /internal/account/adapters/controllers/converters.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | contractv1 "github.com/sadensmol/article_my_clean_architecture_go_application/api/proto/v1" 5 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 6 | ) 7 | 8 | type AccountHandlerAccessLevel contractv1.AccessLevel 9 | 10 | func (cal AccountHandlerAccessLevel) ToDomain() domain.AccountAccessLevel { 11 | switch contractv1.AccessLevel(cal) { 12 | case contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_FULL_ACCESS: 13 | return domain.AccountAccessLevelFull 14 | case contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_READ_ONLY: 15 | return domain.AccountAccessLevelReadOnly 16 | case contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_NO_ACCESS: 17 | return domain.AccountAccessLevelNone 18 | default: 19 | return domain.AccountAccessLevelNone 20 | } 21 | } 22 | 23 | func AccountAccessLevelFromDomain(accessLevel domain.AccountAccessLevel) contractv1.AccessLevel { 24 | switch accessLevel { 25 | case domain.AccountAccessLevelFull: 26 | return contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_FULL_ACCESS 27 | case domain.AccountAccessLevelReadOnly: 28 | return contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_READ_ONLY 29 | case domain.AccountAccessLevelNone: 30 | return contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_NO_ACCESS 31 | default: 32 | return contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_UNKNOWN 33 | } 34 | } 35 | 36 | func AccountStatusFromDomain(status domain.AccountStatus) contractv1.AccountStatus { 37 | switch status { 38 | case domain.AccountStatusNew: 39 | return contractv1.AccountStatus_ACCOUNT_STATUS_NEW 40 | case domain.AccountStatusOpen: 41 | return contractv1.AccountStatus_ACCOUNT_STATUS_OPEN 42 | case domain.AccountStatusClosed: 43 | return contractv1.AccountStatus_ACCOUNT_STATUS_CLOSED 44 | default: 45 | return contractv1.AccountStatus_ACCOUNT_STATUS_UNKNOWN 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /internal/account/adapters/repositories/account-repository.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "github.com/go-jet/jet/v2/postgres" 7 | 8 | "github.com/sadensmol/article_my_clean_architecture_go_application/db/gen/account/public/model" 9 | "github.com/sadensmol/article_my_clean_architecture_go_application/db/gen/account/public/table" 10 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 11 | ) 12 | 13 | type AccountRepository struct { 14 | db *sql.DB 15 | } 16 | 17 | func NewAccountRepository(db *sql.DB) *AccountRepository { 18 | return &AccountRepository{db: db} 19 | } 20 | 21 | func (a *AccountRepository) Create(account domain.Account) (*domain.Account, error) { 22 | 23 | var savedAccount model.Account 24 | err := table.Account.INSERT(table.Account.Name, table.Account.AccessLevel). 25 | VALUES(account.Name, account.AccessLevel). 26 | RETURNING(table.Account.AllColumns).Query(a.db, &savedAccount) 27 | 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | return RepositoryModelAccount(savedAccount).toDomain(), nil 33 | } 34 | 35 | func (a *AccountRepository) GetByID(ID int64) (*domain.Account, error) { 36 | 37 | var savedAccounts []model.Account 38 | err := table.Account.SELECT(table.Account.AllColumns). 39 | WHERE(table.Account.ID.EQ(postgres.Int(ID))). 40 | Query(a.db, &savedAccounts) 41 | 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | if len(savedAccounts) == 0 { 47 | return nil, nil 48 | } 49 | if len(savedAccounts) > 1 { 50 | return nil, fmt.Errorf("GetByID returns non unique result") 51 | } 52 | 53 | return RepositoryModelAccount(savedAccounts[0]).toDomain(), nil 54 | } 55 | -------------------------------------------------------------------------------- /internal/account/adapters/repositories/converters.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "github.com/sadensmol/article_my_clean_architecture_go_application/db/gen/account/public/model" 5 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 6 | ) 7 | 8 | type RepositoryModelAccount model.Account 9 | 10 | func (a RepositoryModelAccount) toDomain() *domain.Account { 11 | return &domain.Account{ 12 | ID: a.ID, 13 | Name: a.Name, 14 | Status: func() domain.AccountStatus { 15 | switch a.Status { 16 | case "open": 17 | return domain.AccountStatusOpen 18 | case "closed": 19 | return domain.AccountStatusClosed 20 | case "new": 21 | return domain.AccountStatusNew 22 | default: 23 | return domain.AccountStatusUnknown 24 | } 25 | 26 | }(), 27 | AccessLevel: func() domain.AccountAccessLevel { 28 | switch a.AccessLevel { 29 | case "full": 30 | return domain.AccountAccessLevelFull 31 | case "readonly": 32 | return domain.AccountAccessLevelReadOnly 33 | case "none": 34 | return domain.AccountAccessLevelNone 35 | default: 36 | return domain.AccountAccessLevelNone 37 | } 38 | }(), 39 | OpenedAt: a.OpenedAt, 40 | ClosedAt: a.ClosedAt, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /internal/account/domain/account.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type AccountStatus string 8 | 9 | const ( 10 | AccountStatusNew AccountStatus = "new" 11 | AccountStatusOpen AccountStatus = "open" 12 | AccountStatusClosed AccountStatus = "closed" 13 | AccountStatusUnknown AccountStatus = "unknown" 14 | ) 15 | 16 | type AccountAccessLevel string 17 | 18 | const ( 19 | AccountAccessLevelFull AccountAccessLevel = "full" 20 | AccountAccessLevelReadOnly AccountAccessLevel = "readonly" 21 | AccountAccessLevelNone AccountAccessLevel = "none" 22 | ) 23 | 24 | type Account struct { 25 | ID int64 26 | Name string 27 | Status AccountStatus 28 | AccessLevel AccountAccessLevel 29 | OpenedAt time.Time 30 | ClosedAt *time.Time 31 | } 32 | -------------------------------------------------------------------------------- /internal/account/services/account-service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 4 | 5 | type AccountService struct { 6 | accountRepository AccountRepository 7 | } 8 | 9 | type AccountRepository interface { 10 | Create(account domain.Account) (*domain.Account, error) 11 | GetByID(ID int64) (*domain.Account, error) 12 | } 13 | 14 | func NewAccountService(accountRepository AccountRepository) *AccountService { 15 | return &AccountService{accountRepository: accountRepository} 16 | } 17 | 18 | func (s *AccountService) Create(account domain.Account) (*domain.Account, error) { 19 | return s.accountRepository.Create(account) 20 | } 21 | 22 | func (s *AccountService) GetByID(ID int64) (*domain.Account, error) { 23 | return s.accountRepository.GetByID(ID) 24 | } 25 | -------------------------------------------------------------------------------- /internal/account/usecases/account.go: -------------------------------------------------------------------------------- 1 | package usecases 2 | 3 | import ( 4 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 5 | ) 6 | 7 | type AccountUsecases struct { 8 | accountService AccountService 9 | } 10 | 11 | type AccountService interface { 12 | Create(account domain.Account) (*domain.Account, error) 13 | GetByID(ID int64) (*domain.Account, error) 14 | } 15 | 16 | func NewAccountUsecases(accountService AccountService) *AccountUsecases { 17 | return &AccountUsecases{accountService: accountService} 18 | } 19 | -------------------------------------------------------------------------------- /internal/account/usecases/create-account.go: -------------------------------------------------------------------------------- 1 | package usecases 2 | 3 | import ( 4 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 5 | ) 6 | 7 | func (a *AccountUsecases) Create(account domain.Account) (*domain.Account, error) { 8 | return a.accountService.Create(account) 9 | } 10 | -------------------------------------------------------------------------------- /internal/account/usecases/get-account-by-id.go: -------------------------------------------------------------------------------- 1 | package usecases 2 | 3 | import ( 4 | "github.com/sadensmol/article_my_clean_architecture_go_application/internal/account/domain" 5 | ) 6 | 7 | func (a *AccountUsecases) GetByID(ID int64) (*domain.Account, error) { 8 | return a.accountService.GetByID(ID) 9 | } 10 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | This is related to the following article: 2 | [My Clean Architecture Go Application](https://medium.com/@sadensmol/my-clean-architecture-go-application-e4611b1754cb) 3 | 4 | # install required dev tools 5 | 6 | ```shell 7 | go install \ 8 | github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \ 9 | github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \ 10 | google.golang.org/protobuf/cmd/protoc-gen-go \ 11 | google.golang.org/grpc/cmd/protoc-gen-go-grpc 12 | ``` 13 | 14 | 15 | # start it 16 | ```shell 17 | make up 18 | ``` 19 | 20 | # run tests 21 | 22 | ```shell 23 | make up 24 | go test ./... 25 | ``` 26 | -------------------------------------------------------------------------------- /tests/account_test.go: -------------------------------------------------------------------------------- 1 | package tests_test 2 | 3 | import ( 4 | "github.com/stretchr/testify/suite" 5 | "testing" 6 | ) 7 | 8 | type AccountTestSuite struct { 9 | suite.Suite 10 | } 11 | 12 | func TestAccountTestSuite(t *testing.T) { 13 | suite.Run(t, new(AccountTestSuite)) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /tests/create-account_test.go: -------------------------------------------------------------------------------- 1 | package tests_test 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "net/http/cookiejar" 7 | "time" 8 | 9 | contractv1 "github.com/sadensmol/article_my_clean_architecture_go_application/api/proto/v1" 10 | "github.com/steinfletcher/apitest" 11 | "github.com/steinfletcher/apitest-jsonpath" 12 | "google.golang.org/grpc" 13 | "google.golang.org/grpc/benchmark" 14 | "google.golang.org/grpc/credentials/insecure" 15 | ) 16 | 17 | func (s *AccountTestSuite) TestCreateAccount() { 18 | clientConn := benchmark.NewClientConn("localhost:9090", grpc.WithTransportCredentials(insecure.NewCredentials())) 19 | client := contractv1.NewAccountServiceClient(clientConn) 20 | response, err := client.Create(context.Background(), &contractv1.CreateAccountRequest{ 21 | Name: "test", 22 | AccessLevel: 2, 23 | }) 24 | 25 | s.Require().NoError(err) 26 | 27 | s.Require().NotNil(response) 28 | s.Require().NotNil(response.GetId()) 29 | } 30 | func (s *AccountTestSuite) TestCreateAccountHttp() { 31 | cookieJar, _ := cookiejar.New(nil) 32 | cli := &http.Client{ 33 | Timeout: time.Second * 1, 34 | Jar: cookieJar, 35 | } 36 | 37 | apitest.New(). // configuration 38 | EnableNetworking(cli). 39 | Post("http://localhost:8090/api/v1/account"). 40 | Expect(s.T()). 41 | Assert(jsonpath.Present("id")). 42 | Status(http.StatusOK). 43 | End() 44 | } 45 | -------------------------------------------------------------------------------- /tests/get-account-by-id_test.go: -------------------------------------------------------------------------------- 1 | package tests_test 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | jsonpath "github.com/steinfletcher/apitest-jsonpath" 7 | "net/http" 8 | "net/http/cookiejar" 9 | "time" 10 | 11 | contractv1 "github.com/sadensmol/article_my_clean_architecture_go_application/api/proto/v1" 12 | "github.com/steinfletcher/apitest" 13 | "google.golang.org/grpc" 14 | "google.golang.org/grpc/benchmark" 15 | "google.golang.org/grpc/credentials/insecure" 16 | ) 17 | 18 | const ( 19 | testAccountID int64 = 1 20 | ) 21 | 22 | func (s *AccountTestSuite) TestGetAccountById() { 23 | clientConn := benchmark.NewClientConn("localhost:9090", grpc.WithTransportCredentials(insecure.NewCredentials())) 24 | client := contractv1.NewAccountServiceClient(clientConn) 25 | 26 | response, err := client.GetById(context.Background(), &contractv1.GetAccountRequest{ 27 | Id: testAccountID, 28 | }) 29 | 30 | s.Require().NoError(err) 31 | 32 | s.Require().NotNil(response) 33 | s.Require().Equal(testAccountID, response.GetId()) 34 | s.Require().Equal("test_account", response.GetName()) 35 | s.Require().Equal(contractv1.AccountStatus_ACCOUNT_STATUS_OPEN, response.GetStatus()) 36 | s.Require().Equal(contractv1.AccessLevel_ACCOUNT_ACCESS_LEVEL_FULL_ACCESS, response.AccessLevel) 37 | s.Require().NotNil(response.GetOpenedDate()) 38 | s.Require().Nil(response.GetClosedDate()) 39 | } 40 | func (s *AccountTestSuite) TestGetAccountByIdHttp() { 41 | cookieJar, _ := cookiejar.New(nil) 42 | cli := &http.Client{ 43 | Timeout: time.Second * 1, 44 | Jar: cookieJar, 45 | } 46 | 47 | apitest.New(). // configuration 48 | EnableNetworking(cli). 49 | Get(fmt.Sprintf("http://localhost:8090/api/v1/account/%d", testAccountID)). 50 | Expect(s.T()). 51 | Assert(jsonpath.Chain(). 52 | Equal("id", "1"). 53 | Equal("name", "test_account"). 54 | Equal("status", "ACCOUNT_STATUS_OPEN"). 55 | Equal("accessLevel", "ACCOUNT_ACCESS_LEVEL_FULL_ACCESS"). 56 | Present("openedDate"). 57 | NotPresent("closedDate"). 58 | End()). 59 | Status(http.StatusOK). 60 | End() 61 | } 62 | --------------------------------------------------------------------------------