Skip to content

Commit

Permalink
feat(): added sql config server
Browse files Browse the repository at this point in the history
  • Loading branch information
alfarih31 committed Jul 27, 2023
1 parent e0c0f61 commit ce09762
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 22 deletions.
5 changes: 3 additions & 2 deletions config_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package env
import (
"encoding/json"
"errors"
"github.com/alfarih31/nb-go-env/internal"
"github.com/joho/godotenv"
"log"
"os"
Expand Down Expand Up @@ -34,11 +35,11 @@ func (dc defaultConfigServer) Get(k string) (string, bool) {
if dc.useDotEnv {
cfg, exist := dc.envs[k]

return cfg, !hasZeroValue(cfg) && exist
return cfg, !internal.HasZeroValue(cfg) && exist
}

cfg := os.Getenv(k)
return cfg, !hasZeroValue(cfg)
return cfg, !internal.HasZeroValue(cfg)
}

func NewDefaultConfigServer(envPath string, fallbackToWide ...bool) (ConfigServer, error) {
Expand Down
20 changes: 0 additions & 20 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,12 @@ import (
"errors"
"fmt"
"github.com/alfarih31/nb-go-parser"
"reflect"
)

type Err struct {
e error
}

// HasZeroValue Check a variable has Zero Value
func hasZeroValue(v interface{}) bool {
if v == nil {
return true
}

t := reflect.TypeOf(v)
if t == nil {
return true
}

switch t.Kind() {
case reflect.Map, reflect.Slice, reflect.Array:
return false
}

return v == reflect.Zero(t).Interface()
}

func (e *Err) Errorf(f string, s ...interface{}) *Err {
return &Err{
e: errors.New(fmt.Sprintf(fmt.Sprintf("this %s: %s", e.e.Error(), f), s...)),
Expand Down
10 changes: 10 additions & 0 deletions examples/using-sql-config-server/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module example

go 1.19

require (
github.com/alfarih31/nb-go-env v1.0.4 // indirect
github.com/alfarih31/nb-go-parser v1.0.11 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/lib/pq v1.10.9 // indirect
)
8 changes: 8 additions & 0 deletions examples/using-sql-config-server/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/alfarih31/nb-go-env v1.0.4 h1:jIrQUsunn9uUMecqHQaK1lMJ3XgEqa420HQSJkUkTlg=
github.com/alfarih31/nb-go-env v1.0.4/go.mod h1:oPDLWPYpw2X/NVLoJfhr5KzZ3Wy+UPxKktOBIk7TL5s=
github.com/alfarih31/nb-go-parser v1.0.11 h1:jW+pU/UH1pBwP/HSavsGhsVmIzEDS6cvmLiAAheKaao=
github.com/alfarih31/nb-go-parser v1.0.11/go.mod h1:0+2qf5oT5sEy4qyNxY/ewsREpHtUYfis3/bERolDFGI=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
51 changes: 51 additions & 0 deletions examples/using-sql-config-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"database/sql"
"fmt"
env2 "github.com/alfarih31/nb-go-env"
sql_config_server "github.com/alfarih31/nb-go-env/sql-config-server"
_ "github.com/lib/pq"
)

const (
host = "localhost"
port = 5432
user = "postgres"
password = "postgres"
dbname = "postgres"
namespace = "example"
)

func CheckError(err error) {
if err != nil {
panic(err)
}
}

func main() {
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)

// open database
db, err := sql.Open("postgres", psqlconn)
CheckError(err)

// create config server
configService, err := sql_config_server.NewSqlConfigServer(db, "configs",
sql_config_server.WithNamespace(namespace),
sql_config_server.WithTableCreation(sql_config_server.DialectPostgres))

CheckError(err)

// seed the database
insertStmt := fmt.Sprintf(`insert into "configs"("key", "value", "namespace") values('foo', 'ba2', '%s')`, namespace)
_, e := db.Exec(insertStmt)
CheckError(e)

env, err := env2.LoadWithConfigServer(configService)
CheckError(err)

fmt.Printf("Config with key 'foo' -> '%s'\n", env.MustGetString("foo"))

db.Close()
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (

require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
6 changes: 6 additions & 0 deletions go.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go 1.19

use (
examples/using-sql-config-server
.
)
22 changes: 22 additions & 0 deletions internal/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package internal

import "reflect"

// HasZeroValue Check a variable has Zero Value
func HasZeroValue(v interface{}) bool {
if v == nil {
return true
}

t := reflect.TypeOf(v)
if t == nil {
return true
}

switch t.Kind() {
case reflect.Map, reflect.Slice, reflect.Array:
return false
}

return v == reflect.Zero(t).Interface()
}
9 changes: 9 additions & 0 deletions sql-config-server/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package sql_config_server

type Dialect uint

const (
DialectPostgres Dialect = iota
DialectMysql
DialectSqlite
)
15 changes: 15 additions & 0 deletions sql-config-server/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sql_config_server

type Option func(*sqlConfigServer)

func WithTableCreation(dialect Dialect) Option {
return func(server *sqlConfigServer) {
server.dialect = &dialect
}
}

func WithNamespace(ns string) Option {
return func(server *sqlConfigServer) {
server.namespace = &ns
}
}
140 changes: 140 additions & 0 deletions sql-config-server/sql_config_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package sql_config_server

import (
"database/sql"
"encoding/json"
"errors"
"fmt"
env "github.com/alfarih31/nb-go-env"
"github.com/alfarih31/nb-go-env/internal"
"log"
)

type sqlConfigServer struct {
tableName string
namespace *string
db *sql.DB
dialect *Dialect
}

type SqlConfigServer interface {
env.ConfigServer
}

func (s *sqlConfigServer) Get(key string) (string, bool) {
var r *sql.Row
if s.namespace != nil {
r = s.db.QueryRow(fmt.Sprintf(`SELECT value FROM "%s" WHERE key = '%s' AND namespace = '%s' ORDER BY id DESC LIMIT 1`, s.tableName, key, *s.namespace))
} else {
r = s.db.QueryRow(fmt.Sprintf(`SELECT value FROM "%s" WHERE key = '%s' ORDER BY id DESC LIMIT 1`, s.tableName, key))
}

var v string
if err := r.Scan(&v); err != nil {
log.Println(err)
return "", false
}

return v, !internal.HasZeroValue(v)
}

func (s *sqlConfigServer) Dump() (string, error) {
var (
rs *sql.Rows
err error
)
if s.namespace != nil {
rs, err = s.db.Query(fmt.Sprintf(`SELECT key, value FROM "%s" WHERE namespace = '%s' ORDER BY id DESC`, s.tableName, *s.namespace))
} else {
rs, err = s.db.Query(fmt.Sprintf(`SELECT key, value FROM "%s" ORDER BY id DESC`, s.tableName))
}

if err != nil {
return "", err
}

configs := map[string]string{}
for rs.Next() {
var k, v string
if err = rs.Scan(&k, &v); err != nil {
return "", err
}
configs[k] = v
}

if err = rs.Close(); err != nil {
return "", err
}

j, e := json.Marshal(configs)

return string(j), e
}

func (s *sqlConfigServer) executeTableCreation() error {
if s.dialect != nil {
var createStmt string
switch *s.dialect {
case DialectPostgres:
createStmt = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS "%s" (
id SERIAL PRIMARY KEY,
namespace CHARACTER VARYING(511),
key VARCHAR(511) NOT NULL,
value TEXT NOT NULL
);`, s.tableName)
case DialectMysql:
createStmt = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS "%s" (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
namespace VARCHAR(511),
key VARCHAR(511) NOT NULL,
value TEXT NOT NULL
);`, s.tableName)
case DialectSqlite:
createStmt = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS "%s" (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
namespace VARCHAR(511),
key VARCHAR(511) NOT NULL,
value TEXT NOT NULL
);`, s.tableName)
default:
return errors.New("unknown dialect")
}

_, err := s.db.Exec(createStmt)
if err != nil {
return err
}

return nil
}

return nil
}

func (s *sqlConfigServer) init() error {
if err := s.executeTableCreation(); err != nil {
return err
}

return nil
}

func NewSqlConfigServer(db *sql.DB, tableName string, opts ...Option) (SqlConfigServer, error) {
cs := &sqlConfigServer{
db: db,
tableName: tableName,
}

for _, opt := range opts {
opt(cs)
}

if err := cs.init(); err != nil {
return nil, err
}

return cs, nil
}

0 comments on commit ce09762

Please sign in to comment.