setup database done

3/connect_db
ajikamaludin 2 years ago
parent a2196f975e
commit 9f272786c6
Signed by: ajikamaludin
GPG Key ID: 476C9A2B4B794EBB

@ -70,7 +70,11 @@ g.Go(func() error { return router.NewHTTPServer(configs, logger) })
- `go run .` run grpc and http server
- test `curl localhost:8080/api/v1/health/status`, reponse
```
{"success":true,"code":"0000","desc":"SUCCESS"}
{
"success":true,
"code":"0000",
"desc":"SUCCESS"
}
```
- GENERATE API DOCS:
- `mkdir swagger`
@ -91,4 +95,23 @@ func CreateSwagger(gwmux *http.ServeMux) {
http.ServeFile(w, r, "swagger/docs.json")
})
}
```
```
### Implement DB_Connection (With PostgreSQL)
- Execute `example.sql` in db, you know how to do it
- add `config.yaml` with line below
```
postgres:
host: 127.0.0.1
port: 5432
dbname: test
username: postgres
password: mysecretpassword
```
- changes `pkg/v1/config/config.go` to add new config line in config struct and and validateConfigData rule
- `go get github.com/lib/pq`
- create `pkg/v1/postgres` dir, create `postgres.go` file in there implement string conn and test connection
- create `pkg/v1/utils/converter` dir, create `converter.go` file in there, to convert camelcase to snake_case
- create `pkg/v1/postgres/custom.main.go` to implement all query to database table custom
- changes `configs/configs.go` to bundle pg connection
- how to use custom.main.go call function from custom main in api status, check `api/v1/health/status.go`

