You've already forked orderservice
Compare commits
2 Commits
f93bcaea03
...
c519941c5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
c519941c5a
|
|||
|
c3def9dc26
|
@@ -0,0 +1,51 @@
|
||||
ARG GOARCH=amd64
|
||||
ARG GOOS=linux
|
||||
ARG CGO_ENABLED=0
|
||||
ARG VERSION=1.0.0
|
||||
ARG BUILD_TIME=unknown
|
||||
|
||||
# Stage 1: Build
|
||||
FROM docker.io/golang:1.24-alpine AS build
|
||||
|
||||
ARG GOOS
|
||||
ARG GOARCH
|
||||
ARG CGO_ENABLED
|
||||
ARG VERSION
|
||||
ARG BUILD_TIME
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=${CGO_ENABLED} \
|
||||
GOOS=${GOOS} \
|
||||
GOARCH=${GOARCH} \
|
||||
go build -trimpath \
|
||||
-ldflags="-s -w -X 'main.Version=${VERSION}' -X 'main.BuildTime=${BUILD_TIME}'" \
|
||||
-o /bin/app ./cmd/migrate
|
||||
|
||||
# Stage 2: Runtime
|
||||
FROM docker.io/alpine:3.22 AS runtime
|
||||
|
||||
ARG VERSION
|
||||
ARG BUILD_TIME
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /bin/app /app/bin
|
||||
|
||||
RUN chown app:app /app/bin && chmod +x /app/bin
|
||||
|
||||
USER app
|
||||
|
||||
LABEL org.opencontainers.image.version=${VERSION}
|
||||
LABEL org.opencontainers.image.created=${BUILD_TIME}
|
||||
|
||||
ENTRYPOINT ["/app/bin"]
|
||||
|
||||
CMD [""]
|
||||
@@ -1,9 +1,10 @@
|
||||
# Go parameters
|
||||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOBUILD=$(GOCMD) build -trimpath -ldflags="-s -w"
|
||||
GOTEST=$(GOCMD) test
|
||||
GODOWNLOAD=$(GOCMD) mod download
|
||||
BINARY_NAME=orderservice
|
||||
MIGRATE_BINARY_NAME=orderservice-migrate
|
||||
BINARY_DIR=bin
|
||||
|
||||
# Protobuf parameters
|
||||
@@ -12,7 +13,7 @@ PROTO_DIR=api/proto
|
||||
PROTO_FILE=$(PROTO_DIR)/order.proto
|
||||
PROTO_OUT=.
|
||||
|
||||
.PHONY: install i generate gen protoc test build run lint fmt format clean help
|
||||
.PHONY: install i generate gen generate-gw test build run migrate lint fmt format clean help
|
||||
|
||||
install:
|
||||
$(GODOWNLOAD)
|
||||
@@ -38,9 +39,21 @@ build:
|
||||
$(GOBUILD) -o ./$(BINARY_DIR)/$(BINARY_NAME) ./cmd/server
|
||||
chmod +x ./$(BINARY_DIR)/$(BINARY_NAME)
|
||||
|
||||
build-migrate:
|
||||
$(GOBUILD) -o ./$(BINARY_DIR)/$(MIGRATE_BINARY_NAME) ./cmd/migrate
|
||||
chmod +x ./$(BINARY_DIR)/$(MIGRATE_BINARY_NAME)
|
||||
|
||||
run: build
|
||||
./$(BINARY_DIR)/$(BINARY_NAME)
|
||||
|
||||
migrate: build-migrate
|
||||
@cmd=$(word 2,$(MAKECMDGOALS)); \
|
||||
if [ -z "$$cmd" ]; then \
|
||||
echo "Usage: make migrate <command>"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
./$(BINARY_DIR)/$(MIGRATE_BINARY_NAME) -cmd $$cmd
|
||||
|
||||
lint:
|
||||
golangci-lint run -c .golangci.yaml ./...
|
||||
|
||||
@@ -68,3 +81,6 @@ help:
|
||||
@echo " clean - Clean build artifacts"
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
%:
|
||||
@:
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"embed"
|
||||
"errors"
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"orderservice/internal/config"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
"github.com/golang-migrate/migrate/v4/source/iofs"
|
||||
)
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrationsFS embed.FS
|
||||
|
||||
func main() {
|
||||
var cmd string
|
||||
|
||||
flag.StringVar(&cmd, "cmd", "up", "migration command: up|down|force|version")
|
||||
flag.Parse()
|
||||
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", cfg.BuildPostgresDSN())
|
||||
if err != nil {
|
||||
log.Fatalf("open db: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
drv, err := postgres.WithInstance(db, &postgres.Config{})
|
||||
if err != nil {
|
||||
log.Printf("postgres driver: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
src, err := iofs.New(migrationsFS, "migrations")
|
||||
if err != nil {
|
||||
log.Printf("iofs source: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
m, err := migrate.NewWithInstance("iofs", src, "postgres", drv)
|
||||
if err != nil {
|
||||
log.Printf("migrate NewWithInstance: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch cmd {
|
||||
case "up":
|
||||
if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||
log.Printf("m.Up failed: %v", err)
|
||||
return
|
||||
}
|
||||
log.Println("migrations applied (up)")
|
||||
case "down":
|
||||
if err := m.Steps(-1); err != nil {
|
||||
log.Printf("m.Steps(-1) failed: %v", err)
|
||||
return
|
||||
}
|
||||
log.Println("stepped down 1 migration")
|
||||
case "version":
|
||||
v, dirty, verr := m.Version()
|
||||
if verr != nil {
|
||||
log.Printf("version: %v", verr)
|
||||
return
|
||||
}
|
||||
log.Printf("version: %d dirty: %v\n", v, dirty)
|
||||
default:
|
||||
log.Printf("unknown cmd: %s", cmd)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
drop table if exists orders;
|
||||
+4
-4
@@ -13,7 +13,7 @@ import (
|
||||
func main() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load config: %v", err)
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
srv := server.New(cfg)
|
||||
@@ -21,7 +21,7 @@ func main() {
|
||||
|
||||
go func() {
|
||||
if err := srv.Start(); err != nil {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("Shutting down server...")
|
||||
log.Println("shutting down server...")
|
||||
srv.Stop()
|
||||
log.Println("Server stopped")
|
||||
log.Println("server stopped")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ services:
|
||||
context: .
|
||||
dockerfile: Containerfile
|
||||
depends_on:
|
||||
migrate:
|
||||
restart: false
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
postgres:
|
||||
restart: false
|
||||
condition: service_healthy
|
||||
@@ -36,6 +40,24 @@ services:
|
||||
restart: unless-stopped
|
||||
shm_size: 4mb
|
||||
|
||||
migrate:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Containerfile.migrate
|
||||
depends_on:
|
||||
postgres:
|
||||
restart: false
|
||||
condition: service_healthy
|
||||
required: true
|
||||
env_file:
|
||||
- path: ./infrastructure/core/.env.template
|
||||
required: true
|
||||
- path: ./infrastructure/core/.env
|
||||
networks:
|
||||
- default
|
||||
restart: no
|
||||
shm_size: 4mb
|
||||
|
||||
postgres:
|
||||
image: docker.io/postgres:17-alpine
|
||||
configs:
|
||||
|
||||
@@ -5,6 +5,7 @@ go 1.24.0
|
||||
toolchain go1.24.9
|
||||
|
||||
require (
|
||||
github.com/golang-migrate/migrate/v4 v4.19.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
@@ -18,6 +19,8 @@ require (
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
|
||||
@@ -1,20 +1,46 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
|
||||
github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
|
||||
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.0 h1:RcjOnCGz3Or6HQYEJ/EEVLfWnmw9KnoigPSjzhCuaSE=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.0/go.mod h1:9dyEcu+hO+G9hPSw8AIg50yg622pXJsoHItQnDGZkI0=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -23,6 +49,11 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
@@ -35,12 +66,30 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
|
||||
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
@@ -74,3 +123,5 @@ google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@@ -33,7 +34,7 @@ func Load() (*Config, error) {
|
||||
HTTPPort: mustGetInt("HTTP_PORT", 8080), //nolint:mnd // false-positive
|
||||
LogLevel: getEnv("LOG_LEVEL", "info"),
|
||||
DBHost: getEnv("POSTGRES_HOST", "localhost"),
|
||||
DBPort: mustGetInt("POSTGRES_PORT", 5432),
|
||||
DBPort: mustGetInt("POSTGRES_PORT", 5432), //nolint:mnd // false-positive
|
||||
DBUser: getEnv("POSTGRES_USERNAME", "postgres"),
|
||||
DBPassword: getEnv("POSTGRES_PASSWORD", "postgres"),
|
||||
DBName: getEnv("POSTGRES_DATABASE", "postgres"),
|
||||
@@ -66,7 +67,12 @@ func mustGetBool(key string, def bool) bool {
|
||||
return b
|
||||
}
|
||||
|
||||
func (c Config) BuildDsn() string {
|
||||
func (c Config) BuildPostgresConnStr() string {
|
||||
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||
c.DBHost, c.DBPort, c.DBUser, c.DBPassword, c.DBName)
|
||||
}
|
||||
|
||||
func (c Config) BuildPostgresDSN() string {
|
||||
return fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable",
|
||||
c.DBUser, c.DBPassword, net.JoinHostPort(c.DBHost, strconv.Itoa(c.DBPort)), c.DBName)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidID = errors.New("invalid uuid")
|
||||
)
|
||||
@@ -17,7 +17,7 @@ func mapError(err error) error {
|
||||
if errors.Is(err, domain.ErrOrderAlreadyExist) {
|
||||
return status.Error(codes.AlreadyExists, err.Error())
|
||||
}
|
||||
if errors.Is(err, domain.ErrInvalidOrderData) {
|
||||
if errors.Is(err, domain.ErrInvalidOrderData) || errors.Is(err, domain.ErrInvalidID) {
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"orderservice/internal/domain"
|
||||
"orderservice/internal/service"
|
||||
pb "orderservice/pkg/api/order"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderHandler struct {
|
||||
@@ -41,7 +43,12 @@ func (h *OrderHandler) CreateOrder(
|
||||
}
|
||||
|
||||
func (h *OrderHandler) GetOrder(ctx context.Context, req *pb.GetOrderRequest) (*pb.GetOrderResponse, error) {
|
||||
order, err := h.service.Get(ctx, req.GetId())
|
||||
parsedID, err := uuid.Parse(req.GetId())
|
||||
if err != nil {
|
||||
return nil, domain.ErrInvalidID
|
||||
}
|
||||
|
||||
order, err := h.service.Get(ctx, parsedID)
|
||||
if err != nil {
|
||||
return nil, mapError(err)
|
||||
}
|
||||
@@ -53,7 +60,12 @@ func (h *OrderHandler) UpdateOrder(
|
||||
ctx context.Context,
|
||||
req *pb.UpdateOrderRequest,
|
||||
) (*pb.UpdateOrderResponse, error) {
|
||||
order, err := h.service.Update(ctx, req.GetId(), req.GetItem(), req.GetQuantity())
|
||||
parsedID, err := uuid.Parse(req.GetId())
|
||||
if err != nil {
|
||||
return nil, domain.ErrInvalidID
|
||||
}
|
||||
|
||||
order, err := h.service.Update(ctx, parsedID, req.GetItem(), req.GetQuantity())
|
||||
if err != nil {
|
||||
return nil, mapError(err)
|
||||
}
|
||||
@@ -65,7 +77,12 @@ func (h *OrderHandler) DeleteOrder(
|
||||
ctx context.Context,
|
||||
req *pb.DeleteOrderRequest,
|
||||
) (*pb.DeleteOrderResponse, error) {
|
||||
err := h.service.Delete(ctx, req.GetId())
|
||||
parsedID, err := uuid.Parse(req.GetId())
|
||||
if err != nil {
|
||||
return nil, domain.ErrInvalidID
|
||||
}
|
||||
|
||||
err = h.service.Delete(ctx, parsedID)
|
||||
if err != nil {
|
||||
return nil, mapError(err)
|
||||
}
|
||||
|
||||
@@ -32,13 +32,13 @@ func (i *LoggerInterceptor) Unary() grpc.UnaryServerInterceptor {
|
||||
|
||||
if err != nil {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
log.Printf("Error: %s, Code: %s, Duration: %v",
|
||||
log.Printf("error: %s, code: %s, duration: %v",
|
||||
st.Message(), st.Code(), duration)
|
||||
} else {
|
||||
log.Printf("Error: %v, Duration: %v", err, duration)
|
||||
log.Printf("error: %v, duration: %v", err, duration)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Method %s completed in %v", info.FullMethod, duration)
|
||||
log.Printf("method %s completed in %v", info.FullMethod, duration)
|
||||
}
|
||||
|
||||
return resp, err
|
||||
@@ -61,10 +61,10 @@ func (i *LoggerInterceptor) Stream() grpc.StreamServerInterceptor {
|
||||
duration := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Stream method %s failed: %v, Duration: %v",
|
||||
log.Printf("stream method %s failed: %v, duration: %v",
|
||||
info.FullMethod, err, duration)
|
||||
} else {
|
||||
log.Printf("Stream method %s completed in %v",
|
||||
log.Printf("stream method %s completed in %v",
|
||||
info.FullMethod, duration)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"orderservice/internal/domain"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderRepository struct {
|
||||
@@ -34,7 +36,7 @@ func (r *OrderRepository) Create(ctx context.Context, order *domain.Order) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *OrderRepository) Get(ctx context.Context, id string) (*domain.Order, error) {
|
||||
func (r *OrderRepository) Get(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,7 +44,7 @@ func (r *OrderRepository) Get(ctx context.Context, id string) (*domain.Order, er
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
order, ok := r.orders[id]
|
||||
order, ok := r.orders[id.String()]
|
||||
if !ok {
|
||||
return nil, domain.ErrOrderNotFound
|
||||
}
|
||||
@@ -66,7 +68,7 @@ func (r *OrderRepository) Update(ctx context.Context, order *domain.Order) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *OrderRepository) Delete(ctx context.Context, id string) error {
|
||||
func (r *OrderRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -74,11 +76,11 @@ func (r *OrderRepository) Delete(ctx context.Context, id string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if _, ok := r.orders[id]; !ok {
|
||||
if _, ok := r.orders[id.String()]; !ok {
|
||||
return domain.ErrOrderNotFound
|
||||
}
|
||||
|
||||
delete(r.orders, id)
|
||||
delete(r.orders, id.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import (
|
||||
"context"
|
||||
|
||||
"orderservice/internal/domain"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type OrderRepository interface {
|
||||
Create(ctx context.Context, order *domain.Order) error
|
||||
Get(ctx context.Context, id string) (*domain.Order, error)
|
||||
Get(ctx context.Context, id uuid.UUID) (*domain.Order, error)
|
||||
Update(ctx context.Context, order *domain.Order) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
Delete(ctx context.Context, id uuid.UUID) error
|
||||
List(ctx context.Context) ([]*domain.Order, error)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package postgres
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -12,24 +11,19 @@ import (
|
||||
|
||||
"orderservice/internal/domain"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq" // postgres driver
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
//go:embed schema.sql
|
||||
var Schema string
|
||||
|
||||
const (
|
||||
orderCachePrefix = "order:"
|
||||
cacheTTL = 5 * time.Minute
|
||||
maxCacheRetries = 2
|
||||
cacheRetryDelay = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
type OrderRepository struct {
|
||||
db *sqlx.DB
|
||||
cache *redis.Client
|
||||
redisClient *redis.Client
|
||||
cacheEnable bool
|
||||
}
|
||||
|
||||
@@ -46,7 +40,7 @@ func NewOrderRepository(db *sqlx.DB, redisClient *redis.Client, config *Config)
|
||||
|
||||
return &OrderRepository{
|
||||
db: db,
|
||||
cache: redisClient,
|
||||
redisClient: redisClient,
|
||||
cacheEnable: config.CacheEnable,
|
||||
}
|
||||
}
|
||||
@@ -77,19 +71,19 @@ func (r *OrderRepository) Create(ctx context.Context, order *domain.Order) error
|
||||
|
||||
if r.cacheEnable {
|
||||
if err := r.setCacheWithRetry(ctx, order); err != nil {
|
||||
log.Printf("WARN: cache set error for order %s: %v", order.ID, err)
|
||||
log.Printf("warn: cache set error for order %s: %v", order.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *OrderRepository) Get(ctx context.Context, id string) (*domain.Order, error) {
|
||||
func (r *OrderRepository) Get(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
if r.cacheEnable {
|
||||
if order, err := r.getFromCache(ctx, id); err == nil {
|
||||
if order, err := r.getFromCache(ctx, id.String()); err == nil {
|
||||
return order, nil
|
||||
} else if !errors.Is(err, redis.Nil) {
|
||||
log.Printf("WARN: cache get error for order %s: %v", id, err)
|
||||
log.Printf("warn: cache get error for order %s: %v", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +103,7 @@ func (r *OrderRepository) Get(ctx context.Context, id string) (*domain.Order, er
|
||||
|
||||
if r.cacheEnable {
|
||||
if err := r.setCacheWithRetry(ctx, &order); err != nil {
|
||||
log.Printf("WARN: cache set error for order %s: %v", id, err)
|
||||
log.Printf("warn: cache set error for order %s: %v", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,14 +143,14 @@ func (r *OrderRepository) Update(ctx context.Context, order *domain.Order) error
|
||||
|
||||
if r.cacheEnable {
|
||||
if err := r.setCacheWithRetry(ctx, order); err != nil {
|
||||
log.Printf("WARN: cache set error for order %s: %v", order.ID, err)
|
||||
log.Printf("warn: cache set error for order %s: %v", order.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *OrderRepository) Delete(ctx context.Context, id string) error {
|
||||
func (r *OrderRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
tx, err := r.db.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin transaction: %w", err)
|
||||
@@ -186,7 +180,7 @@ func (r *OrderRepository) Delete(ctx context.Context, id string) error {
|
||||
return fmt.Errorf("commit transaction: %w", err)
|
||||
}
|
||||
|
||||
r.invalidateCache(ctx, id)
|
||||
r.invalidateCache(ctx, id.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -206,14 +200,14 @@ func (r *OrderRepository) List(ctx context.Context) ([]*domain.Order, error) {
|
||||
}
|
||||
|
||||
func (r *OrderRepository) getFromCache(ctx context.Context, id string) (*domain.Order, error) {
|
||||
data, err := r.cache.Get(ctx, r.cacheKey(id)).Bytes()
|
||||
data, err := r.redisClient.Get(ctx, r.cacheKey(id)).Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var order domain.Order
|
||||
if err := json.Unmarshal(data, &order); err != nil {
|
||||
r.cache.Del(ctx, r.cacheKey(id))
|
||||
r.redisClient.Del(ctx, r.cacheKey(id))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -228,16 +222,7 @@ func (r *OrderRepository) setCacheWithRetry(ctx context.Context, order *domain.O
|
||||
|
||||
key := r.cacheKey(order.ID.String())
|
||||
|
||||
for i := range maxCacheRetries {
|
||||
err = r.cache.Set(ctx, key, data, cacheTTL).Err()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if i < maxCacheRetries-1 {
|
||||
time.Sleep(cacheRetryDelay)
|
||||
}
|
||||
}
|
||||
err = r.redisClient.Set(ctx, key, data, cacheTTL).Err()
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -248,11 +233,11 @@ func (r *OrderRepository) invalidateCache(_ context.Context, id string) {
|
||||
}
|
||||
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), r.redisClient.Options().ReadTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := r.cache.Del(ctx, r.cacheKey(id)).Err(); err != nil {
|
||||
log.Printf("WARN: cache invalidation failed for order %s: %v", id, err)
|
||||
if err := r.redisClient.Del(ctx, r.cacheKey(id)).Err(); err != nil {
|
||||
log.Printf("warn: cache invalidation failed for order %s: %v", id, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
+35
-11
@@ -6,6 +6,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"orderservice/internal/config"
|
||||
"orderservice/internal/interceptor"
|
||||
@@ -19,12 +20,25 @@ import (
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq" // postgres driver
|
||||
"github.com/redis/go-redis/v9"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
const (
|
||||
httpReadTimeout = 10 * time.Second
|
||||
httpWriteTimeout = 10 * time.Second
|
||||
httpIdleTimeout = 60 * time.Second
|
||||
redisRetryCount = 2
|
||||
redisMinRetryBackoff = 50 * time.Millisecond
|
||||
redisMaxRetryBackoff = 200 * time.Millisecond
|
||||
redisDialTimeout = 1 * time.Second
|
||||
redisDialerRetries = 3
|
||||
redisTimeout = 2 * time.Second
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
grpcServer *grpc.Server
|
||||
config *config.Config
|
||||
@@ -62,28 +76,38 @@ func runHTTPHandler(s *Server, grpcServerEndpoint *string) error {
|
||||
mux.Handle("/healthz", httpHandlers.NewHealthHandler(s.db, s.redisDB))
|
||||
mux.Handle("/", gwmux)
|
||||
|
||||
addr := fmt.Sprintf(":%d", s.config.HTTPPort)
|
||||
return http.ListenAndServe(addr, mux)
|
||||
srv := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", s.config.HTTPPort),
|
||||
Handler: mux,
|
||||
ReadTimeout: httpReadTimeout,
|
||||
WriteTimeout: httpWriteTimeout,
|
||||
IdleTimeout: httpIdleTimeout,
|
||||
}
|
||||
|
||||
return srv.ListenAndServe()
|
||||
}
|
||||
|
||||
func getDatabase(cfg config.Config) (*sqlx.DB, error) {
|
||||
db, err := sqlx.Connect("postgres", cfg.BuildDsn())
|
||||
db, err := sqlx.Connect("postgres", cfg.BuildPostgresConnStr())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connect to database: %w", err)
|
||||
}
|
||||
|
||||
_, err = db.Exec(orderPostgresRepo.Schema)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("run schema: %w", err)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func getRedis(cfg config.Config) (*redis.Client, error) {
|
||||
conn, err := redis.ParseURL(cfg.RedisURI)
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: conn.Addr,
|
||||
Addr: conn.Addr,
|
||||
MaxRetries: redisRetryCount,
|
||||
MinRetryBackoff: redisMinRetryBackoff,
|
||||
MaxRetryBackoff: redisMaxRetryBackoff,
|
||||
DialTimeout: redisDialTimeout,
|
||||
DialerRetries: redisDialerRetries,
|
||||
DialerRetryTimeout: redisDialTimeout,
|
||||
ReadTimeout: redisTimeout,
|
||||
WriteTimeout: redisTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse Redis URI: %w", err)
|
||||
@@ -131,14 +155,14 @@ func (s *Server) Start() error {
|
||||
|
||||
if s.config.EnableHTTPHandler {
|
||||
go func() {
|
||||
log.Printf("Starting HTTP gateway on port %d", s.config.HTTPPort)
|
||||
log.Printf("starting HTTP gateway on port %d", s.config.HTTPPort)
|
||||
if err := runHTTPHandler(s, &addr); err != nil {
|
||||
log.Printf("HTTP gateway failed: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
log.Printf("Starting gRPC server on port %d", s.config.GRPCPort)
|
||||
log.Printf("starting gRPC server on port %d", s.config.GRPCPort)
|
||||
|
||||
if err := s.grpcServer.Serve(lis); err != nil {
|
||||
return fmt.Errorf("failed to serve: %w", err)
|
||||
|
||||
@@ -37,11 +37,11 @@ func (s *OrderService) Create(ctx context.Context, item string, quantity int32)
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (s *OrderService) Get(ctx context.Context, id string) (*domain.Order, error) {
|
||||
func (s *OrderService) Get(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
return s.repo.Get(ctx, id)
|
||||
}
|
||||
|
||||
func (s *OrderService) Update(ctx context.Context, id string, item string, quantity int32) (*domain.Order, error) {
|
||||
func (s *OrderService) Update(ctx context.Context, id uuid.UUID, item string, quantity int32) (*domain.Order, error) {
|
||||
order, err := s.repo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -61,7 +61,7 @@ func (s *OrderService) Update(ctx context.Context, id string, item string, quant
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (s *OrderService) Delete(ctx context.Context, id string) error {
|
||||
func (s *OrderService) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
return s.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user