commit 26a48770eb1888006c0812d9df3a0a43a9047d3c Author: mirza Date: Wed Apr 23 08:44:55 2025 +0700 init project diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..4062a23 --- /dev/null +++ b/.air.toml @@ -0,0 +1,46 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./main" + cmd = "make build" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b368bec --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with "go test -c" +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +tmp/ + +# IDE specific files +.vscode +.idea + +# .env file +.env + +# Project build +main +*templ.go + +# OS X generated file +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..617d88c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM golang:1.23-alpine AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ + +RUN go mod tidy + +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/api +# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . + +FROM alpine:latest + +# Set timezone ke Asia/Jakarta +ENV TZ=Asia/Jakarta + +RUN apk --no-cache add ca-certificates tzdata + +WORKDIR /root/ + +COPY --from=builder /app/main . +COPY --from=builder /app/.env . +EXPOSE 8080 +CMD ["./main"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b77025c --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +# Simple Makefile for a Go project + +# Build the application +all: build test + +build: + @echo "Building..." + + + @go build -o main cmd/api/main.go + +# Run the application +run: + @go run cmd/api/main.go +# Create DB container +docker-run: + @docker-compose up --build +# Shutdown DB container +docker-down: + @if docker compose down 2>/dev/null; then \ + : ; \ + else \ + echo "Falling back to Docker Compose V1"; \ + docker-compose down; \ + @go test ./... -v +# Integrations Tests for the application +itest: + @echo "Running integration tests..." + @go test ./internal/database -v + +# Clean the binary +clean: + fi + +# Test the application +test: + @echo "Testing..." + @echo "Cleaning..." + @rm -f main + +# Live Reload +watch: + @if command -v air > /dev/null; then \ + air; \ + echo "Watching...";\ + else \ + read -p "Go's 'air' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/air-verse/air@latest; \ + air; \ + echo "Watching...";\ + else \ + echo "You chose not to install air. Exiting..."; \ + exit 1; \ + fi; \ + fi + +.PHONY: all build run test clean watch docker-run docker-down itest diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e9ad51 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# Project api-lis + +One Paragraph of project description goes here + +## Getting Started + +These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. + +## MakeFile + +Run build make command with tests +```bash +make all +``` + +Build the application +```bash +make build +``` + +Run the application +```bash +make run +``` +Create DB container +```bash +make docker-run +``` + +Shutdown DB Container +```bash +make docker-down +``` + +DB Integrations Test: +```bash +make itest +``` + +Live reload the application: +```bash +make watch +``` + +Run the test suite: +```bash +make test +``` + +Clean up binary from the last build: +```bash +make clean +``` diff --git a/cmd/api/main.go b/cmd/api/main.go new file mode 100644 index 0000000..a4099b7 --- /dev/null +++ b/cmd/api/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os/signal" + "syscall" + "time" + + "api-lis/internal/server" +) + +func gracefulShutdown(apiServer *http.Server, done chan bool) { + // Create context that listens for the interrupt signal from the OS. + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + // Listen for the interrupt signal. + <-ctx.Done() + + log.Println("shutting down gracefully, press Ctrl+C again to force") + + // The context is used to inform the server it has 5 seconds to finish + // the request it is currently handling + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := apiServer.Shutdown(ctx); err != nil { + log.Printf("Server forced to shutdown with error: %v", err) + } + + log.Println("Server exiting") + + // Notify the main goroutine that the shutdown is complete + done <- true +} + +func main() { + + server := server.NewServer() + + // Create a done channel to signal when the shutdown is complete + done := make(chan bool, 1) + + // Run graceful shutdown in a separate goroutine + go gracefulShutdown(server, done) + + err := server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + panic(fmt.Sprintf("http server error: %s", err)) + } + + // Wait for the graceful shutdown to complete + <-done + log.Println("Graceful shutdown complete.") +} diff --git a/cmd/api/main.goZone.Identifier b/cmd/api/main.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7da0f98 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + container_name: api-lis + restart: always + ports: + - 8080:8080 + volumes: + - .:/app + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + environment: + # TIMEZONE + - TZ=Asia/Jakarta + # DATABASE SIMRS V3.0 + - SIMRS_STAG_HOST=10.10.123.223 + - SIMRS_STAG_PORT=5432 + - SIMRS_STAG_NAME=simrsbackup + - SIMRS_STAG_USER=simtest + - SIMRS_STAG_PASS=12345 + # DATABASE SATU DATA + - SATUDATA_HOST=10.10.123.165 + - SATUDATA_USER=stim + - SATUDATA_PASS=stim*RS54 + - SATUDATA_NAME=satu_db + - SATUDATA_PORT=5000 + # BPJS + - BASEURL_BPJS=https://apijkn.bpjs-kesehatan.go.id/ + - CONS_ID=5257 + - USER_KEY=4cf1cbef8c008440bbe9ef9ba789e482 + - SECRET_KEY=1bV363512D + # SERVICE ANTROL + - ANTREAN_RS=antreanrs + # BPJS VCLAIM + - VCALIM_RS=vclaim-rest + # BPJS PCARE + - PCARE_RS=pcare-rest + # BPJS ICARE + - PCARE_APLICARE=ihs + # LIS MIKROBIOLOGI + - LIS_MIKROBIOLOGI_URL=http://10.10.123.218/ + - LIS_REGISTERPASIEN=registerpasien \ No newline at end of file diff --git a/docker-push.sh b/docker-push.sh new file mode 100644 index 0000000..0510d0d --- /dev/null +++ b/docker-push.sh @@ -0,0 +1,27 @@ +!/bin/bash + +#get image name +remote_url=$(git remote get-url origin) +image=$(echo $remote_url | sed 's|https://||g; s|.git||g') + +#get branch name +branch_name=$(git rev-parse --abbrev-ref HEAD) +clean_branch_name=${branch_name##*/} + +#get timestamp for the tag +timestamp=$(date +%Y%m%d%H%M%S) + +tag=$image:$timestamp-$clean_branch_name +latest=$image:latest-$clean_branch_name + +#build image +docker build -t $tag . +docker tag $tag $latest + +#push to dockerhub +docker login git.rssa.top -u stim -p 4fde63b07906e7bfa6b3493d76d153a3981039b9 +docker push $tag +docker push $latest + +#remove dangling images +docker system prune -f diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..87ed5d1 --- /dev/null +++ b/go.mod @@ -0,0 +1,91 @@ +module api-lis + +go 1.23.1 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/jackc/pgx/v5 v5.7.2 + github.com/joho/godotenv v1.5.1 + github.com/testcontainers/testcontainers-go v0.35.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0 + gorm.io/driver/postgres v1.5.11 + gorm.io/gorm v1.25.12 +) + +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/bytedance/sonic v1.12.7 // indirect + github.com/bytedance/sonic/loader v0.2.3 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/containerd/containerd v1.7.18 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v27.1.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.24.0 // indirect + github.com/goccy/go-json v0.10.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/stretchr/testify v1.10.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + golang.org/x/arch v0.13.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.36.3 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..66c07a0 --- /dev/null +++ b/go.sum @@ -0,0 +1,270 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/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/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q= +github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0= +github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= +github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/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 v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+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/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= +github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM= +github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64= +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/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +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/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo= +github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4= +github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0 h1:eEGx9kYzZb2cNhRbBrNOCL/YPOM7+RMJiy3bB+ie0/I= +github.com/testcontainers/testcontainers-go/modules/postgres v0.35.0/go.mod h1:hfH71Mia/WWLBgMD2YctYcMlfsbnT0hflweL1dy8Q4s= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= +golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/internal/database/database.go b/internal/database/database.go new file mode 100644 index 0000000..62a3214 --- /dev/null +++ b/internal/database/database.go @@ -0,0 +1,148 @@ +package database + +import ( + "context" + "fmt" + "log" + "os" + "strconv" + "strings" + "time" + + _ "github.com/jackc/pgx/v5/stdlib" + _ "github.com/joho/godotenv/autoload" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +type Services interface { + Health() map[string]string + GetDB(string) *gorm.DB +} + +type service struct { + simrsDB *gorm.DB + satuDataDB *gorm.DB +} + +var ( + hostSimrs = os.Getenv("SIMRS_STAG_HOST") + userNameSimrs = os.Getenv("SIMRS_STAG_USER") + passwordSimrs = os.Getenv("SIMRS_STAG_PASS") + dbNameSimrs = os.Getenv("SIMRS_STAG_NAME") + portSimrs = os.Getenv("SIMRS_STAG_PORT") + + hostSatuData = os.Getenv("SATUDATA_HOST") + userNameSatuData = os.Getenv("SATUDATA_USERNAME") + passwordSatuData = os.Getenv("SATUDATA_PASSWORD") + dbNameSatuData = os.Getenv("SATUDATA_NAME") + portSatuData = os.Getenv("SATUDATA_PORT") + + dbInstance *service +) + +func New() Services { + // Reuse Connection + if dbInstance != nil { + return dbInstance + } + simrs := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Jakarta", hostSimrs, userNameSimrs, passwordSimrs, dbNameSimrs, portSimrs) + + SimrsDB, err := gorm.Open(postgres.Open(simrs), &gorm.Config{}) + if err != nil { + log.Fatal("Failed to connect to database SIMRS: ", err) + } else { + log.Println("Successfully connected to the database SIMRS") + } + satuData := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Jakarta", hostSatuData, userNameSatuData, passwordSatuData, dbNameSatuData, portSatuData) + + satuDataDB, err := gorm.Open(postgres.Open(satuData), &gorm.Config{}) + if err != nil { + log.Fatal("Failed to connect to database SatuData: ", err) + } else { + log.Println("Successfully connected to the database SatuData") + } + + mongoURI := fmt.Sprintf("mongodb://%s:%s@%s:%s/%s?authSource=admin", + user, pass, host, port, database) + + dbInstance = &service{ + simrsDB: SimrsDB, + satuDataDB: satuDataDB, + } + return dbInstance +} + +// Health checks the health of the database connection by pinging the database. +// It returns a map with keys indicating various health statistics. +func (s *service) Health() map[string]string { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + stats := make(map[string]string) + + // Ping the database using GORM + db, err := s.simrsDB.DB() // Retrieve the underlying sql.DB instance from GORM + if err != nil { + stats["status"] = "down" + stats["error"] = fmt.Sprintf("failed to get sql.DB from GORM: %v", err) + log.Fatalf("failed to get sql.DB from GORM: %v", err) // Log the error and terminate the program + return stats + } + + err = db.PingContext(ctx) + if err != nil { + stats["status"] = "down" + stats["error"] = fmt.Sprintf("db down: %v", err) + log.Fatalf("db down: %v", err) // Log the error and terminate the program + return stats + } + + // Database is up, add more statistics + stats["status"] = "up" + stats["message"] = "It's healthy" + + // Get database stats + dbStats := db.Stats() + stats["open_connections"] = strconv.Itoa(dbStats.OpenConnections) + stats["in_use"] = strconv.Itoa(dbStats.InUse) + stats["idle"] = strconv.Itoa(dbStats.Idle) + stats["wait_count"] = strconv.FormatInt(dbStats.WaitCount, 10) + stats["wait_duration"] = dbStats.WaitDuration.String() + stats["max_idle_closed"] = strconv.FormatInt(dbStats.MaxIdleClosed, 10) + stats["max_lifetime_closed"] = strconv.FormatInt(dbStats.MaxLifetimeClosed, 10) + + // Evaluate stats to provide a health message + if dbStats.OpenConnections > 40 { // Assuming 50 is the max for this example + stats["message"] = "The database is experiencing heavy load." + } + + if dbStats.WaitCount > 1000 { + stats["message"] = "The database has a high number of wait events, indicating potential bottlenecks." + } + + if dbStats.MaxIdleClosed > int64(dbStats.OpenConnections)/2 { + stats["message"] = "Many idle connections are being closed, consider revising the connection pool settings." + } + + if dbStats.MaxLifetimeClosed > int64(dbStats.OpenConnections)/2 { + stats["message"] = "Many connections are being closed due to max lifetime, consider increasing max lifetime or revising the connection usage pattern." + } + + return stats +} + +// Close closes the database connection. +// It logs a message indicating the disconnection from the specific database. +// If the connection is successfully closed, it returns nil. +// If an error occurs while closing the connection, it returns the error. + +func (s *service) GetDB(database string) *gorm.DB { + if strings.ToLower(database) == "simrs" { + return s.simrsDB + } else if strings.ToLower(database) == "satudata" { + return s.satuDataDB + } + log.Println("Database tidak ditemukan") + return nil +} diff --git a/internal/database/database.goZone.Identifier b/internal/database/database.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/internal/database/database_test.go b/internal/database/database_test.go new file mode 100644 index 0000000..fd46cbb --- /dev/null +++ b/internal/database/database_test.go @@ -0,0 +1,100 @@ +package database + +import ( + "context" + "log" + "testing" + "time" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/postgres" + "github.com/testcontainers/testcontainers-go/wait" +) + +func mustStartPostgresContainer() (func(context.Context) error, error) { + var ( + dbName = "database" + dbPwd = "password" + dbUser = "user" + ) + + dbContainer, err := postgres.Run( + context.Background(), + "postgres:latest", + postgres.WithDatabase(dbName), + postgres.WithUsername(dbUser), + postgres.WithPassword(dbPwd), + testcontainers.WithWaitStrategy( + wait.ForLog("database system is ready to accept connections"). + WithOccurrence(2). + WithStartupTimeout(5*time.Second)), + ) + if err != nil { + return nil, err + } + + database = dbName + password = dbPwd + username = dbUser + + dbHost, err := dbContainer.Host(context.Background()) + if err != nil { + return dbContainer.Terminate, err + } + + dbPort, err := dbContainer.MappedPort(context.Background(), "5432/tcp") + if err != nil { + return dbContainer.Terminate, err + } + + host = dbHost + port = dbPort.Port() + + return dbContainer.Terminate, err +} + +func TestMain(m *testing.M) { + teardown, err := mustStartPostgresContainer() + if err != nil { + log.Fatalf("could not start postgres container: %v", err) + } + + m.Run() + + if teardown != nil && teardown(context.Background()) != nil { + log.Fatalf("could not teardown postgres container: %v", err) + } +} + +func TestNew(t *testing.T) { + srv := New() + if srv == nil { + t.Fatal("New() returned nil") + } +} + +func TestHealth(t *testing.T) { + srv := New() + + stats := srv.Health() + + if stats["status"] != "up" { + t.Fatalf("expected status to be up, got %s", stats["status"]) + } + + if _, ok := stats["error"]; ok { + t.Fatalf("expected error not to be present") + } + + if stats["message"] != "It's healthy" { + t.Fatalf("expected message to be 'It's healthy', got %s", stats["message"]) + } +} + +func TestClose(t *testing.T) { + srv := New() + + if srv.Close() != nil { + t.Fatalf("expected Close() to return nil") + } +} diff --git a/internal/database/database_test.goZone.Identifier b/internal/database/database_test.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/internal/server/routes.go b/internal/server/routes.go new file mode 100644 index 0000000..d392b24 --- /dev/null +++ b/internal/server/routes.go @@ -0,0 +1,35 @@ +package server + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + mikrobiologiHandler "api-lis/pkg/handlers/mikrobiologi" +) + +func (s *Server) RegisterRoutes() http.Handler { + r := gin.Default() + + r.GET("/hello", s.HelloWorldHandler) + r.GET("/health", s.healthHandler) + + v1 := r.Group("/api") + + mikrobiologi := v1.Group("/mikrobiologi") + { + mikrobiologi.POST("/sendmikro", mikrobiologiHandler.SendDataLISMikro) + } + return r +} + +func (s *Server) HelloWorldHandler(c *gin.Context) { + resp := make(map[string]string) + resp["message"] = "Hello World" + + c.JSON(http.StatusOK, resp) +} + +func (s *Server) healthHandler(c *gin.Context) { + c.JSON(http.StatusOK, s.db.Health()) +} diff --git a/internal/server/routes.goZone.Identifier b/internal/server/routes.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go new file mode 100644 index 0000000..db2233e --- /dev/null +++ b/internal/server/routes_test.go @@ -0,0 +1,32 @@ +package server + +import ( + "github.com/gin-gonic/gin" + "net/http" + "net/http/httptest" + "testing" +) + +func TestHelloWorldHandler(t *testing.T) { + s := &Server{} + r := gin.New() + r.GET("/", s.HelloWorldHandler) + // Create a test HTTP request + req, err := http.NewRequest("GET", "/", nil) + if err != nil { + t.Fatal(err) + } + // Create a ResponseRecorder to record the response + rr := httptest.NewRecorder() + // Serve the HTTP request + r.ServeHTTP(rr, req) + // Check the status code + if status := rr.Code; status != http.StatusOK { + t.Errorf("Handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + // Check the response body + expected := "{\"message\":\"Hello World\"}" + if rr.Body.String() != expected { + t.Errorf("Handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} diff --git a/internal/server/routes_test.goZone.Identifier b/internal/server/routes_test.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..0d295a3 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,39 @@ +package server + +import ( + "fmt" + "net/http" + "os" + "strconv" + "time" + + _ "github.com/joho/godotenv/autoload" + + "api-lis/internal/database" +) + +type Server struct { + port int + + db database.Service +} + +func NewServer() *http.Server { + port, _ := strconv.Atoi(os.Getenv("PORT")) + NewServer := &Server{ + port: port, + + db: database.New(), + } + + // Declare Server config + server := &http.Server{ + Addr: fmt.Sprintf(":%d", NewServer.port), + Handler: NewServer.RegisterRoutes(), + IdleTimeout: time.Minute, + ReadTimeout: 10 * time.Second, + WriteTimeout: 30 * time.Second, + } + + return server +} diff --git a/internal/server/server.goZone.Identifier b/internal/server/server.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/database.go b/pkg/database/simrs/database.go new file mode 100644 index 0000000..cb705e2 --- /dev/null +++ b/pkg/database/simrs/database.go @@ -0,0 +1,11 @@ +package simrs + +import "gorm.io/gorm" + +type DatabaseService struct { + DB *gorm.DB +} + +func NewDatabaseService(db *gorm.DB) *DatabaseService { + return &DatabaseService{DB: db} +} diff --git a/pkg/database/simrs/database.goZone.Identifier b/pkg/database/simrs/database.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/dokter.go b/pkg/database/simrs/dokter.go new file mode 100644 index 0000000..7ca2157 --- /dev/null +++ b/pkg/database/simrs/dokter.go @@ -0,0 +1,16 @@ +package simrs + +import ( + "log" +) + +func (s *DatabaseService) GetNamaDokter(kdDokter string) (string, error) { + var namaDokter string + querySelect := `SELECT namadokter FROM m_dokter where "kddokter" = ?` + errSelect := s.DB.Debug().Raw(querySelect, kdDokter).Scan(&namaDokter).Error + if errSelect != nil { + log.Println(errSelect) + return "", errSelect + } + return namaDokter, nil +} diff --git a/pkg/database/simrs/dokter.goZone.Identifier b/pkg/database/simrs/dokter.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/mikrobiologi.go b/pkg/database/simrs/mikrobiologi.go new file mode 100644 index 0000000..b26c77f --- /dev/null +++ b/pkg/database/simrs/mikrobiologi.go @@ -0,0 +1,82 @@ +package simrs + +import ( + "api-lis/pkg/models/simrs/mikrobiologi" + "errors" + "log" + + "gorm.io/gorm" +) + +func (s *DatabaseService) GetDataMikroBiologi(req *mikrobiologi.RequestPasienMikrobiologi) ([]*mikrobiologi.DataPasienMikrobiologi, error) { + var dataPasien []*mikrobiologi.DataPasienMikrobiologi + query := `select tom."nomr" as nomr, tomm."nonota" as nonota, tom."idxdaftar" as idxdaftar, tom."tglorder" as tglorder, tom."nolab" as nolab, tom."rajal" as statusrajal, tom."aps" as statusaps, + mp."nama" as nama, mp."noktp" as noktp, mp."noktp_baru" as noktpbaru, mp."tempat" as tmptlahir, mp."tgllahir" as tgllahir, mp."jeniskelamin" as jeniskelamin, mp."alamat" as alamat, + mpa."nama" as namaaps, mpa."noktp" as noktpaps, mpa."tempat" as tmptlahiraps, mpa."tgllahir" as tgllahiraps, mpa."jeniskelamin" as jeniskelaminaps, mpa."alamat" as alamataps, + mr."nama" as namaruang, mr."kelas" as kelasruang, + trj."kodetarif" as kodetarifrajal, + trp."kodetarif" as kodetarifranap + from t_orderlabmikro tom + left join m_pasien mp on mp."nomr" = tom."nomr" + left join m_pasien_aps mpa on mpa."nomr" = tom."nomr" + left join m_ruang mr on mr."no" = tom."kdpoli" + left join t_orderlabmikro_main tomm on tomm."nolab" = tom."nolab" + left join t_billrajal trj on trj."nonota" = CAST(tomm."nonota" AS int8) + left join t_billranap trp on trp."nonota" = CAST(tomm."nonota" AS int8) + where tom."nomr" = ? + and tom."idxdaftar" = ? + group by (tom."nomr",tomm."nonota",tom."idxdaftar",tom."tglorder",tom."nolab",tom."rajal",tom."aps",mp."nama",mp."noktp",mp."noktp_baru",mp."tempat",mp."tgllahir",mp."jeniskelamin",mp."alamat",mpa."nama",mpa."noktp", + mpa."tempat",mpa."tgllahir",mpa."jeniskelamin",mpa."alamat",mr."nama",mr."kelas",trj."kodetarif",trp."kodetarif") + ` + errQuery := s.DB.Debug().Raw(query, req.NOMR, req.IDXDaftar).Scan(&dataPasien).Error + if errQuery != nil { + if errors.Is(errQuery, gorm.ErrRecordNotFound) { + errMsg := errors.New("Data Tidak Ditemukan") + log.Println(errMsg) + return nil, errMsg + } + log.Println(errQuery) + return nil, errQuery + } + return dataPasien, nil +} + +func (s *DatabaseService) GetDataMikroBiologiByNoMR(req *mikrobiologi.RequestPasienMikrobiologi) ([]*mikrobiologi.OrderLabMikroMain, error) { + var data []*mikrobiologi.OrderLabMikroMain + query := `select * from "t_orderlabmikro_main" where "nomr" = ? and "idxdaftar" = ? and "nolab" = ?` + errSelect := s.DB.Debug().Raw(query, req.NOMR, req.IDXDaftar, req.NoLab).Scan(&data).Error + if errSelect != nil { + if errors.Is(errSelect, gorm.ErrRecordNotFound) { + errMsg := errors.New("Data Tidak Ditemukan") + log.Println(errMsg) + return nil, errMsg + } + log.Println(errSelect) + return nil, errSelect + } + return data, nil +} + +func (s *DatabaseService) GetDataLabMikro(noLab string) ([]*mikrobiologi.OrderLabMikro, bool, error) { + var dataMikro []*mikrobiologi.OrderLabMikro + querySelect := `select olm."idxordermikro", olm."jenis_pemeriksaan" + from t_orderlabmikro olm + left join "m_form_lab" fl on olm."idxform" = fl."form_id" + where olm."nolab" = ? and fl."sub_kelompok" = 'Jenis Pemeriksaan'` + errSelect := s.DB.Debug().Raw(querySelect, noLab).Scan(&dataMikro).Error + if errSelect != nil { + log.Println(errSelect) + return nil, false, errSelect + } + return dataMikro, true, nil +} + +func (s *DatabaseService) UpdateLabMikro(req *mikrobiologi.ReqUpdateLisMikro) error { + queryUpdate := `update "t_orderlabmikro" set "no_lokal" = ? where "idxordermikro" = ?` + errUpdate := s.DB.Debug().Exec(queryUpdate, req.NoLokal, req.IdxOrderMikro).Error + if errUpdate != nil { + log.Println(errUpdate) + return errUpdate + } + return nil +} diff --git a/pkg/database/simrs/mikrobiologi.goZone.Identifier b/pkg/database/simrs/mikrobiologi.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/pasien.go b/pkg/database/simrs/pasien.go new file mode 100644 index 0000000..273d70e --- /dev/null +++ b/pkg/database/simrs/pasien.go @@ -0,0 +1,18 @@ +package simrs + +import ( + "api-lis/pkg/models/simrs/mikrobiologi" + "api-lis/pkg/models/simrs/pasien" + "log" +) + +func (s *DatabaseService) GetMPasien(req *mikrobiologi.RequestPasienMikrobiologi) (*pasien.MPasien, error) { + var dataPasien *pasien.MPasien + querySelect := `select * from m_pasien where "nomr" = ?` + errSelect := s.DB.Debug().Raw(querySelect, req.NOMR).First(&dataPasien).Error + if errSelect != nil { + log.Println(errSelect) + return nil, errSelect + } + return dataPasien, nil +} diff --git a/pkg/database/simrs/pasien.goZone.Identifier b/pkg/database/simrs/pasien.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/pendaftaran.go b/pkg/database/simrs/pendaftaran.go new file mode 100644 index 0000000..59556ff --- /dev/null +++ b/pkg/database/simrs/pendaftaran.go @@ -0,0 +1,19 @@ +package simrs + +import ( + "api-lis/pkg/models/simrs/mikrobiologi" + "log" +) + +func (s *DatabaseService) GetCaraBayar(req *mikrobiologi.OrderLabMikroMain) (string, error) { + var CaraBayar string + query := `select mcb."nama" from t_pendaftaran tp + left join m_carabayar mcb on tp."kdcarabayar" = mcb.kode + where tp."idxdaftar" = ?` + errSelect := s.DB.Debug().Raw(query, req.IdxDaftar).First(&CaraBayar).Error + if errSelect != nil { + log.Println(errSelect) + return "", errSelect + } + return CaraBayar, nil +} diff --git a/pkg/database/simrs/pendaftaran.goZone.Identifier b/pkg/database/simrs/pendaftaran.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/database/simrs/ruang.go b/pkg/database/simrs/ruang.go new file mode 100644 index 0000000..85d85a8 --- /dev/null +++ b/pkg/database/simrs/ruang.go @@ -0,0 +1,17 @@ +package simrs + +import ( + "api-lis/pkg/models/simrs/ruang" + "log" +) + +func (s *DatabaseService) GetNamaRuang(kdPoli string) (*ruang.MRuang, error) { + var poli *ruang.MRuang + query := `select "nama", "subsistem" from m_ruang where "no" = ?` + errSelect := s.DB.Debug().Raw(query, kdPoli).Scan(&poli).Error + if errSelect != nil { + log.Println(errSelect) + return nil, errSelect + } + return poli, nil +} diff --git a/pkg/database/simrs/ruang.goZone.Identifier b/pkg/database/simrs/ruang.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/handlers/mikrobiologi/mikrobiologi.go b/pkg/handlers/mikrobiologi/mikrobiologi.go new file mode 100644 index 0000000..d69e62d --- /dev/null +++ b/pkg/handlers/mikrobiologi/mikrobiologi.go @@ -0,0 +1,161 @@ +package mikrobiologi + +import ( + "api-lis/internal/database" + "api-lis/pkg/database/simrs" + "api-lis/pkg/models/simrs/mikrobiologi" + "log" + "net/http" + "time" + + "github.com/gin-gonic/gin" +) + +func SendDataLISMikro(c *gin.Context) { + db := database.New().GetDB("simrs") + if db == nil { + log.Println("DB nil") + c.JSON(500, gin.H{"message": "DB nil"}) + return + } + simrsDB := simrs.NewDatabaseService(db) + var req *mikrobiologi.RequestPasienMikrobiologi + + err := c.Bind(&req) + if err != nil { + log.Println(err) + c.JSON(http.StatusBadRequest, gin.H{ + "message": err, + }) + return + } + + log.Println("REQUEST", req) + + dataMikro, errData := simrsDB.GetDataMikroBiologiByNoMR(req) + if errData != nil { + log.Println(errData) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errData, + }) + return + } + + dataPasien, errPasien := simrsDB.GetMPasien(req) + if errPasien != nil { + log.Println(errPasien) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errPasien, + }) + return + } + + tglLahir, errParse := time.Parse(time.RFC3339, dataPasien.TanggalLahir) + if errParse != nil { + log.Println(errParse) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errParse, + }) + return + } + + var responseMikro []*mikrobiologi.ResponseLISMikro + var dataLisMikro *mikrobiologi.RequestLISMikro + tglLahirString := tglLahir.Format("2006-01-02") + for _, dataMikroMain := range dataMikro { + dataLabMikro, exist, errDiagnosa := simrsDB.GetDataLabMikro(dataMikroMain.NoLab) + if errDiagnosa != nil { + log.Println(errDiagnosa) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errDiagnosa, + }) + return + } + + if !exist { + log.Println("Data bukan pemeriksaan") + continue + } + + namaDokter, errDokter := simrsDB.GetNamaDokter(dataMikroMain.DokterPengirim) + if errDokter != nil { + log.Println(errDokter) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errDokter, + }) + return + } + poli, errDokter := simrsDB.GetNamaRuang(dataMikroMain.KodePoli) + if errDokter != nil { + log.Println(errDokter) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errDokter, + }) + return + } + + caraBayar, errCaraBayar := simrsDB.GetCaraBayar(dataMikroMain) + if errCaraBayar != nil { + log.Println(errCaraBayar) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errCaraBayar, + }) + return + } + for _, value := range dataLabMikro { + dataLisMikro = &mikrobiologi.RequestLISMikro{ + NoRM: dataMikroMain.NoMR, + Nama: dataPasien.Nama, + Alamat: dataPasien.Alamat, + Kota: dataPasien.Tempat, + TanggalLahir: tglLahirString, + NoHP: dataPasien.NoTelpon, + Kelamin: dataPasien.JenisKelamin, + NIK: dataPasien.NoKTP, + NoBPJS: dataPasien.NoKartu, + DokterPeminta: namaDokter, + AsalPasien: poli.NamaPoli, + Layanan: value.NamaPemeriksaan, + StatusBayar: "", + NoTransaksi: dataMikroMain.NoLab, + Asuransi: caraBayar, + Klinis: "", + KodeSpesimen: dataMikroMain.StatusSpesimen, + NamaSpesimen: dataMikroMain.Spesimen, + Pengambilan: "", + } + + resMikro, errMikro := SendLisMikro(dataLisMikro) + if errMikro != nil { + log.Println(errMikro) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errMikro.Error(), + }) + return + } + + log.Println(resMikro) + + reqUpdate := &mikrobiologi.ReqUpdateLisMikro{ + IdxOrderMikro: value.IdxOrderMikro, + NoLokal: resMikro.Message, + } + errUpdate := simrsDB.UpdateLabMikro(reqUpdate) + if errUpdate != nil { + log.Println(errUpdate) + c.JSON(http.StatusBadRequest, gin.H{ + "message": errUpdate, + }) + return + } + + responseMikro = append(responseMikro, &mikrobiologi.ResponseLISMikro{ + NoLab: dataMikroMain.NoLab, + Status: resMikro.Status, + Message: resMikro.Message, + }) + } + } + log.Println("RESPONSE", responseMikro) + c.JSON(http.StatusOK, responseMikro) +} diff --git a/pkg/handlers/mikrobiologi/mikrobiologi.goZone.Identifier b/pkg/handlers/mikrobiologi/mikrobiologi.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/handlers/mikrobiologi/response.go b/pkg/handlers/mikrobiologi/response.go new file mode 100644 index 0000000..82f0f5b --- /dev/null +++ b/pkg/handlers/mikrobiologi/response.go @@ -0,0 +1,79 @@ +package mikrobiologi + +import ( + "api-lis/pkg/models/simrs/mikrobiologi" + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "os" +) + +func SendLisMikro(request *mikrobiologi.RequestLISMikro) (*mikrobiologi.Response, error) { + baseUrl := os.Getenv("LIS_MIKROBIOLOGI_URL") + endpoint := os.Getenv("LIS_REGISTERPASIEN") + url := baseUrl + endpoint + log.Println("URL", url) + + reqMarshall, err := json.Marshal(request) + if err != nil { + log.Printf("Error json marshal: %v", err) + return nil, err + } + headers := map[string]string{ + "Accept": "application/json", + "Content-Type": "application/json", + } + log.Println("REQUEST: ", string(reqMarshall)) + + req, err := http.NewRequest("POST", url, bytes.NewReader(reqMarshall)) + if err != nil { + log.Printf("Error creating request: %v", err) + return nil, err + } + + for key, value := range headers { + req.Header.Set(key, value) + } + + client := http.Client{} + + response, err := client.Do(req) + if err != nil { + log.Printf("Error making external API request: %v", err) + return nil, err + } + + log.Println(response) + + res, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println(err) + } + + if response.StatusCode != 201 { + var responseError *mikrobiologi.ResponseError + err = json.Unmarshal(res, &responseError) + if err != nil { + log.Printf("Error unmarshalling response: %v", err) + return nil, err + } + + log.Println("MASUK SINI?") + log.Println(responseError.Error) + return nil, fmt.Errorf(responseError.Error) + } + + var responses *mikrobiologi.Response + + log.Println("RESPONSE: ", string(res)) + err = json.Unmarshal(res, &responses) + if err != nil { + log.Printf("Error unmarshalling response: %v", err) + return nil, err + } + + return responses, nil +} diff --git a/pkg/handlers/mikrobiologi/response.goZone.Identifier b/pkg/handlers/mikrobiologi/response.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/models/simrs/mikrobiologi/mikrobiologi.go b/pkg/models/simrs/mikrobiologi/mikrobiologi.go new file mode 100644 index 0000000..fad06de --- /dev/null +++ b/pkg/models/simrs/mikrobiologi/mikrobiologi.go @@ -0,0 +1,157 @@ +package mikrobiologi + +type RequestPasienMikrobiologi struct { + NOMR string `json:"nomr"` + IDXDaftar string `json:"idxdaftar"` + NoLab string `json:"nolab"` +} + +type DataPasienMikrobiologi struct { + NOMR string `gorm:"column:nomr" json:"nomr"` + NoNota string `gorm:"column:nonota" json:"nonota"` + IDXDaftar int `gorm:"column:idxdaftar" json:"idxdaftar"` + TanggalOrder string `gorm:"column:tglorder" json:"tglorder"` + NoLab string `gorm:"column:nolab" json:"nolab"` + StatusRajal int `gorm:"column:statusrajal" json:"statusrajal"` + StatusAPS int `gorm:"column:statusaps" json:"statusaps"` + Nama string `gorm:"column:nama" json:"nama"` + NoKTP string `gorm:"column:noktp" json:"noktp"` + NoKTPBaru string `gorm:"column:noktpbaru" json:"noktpbaru"` + TempatLahir string `gorm:"column:tmptlahir" json:"tmptlahir"` + TanggalLahir string `gorm:"column:tgllahir" json:"tgllahir"` + JenisKelamin string `gorm:"column:jeniskelamin" json:"jeniskelamin"` + Alamat string `gorm:"column:alamat" json:"alamat"` + NamaAPS string `gorm:"column:namaaps" json:"namaaps"` + NoKTPAPS string `gorm:"column:noktpaps" json:"noktpaps"` + TempatLahirAPS string `gorm:"column:tmptlahiraps" json:"tmptlahiraps"` + TanggalLahirAPS string `gorm:"column:tgllahiraps" json:"tgllahiraps"` + JenisKelaminAPS string `gorm:"column:jeniskelaminaps" json:"jeniskelaminaps"` + AlamatAPS string `gorm:"column:alamataps" json:"alamataps"` + NamaRuang string `gorm:"column:namaruang" json:"namaruang"` + KelasRuang string `gorm:"column:kelasruang" json:"kelasruang"` + KodeTarifRajal string `gorm:"column:kodetarifrajal" json:"kodetarifrajal"` + KodeTarifRanap string `gorm:"column:kodetarifranap" json:"kodetarifranap"` +} + +type ResponseDataPasienRanap struct { + NOMR string `gorm:"column:nomr" json:"nomr"` + NoNota string `gorm:"column:nonota" json:"nonota"` + IDXDaftar int `gorm:"column:idxdaftar" json:"idxdaftar"` + TanggalOrder string `gorm:"column:tglorder" json:"tglorder"` + NoLab string `gorm:"column:nolab" json:"nolab"` + StatusRajal int `gorm:"column:statusrajal" json:"statusrajal"` + Nama string `gorm:"column:nama" json:"nama"` + NoKTP string `gorm:"column:noktp" json:"noktp"` + TempatLahir string `gorm:"column:tmptlahir" json:"tmptlahir"` + TanggalLahir string `gorm:"column:tgllahir" json:"tgllahir"` + JenisKelamin string `gorm:"column:jeniskelamin" json:"jeniskelamin"` + Alamat string `gorm:"column:alamat" json:"alamat"` + NamaRuang string `gorm:"column:namaruang" json:"namaruang"` + KelasRuang string `gorm:"column:kelasruang" json:"kelasruang"` + KodeTarifRanap string `gorm:"column:kodetarifranap" json:"kodetarifranap"` +} + +type ResponseDataPasienRajal struct { + NOMR string `gorm:"column:nomr" json:"nomr"` + NoNota string `gorm:"column:nonota" json:"nonota"` + IDXDaftar int `gorm:"column:idxdaftar" json:"idxdaftar"` + TanggalOrder string `gorm:"column:tglorder" json:"tglorder"` + NoLab string `gorm:"column:nolab" json:"nolab"` + StatusRajal int `gorm:"column:statusrajal" json:"statusrajal"` + Nama string `gorm:"column:nama" json:"nama"` + NoKTP string `gorm:"column:noktp" json:"noktp"` + TempatLahir string `gorm:"column:tmptlahir" json:"tmptlahir"` + TanggalLahir string `gorm:"column:tgllahir" json:"tgllahir"` + JenisKelamin string `gorm:"column:jeniskelamin" json:"jeniskelamin"` + Alamat string `gorm:"column:alamat" json:"alamat"` + NamaRuang string `gorm:"column:namaruang" json:"namaruang"` + KelasRuang string `gorm:"column:kelasruang" json:"kelasruang"` + KodeTarifRajal string `gorm:"column:kodetarifrajal" json:"kodetarifrajal"` +} + +type ResponseDataPasienRajalAPS struct { + NOMR string `gorm:"column:nomr" json:"nomr"` + NoNota string `gorm:"column:nonota" json:"nonota"` + IdxDaftar int `gorm:"column:idxdaftar" json:"idxdaftar"` + TanggalOrder string `gorm:"column:tglorder" json:"tglorder"` + NoLab string `gorm:"column:nolab" json:"nolab"` + StatusRajal int `gorm:"column:statusrajal" json:"statusrajal"` + StatusAPS int `gorm:"column:statusaps" json:"statusaps"` + NamaAPS string `gorm:"column:namaaps" json:"namaaps"` + NoKTPAPS string `gorm:"column:noktpaps" json:"noktpaps"` + TempatLahirAPS string `gorm:"column:tmptlahiraps" json:"tmptlahiraps"` + TanggalLahirAPS string `gorm:"column:tgllahiraps" json:"tgllahiraps"` + JenisKelaminAPS string `gorm:"column:jeniskelaminaps" json:"jeniskelaminaps"` + AlamatAPS string `gorm:"column:alamataps" json:"alamataps"` + NamaRuang string `gorm:"column:namaruang" json:"namaruang"` + KelasRuang string `gorm:"column:kelasruang" json:"kelasruang"` + KodeTarifRajal string `gorm:"column:kodetarifrajal" json:"kodetarifrajal"` +} + +type RequestLISMikro struct { + NoRM string `json:"norm"` + Nama string `json:"nama"` + Alamat string `json:"alamat"` + Kota string `json:"kota"` + TanggalLahir string `json:"tgllahir"` + NoHP string `json:"nohap"` + Kelamin string `json:"kelamin"` + NIK string `json:"nik"` + NoBPJS string `json:"nobpjs"` + DokterPeminta string `json:"drpeminta"` + AsalPasien string `json:"asalpasien"` + Layanan string `json:"layanan"` + StatusBayar string `json:"statusbayar"` + NoTransaksi string `json:"notransaksi"` + Asuransi string `json:"asuransi"` + Klinis string `json:"klinis"` + KodeSpesimen string `json:"kode"` + NamaSpesimen string `json:"spesimen"` + Pengambilan string `json:"pengambilan"` +} + +type OrderLabMikroMain struct { + IdxMikroMain string `gorm:"column:idxmikromain" json:"idxmikromain"` + NoLab string `gorm:"column:nolab" json:"nolab"` + IdxDaftar string `gorm:"column:idxdaftar" json:"idxdaftar"` + NoMR string `gorm:"column:nomr" json:"nomr"` + WaktuPengambilan string `gorm:"column:waktu_pengambilan" json:"waktu_pengambilan"` + TglOrder string `gorm:"column:tglorder" json:"tglorder"` + StatusSpesimen string `gorm:"column:status_specimen" json:"status_specimen"` + Spesimen string `gorm:"column:specimen" json:"specimen"` + DokterPengirim string `gorm:"column:drpengirim" json:"drpengirim"` + KodePoli string `gorm:"column:kdpoli" json:"kdpoli"` + NoNota string `gorm:"column:nonota" json:"nonota"` + StatusRajal string `gorm:"column:st_rajal" json:"st_rajal"` + StatusAPS string `gorm:"column:st_aps" json:"st_aps"` +} + +type OrderLabMikro struct { + IdxOrderMikro string `gorm:"column:idxordermikro" json:"idxordermikro"` + NamaPemeriksaan string `gorm:"column:nama_pemeriksaan" json:"nama_pemeriksaan"` +} + +type Response struct { + Status string `json:"status"` + Message string `json:"message"` +} + +type ResponseError struct { + Error string `json:"error"` +} + +type ResponseLISMikro struct { + NoLab string `json:"nolab"` + Status string `json:"status"` + Message string `json:"message"` +} + +type ReqUpdateLisMikro struct { + IdxOrderMikro string `gorm:"column:idxordermikro" json:"idxordermikro"` + NoLokal string `gorm:"column:no_lokal" json:"no_lokal"` +} + +type RequestBatalMikro struct { + NoLokal string `json:"no_lokal"` + Alasan string `json:"alasan"` +} diff --git a/pkg/models/simrs/mikrobiologi/mikrobiologi.goZone.Identifier b/pkg/models/simrs/mikrobiologi/mikrobiologi.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/models/simrs/pasien/pasien.go b/pkg/models/simrs/pasien/pasien.go new file mode 100644 index 0000000..3ffc59a --- /dev/null +++ b/pkg/models/simrs/pasien/pasien.go @@ -0,0 +1,14 @@ +package pasien + +type MPasien struct { + ID int `gorm:"column:id" json:"id"` + NoMR string `gorm:"column:no_mr" json:"no_mr"` + Nama string `gorm:"column:nama" json:"nama"` + Tempat string `gorm:"column:tempat" json:"tempat"` + TanggalLahir string `gorm:"column:tgllahir" json:"tgllahir"` + JenisKelamin string `gorm:"column:jeniskelamin" json:"jeniskelamin"` + Alamat string `gorm:"column:alamat" json:"alamat"` + NoKTP string `gorm:"column:noktp" json:"noktp"` + NoTelpon string `gorm:"column:notelp" json:"notelp"` + NoKartu string `gorm:"column:no_kartu" json:"no_kartu"` +} diff --git a/pkg/models/simrs/pasien/pasien.goZone.Identifier b/pkg/models/simrs/pasien/pasien.goZone.Identifier new file mode 100644 index 0000000..e69de29 diff --git a/pkg/models/simrs/ruang/ruang.go b/pkg/models/simrs/ruang/ruang.go new file mode 100644 index 0000000..a8a26ae --- /dev/null +++ b/pkg/models/simrs/ruang/ruang.go @@ -0,0 +1,6 @@ +package ruang + +type MRuang struct { + NamaPoli string `gorm:"column:nama" json:"nama"` + Subsistem string `gorm:"column:subsistem" json:"subsistem"` +} diff --git a/pkg/models/simrs/ruang/ruang.goZone.Identifier b/pkg/models/simrs/ruang/ruang.goZone.Identifier new file mode 100644 index 0000000..e69de29