@ -2,13 +2,31 @@ package health
import (
"context"
"errors"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/postgres"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants"
hlpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/health"
"github.com/golang/protobuf/ptypes/empty"
)
func (s *Server) Status(ctx context.Context, req *empty.Empty) (*hlpb.Response, error) {
// select db
rows, err := s.config.Pg.CustomMainSelect(&postgres.CustomMain{UserId: "abc"})
if err != nil {
s.logger.Errorf("[HEALTH][GET] ERROR %v", err)
}
if len(rows) <= 0 {
s.logger.Errorf("[HEALTH][GET] EMPTY ROW")
return nil, errors.New("Invoke empty rows")
} else {
for _, v := range rows {
s.logger.Infof("[HEALTH][GET][ROW] %v", v)
}
}
return &hlpb.Response{
Success: true,
Code: constants.SuccessCode,

@ -5,3 +5,9 @@ server:
port: 5566
rest:
port: 8080
postgres:
host: 127.0.0.1
port: 5432
dbname: test
username: aji
password: eta

@ -4,12 +4,14 @@ import (
"log"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/config"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/postgres"
"github.com/sirupsen/logrus"
)
// bundle/wrap another service access here
type Configs struct {
Config *config.Config
Pg *postgres.Conn
}
func New() (*Configs, *logrus.Logger, error) {
@ -32,9 +34,14 @@ func New() (*Configs, *logrus.Logger, error) {
logger.Info("[CONFIG] Setup complete")
// TODO: pg letter
// Test Pg Con
pg, err := postgres.New(config)
if err != nil {
return nil, nil, err
}
return &Configs{
Config: config,
Pg: pg,
}, logger, nil
}

@ -0,0 +1,31 @@
CREATE DATABASE test;
CREATE SCHEMA custom;
CREATE TABLE IF NOT EXISTS custom.main (
user_id VARCHAR (50) PRIMARY KEY,
pass VARCHAR (256) NOT NUll,
del_flag BOOLEAN default FALSE,
description VARCHAR(50),
cre_id VARCHAR (50) NOT NULL,
cre_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
mod_id VARCHAR (50) NOT NULL,
mod_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
mod_ts INT NOT NULL
);
CREATE OR REPLACE FUNCTION custom.trigger_set_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.mod_time = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE TRIGGER set_timestamp
BEFORE UPDATE ON custom.main
FOR EACH ROW
EXECUTE PROCEDURE custom.trigger_set_timestamp();
INSERT INTO custom.main (user_id, pass, cre_id, mod_id, mod_ts) VALUES ('abc', 'password', 1, 1, 1);
SELECT * FROM custom.main;
UPDATE custom.main SET pass = 'pass', mod_ts = 3;

@ -14,7 +14,10 @@ require (
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
)
require github.com/felixge/httpsnoop v1.0.1 // indirect
require (
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/lib/pq v1.10.6 // indirect
)
require (
github.com/golang/protobuf v1.5.2

@ -52,6 +52,8 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=

@ -21,6 +21,13 @@ type Config struct {
Port int `yaml:"port"`
} `yaml:"rest"`
} `yaml:"server"`
Postgres struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Dbname string `yaml:"dbname"`
Username string `yaml:"username"`
Password string `yaml:"password"`
} `yaml:"postgres"`
}
func New() (*Config, error) {
@ -100,5 +107,21 @@ func validateConfigData(config *Config) error {
return errors.New("server.rest.port is empty")
}
if config.Postgres.Host == "" {
return errors.New("postgres.host is empty")
}
if config.Postgres.Port == 0 {
return errors.New("postgres.port is empty")
}
if config.Postgres.Dbname == "" {
return errors.New("postgres.dbname is empty")
}
if config.Postgres.Username == "" {
return errors.New("postgres.user is empty")
}
if config.Postgres.Password == "" {
return errors.New("postgres.pass is empty")
}
return nil
}

@ -0,0 +1,74 @@
package postgres
import (
"database/sql"
"fmt"
"reflect"
"strings"
"time"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/converter"
)
type CustomMain struct {
UserId string `db:"user_id,omitempty"`
Pass string `db:"pass,omitempty"`
DelFlag bool `db:"del_flag,omitempty"`
Description sql.NullString `db:"description,omitempty"`
CreId string `db:"cre_id,omitempty"`
CreTime time.Time `db:"cre_time,omitempty"`
ModId string `db:"mod_id,omitempty"`
ModTime time.Time `db:"mod_time,omitempty"`
ModTs int `db:"mod_td,omitempty"`
}
func (c *Conn) CustomMainSelect(filter *CustomMain) ([]*CustomMain, error) {
//create query syntax
qsyntax := fmt.Sprintf(`SELECT * FROM %s`, constants.Table_Custom_Main)
fil := reflect.ValueOf(*filter)
for i := 0; i < fil.NumField(); i++ {
if !fil.Field(i).IsZero() {
if i == 0 {
qsyntax = fmt.Sprintf(`%s WHERE`, qsyntax)
}
qsyntax = fmt.Sprintf(`%s %s = '%v'`, qsyntax, converter.CamelToSnakeCase(fil.Type().Field(i).Name), fil.Field(i))
}
}
qsyntax = strings.TrimRight(qsyntax, "AND")
qsyntax = fmt.Sprintf(`%s;`, qsyntax)
fmt.Println(qsyntax)
db, err := sql.Open(POSTGRES, c.Conn)
if err != nil {
return nil, err
}
rows, err := db.Query(qsyntax)
defer db.Close()
if err != nil {
return nil, err
}
defer rows.Close()
var rowsScanArr []*CustomMain
for rows.Next() {
var rowsScan CustomMain
err := rows.Scan(&rowsScan.UserId, &rowsScan.Pass,
&rowsScan.DelFlag, &rowsScan.Description, &rowsScan.CreId,
&rowsScan.CreTime, &rowsScan.ModId, &rowsScan.ModTime, &rowsScan.ModTs)
if err != nil {
return nil, err
}
rowsScanArr = append(rowsScanArr, &rowsScan)
}
return rowsScanArr, nil
}

@ -0,0 +1,41 @@
package postgres
import (
"database/sql"
"fmt"
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/config"
_ "github.com/lib/pq"
)
const (
POSTGRES string = "postgres"
)
type Conn struct {
Conn string
}
func New(config *config.Config) (*Conn, error) {
conn := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v sslmode=disable",
config.Postgres.Host,
config.Postgres.Port,
config.Postgres.Username,
config.Postgres.Password,
config.Postgres.Dbname)
db, err := sql.Open(POSTGRES, conn)
if err != nil {
return nil, err
}
err = db.Ping()
defer db.Close()
if err != nil {
return nil, err
}
return &Conn{
Conn: conn,
}, nil
}

@ -8,3 +8,7 @@ const (
SuccessCode = `0000`
SuccesDesc = `SUCCESS`
)
const (
Table_Custom_Main = "custom.main"
)

@ -0,0 +1,16 @@
package converter
import (
"regexp"
"strings"
)
func CamelToSnakeCase(str string) string {
var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)")
var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])")
snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}")
snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}")
return strings.ToLower(snake)
}
Loading…
Cancel
Save