From f250000e1067b6791c92db2e3a12e2379fb31ea7 Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Mon, 17 May 2021 15:05:18 +0900 Subject: [PATCH 1/7] bugfix: parse flags before listening port --- cmd/contract-server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/contract-server/server.go b/cmd/contract-server/server.go index c5859cd..e1bf88f 100644 --- a/cmd/contract-server/server.go +++ b/cmd/contract-server/server.go @@ -37,9 +37,9 @@ func setFlags() { } func main() { + flag.Parse() lis, err := net.Listen("tcp", ":"+strconv.Itoa(port)) log.Info("Starting to listen port ", port) - flag.Parse() if err != nil { log.Fatal("failed to listen:", err) } From 5f9d164cc04fc49605eeaa3eddae82e0df13ec61 Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Tue, 18 May 2021 18:36:01 +0900 Subject: [PATCH 2/7] implement: postgresql package --- go.mod | 4 + go.sum | 14 ++- pkg/postgresql/accessor.go | 185 ++++++++++++++++++++++++++++++++ pkg/postgresql/accessor_test.go | 158 +++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 pkg/postgresql/accessor.go create mode 100644 pkg/postgresql/accessor_test.go diff --git a/go.mod b/go.mod index e6b3973..adbba8d 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,12 @@ module github.com/sktelecom/tks-contract go 1.16 require ( + github.com/DATA-DOG/go-sqlmock v1.5.0 + github.com/google/uuid v1.2.0 + github.com/lib/pq v1.10.2 github.com/sirupsen/logrus v1.8.1 github.com/sktelecom/tks-proto v0.0.4-0.20210419072147-cbafa000deab + github.com/stretchr/testify v1.7.0 // indirect google.golang.org/grpc v1.36.1 google.golang.org/protobuf v1.26.0 ) diff --git a/go.sum b/go.sum index c97638a..a87b1dc 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -32,19 +34,22 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/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= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sktelecom/tks-proto v0.0.4-0.20210419050352-2299e8d5d653 h1:plu5huLviWEh5uJyyVf3AZoYl8sajUtn2KfzkU2+wFs= -github.com/sktelecom/tks-proto v0.0.4-0.20210419050352-2299e8d5d653/go.mod h1:5r0c5Sq4RhX5IuVIyD/aRunO7WUHmpymBOBz9LTCaRY= github.com/sktelecom/tks-proto v0.0.4-0.20210419072147-cbafa000deab h1:Jqxkx4bq1uC6Y5BRaqo2eKE8eCdewluZ+1aTtDAk0d0= github.com/sktelecom/tks-proto v0.0.4-0.20210419072147-cbafa000deab/go.mod h1:5r0c5Sq4RhX5IuVIyD/aRunO7WUHmpymBOBz9LTCaRY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -97,7 +102,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/postgresql/accessor.go b/pkg/postgresql/accessor.go new file mode 100644 index 0000000..70e36eb --- /dev/null +++ b/pkg/postgresql/accessor.go @@ -0,0 +1,185 @@ +package postgresql + +import ( + "database/sql" + "fmt" + + "github.com/sktelecom/tks-contract/pkg/log" + + _ "github.com/lib/pq" +) + +// Accessor is an accessor for PostgresqlDB. +type Accessor struct { + db *sql.DB +} + +// New returns a new Postgresql. +func New(db *sql.DB) *Accessor { + return &Accessor{ + db: db, + } +} + +// Close closes database session. +func (p *Accessor) Close() error { + p.db.Close() + return nil +} + +// Get returns result of querying from DB. +// Support both non-transactional and transactional queries. +func (p *Accessor) Get(tx *sql.Tx, fields, table string, conditions map[string]interface{}) (*sql.Rows, error) { + var query string + if len(conditions) != 0 { + conditionSql := getVarSyntaxFromMaps(conditions) + query = fmt.Sprintf(`SELECT %s FROM %s WHERE %s`, fields, table, conditionSql[0]) + } else { + query = fmt.Sprintf(`SELECT %s FROM %s`, fields, table) + } + + if tx == nil { + return p.db.Query(query) + } + + rows, err := tx.Query(query) + if err != nil { + tx.Rollback() + return nil, err + } + return rows, nil +} + +// Insert inserts new column into table. +func (p *Accessor) Insert(tx *sql.Tx, table string, values ...interface{}) (int64, error) { + query := fmt.Sprintf(`INSERT INTO %s VALUES(%s)`, table, getVarSyntax(len(values))) + var ( + res sql.Result + err error + ) + if tx == nil { + if res, err = p.db.Exec(query, values...); err != nil { + return 0, err + } + return res.RowsAffected() + } + + if res, err = tx.Exec(query, values...); err != nil { + tx.Rollback() + return 0, err + } + return res.RowsAffected() +} + +// Delete deletes a row which meets a condition in table. +func (p *Accessor) Delete(tx *sql.Tx, table string, conditions map[string]interface{}) (int64, error) { + var ( + res sql.Result + err error + ) + conditionKeySql := getVarSyntaxFromMaps(conditions) + conditionValues := getValueSliceFromMaps(conditions) + + query := fmt.Sprintf(`DELETE FROM %s WHERE %s`, table, conditionKeySql[0]) + if tx == nil { + if res, err = p.db.Exec(query, conditionValues...); err != nil { + log.Fatal(err) + return 0, err + } + return res.RowsAffected() + } + + if res, err = tx.Exec(query, conditionValues...); err != nil { + tx.Rollback() + return 0, err + } + return res.RowsAffected() +} + +// Update updates values of specific row which meets a condition in table. +func (p *Accessor) Update(tx *sql.Tx, table string, values, conditions map[string]interface{}) (int64, error) { + var ( + res sql.Result + err error + ) + sqlArr := getVarSyntaxFromMaps(values, conditions) + args := getValueSliceFromMaps(values, conditions) + query := fmt.Sprintf(`UPDATE %s SET %s WHERE %s`, table, sqlArr[0], sqlArr[1]) + if tx == nil { + if res, err = p.db.Exec(query, args...); err != nil { + log.Fatal(err) + return 0, err + } + return res.RowsAffected() + } + if res, err = tx.Exec(query, args...); err != nil { + tx.Rollback() + return 0, err + } + return res.RowsAffected() +} + +func (p *Accessor) Query(query string, args ...interface{}) (*sql.Rows, error) { + return p.db.Query(query, args...) +} + +func (p *Accessor) BeginTx() (*sql.Tx, error) { + return p.db.Begin() +} + +func (p *Accessor) CommitTx(tx *sql.Tx) error { + return tx.Commit() +} + +// getVarSyntax makes "$1, $2, $3..." string for SQL query. +func getVarSyntax(count int) string { + var ( + result string + idx int + start bool = true + ) + for idx = 1; idx <= count; idx++ { + if !start { + result += ", " + } + result += fmt.Sprintf(`$%d`, idx) + start = false + } + return result +} + +// getValuesSliceFromMaps returns one slice gathering all values from multiple maps. +func getValueSliceFromMaps(maps ...map[string]interface{}) []interface{} { + result := make([]interface{}, 0) + for i := range maps { + for _, v := range maps[i] { + result = append(result, v) + } + } + return result +} + +// getVarSyntaxFromMaps returns multiple varSyntax "name=$1, id=$2 ..." from multiple maps. +// Index of varSyntax between multiple maps increases continously. +func getVarSyntaxFromMaps(maps ...map[string]interface{}) []string { + var ( + idx int = 1 + result []string + ) + for i := range maps { + var ( + temp string + start bool = true + ) + for k := range maps[i] { + if !start { + temp += ", " + } + temp += fmt.Sprintf("%s=$%d", k, idx) + start = false + idx++ + } + result = append(result, temp) + } + return result +} diff --git a/pkg/postgresql/accessor_test.go b/pkg/postgresql/accessor_test.go new file mode 100644 index 0000000..c602f48 --- /dev/null +++ b/pkg/postgresql/accessor_test.go @@ -0,0 +1,158 @@ +package postgresql_test + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/sktelecom/tks-contract/pkg/postgresql" +) + +func TestInsert(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection.", err) + } + defer db.Close() + accessor := postgresql.New(db) + defer accessor.Close() + + mock.ExpectExec("INSERT INTO records"). + WithArgs("gopher", "828cec77-1da5-4ba6-90d0-270d71be3c55", 50). + WillReturnResult(sqlmock.NewResult(1, 1)) + + count, err := accessor.Insert(nil, "records(name, id, score)", + "gopher", + "828cec77-1da5-4ba6-90d0-270d71be3c55", + 50) + + if err != nil { + t.Errorf("error was not expected while creating contract: %s", err) + } + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulilled expectations: %s", err) + } + t.Log("updated count: ", count) +} + +func TestInsertWithTransaction(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection.", err) + } + defer db.Close() + accessor := postgresql.New(db) + defer accessor.Close() + + mock.ExpectBegin() + mock.ExpectExec("INSERT INTO records"). + WithArgs("gopher", "828cec77-1da5-4ba6-90d0-270d71be3c55", 50). + WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + tx, err := accessor.BeginTx() + count, err := accessor.Insert(tx, "records(name, id, score)", + "gopher", + "828cec77-1da5-4ba6-90d0-270d71be3c55", + 50) + tx.Commit() + if err != nil { + t.Errorf("error was not expected while creating contract: %s", err) + } + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulilled expectations: %s", err) + } + t.Log("updated count: ", count) +} + +func TestGet(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection.", err) + } + defer db.Close() + + mockRows := sqlmock.NewRows([]string{"name", "id", "score"}). + AddRow("gopher", "828cec77-1da5-4ba6-90d0-270d71be3c55", 50) + mock.ExpectQuery("^SELECT (.+) FROM records$").WillReturnRows(mockRows) + + accessor := postgresql.New(db) + // have to call Close() + defer accessor.Close() + + rows, err := accessor.Get(nil, "*", "records", map[string]interface{}{}) + if err != nil { + t.Error(err) + } + if err = mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } + defer rows.Close() + for rows.Next() { + var ( + name, id string + score int + ) + rows.Scan(&name, &id, &score) + t.Logf("scanned row: %s %s %d", name, id, score) + } +} + +func TestUpdate(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection.", err) + } + defer db.Close() + + mock.ExpectExec("UPDATE records"). + WithArgs(70, "8192039", "gopher"). + WillReturnResult(sqlmock.NewResult(1, 1)) + accessor := postgresql.New(db) + // have to call Close() + defer accessor.Close() + updateValues := map[string]interface{}{ + "score": 70, + } + conditionValues := map[string]interface{}{ + "id": "8192039", + "name": "gopher", + } + count, err := accessor.Update(nil, "records", updateValues, conditionValues) + if err != nil { + t.Error(err) + } + if err = mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } + + t.Logf("updated count: %d", count) +} + +func TestDelete(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection.", err) + } + defer db.Close() + + mock.ExpectExec("DELETE FROM records"). + WithArgs("gopher", 31, 50). + WillReturnResult(sqlmock.NewResult(1, 1)) + accessor := postgresql.New(db) + // have to call Close() + defer accessor.Close() + condition := map[string]interface{}{ + "name": "gopher", + "age": 31, + "score": 50, + } + count, err := accessor.Delete(nil, "records", condition) + if err != nil { + t.Error(err) + } + if err = mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } + + t.Logf("updated count: %d", count) +} From 34cb3ff62c991c2ccd85d78a7340cb8f0c495b4a Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Tue, 18 May 2021 18:36:44 +0900 Subject: [PATCH 3/7] update docs and scripts for initialization DB --- README.md | 15 +++++++++++---- scripts/script.sql | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 scripts/script.sql diff --git a/README.md b/README.md index 67d4874..c7b5c40 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,27 @@ This service communicates based on gRPC. You can refer to the proto files in [tk ## Quick Start +### Development environment +* Installed docker 20.x +* Running postgresql and Initilizing database. + ``` + docker run -p 5432:5432 --name postgres -e POSTGRES_PASSWORD=password -d postgres + docker cp scripts/script.sql postgres:/script.sql + docker exec -ti postgres psql -U postgres -a -f script.sql + ``` ### For go developers ``` go install -v ./... -contract-server -port 50051 -enable-mockup +contract-server -port 9110 ``` ### For docker users ``` TAGS=$(curl --silent "https://api.github.com/repos/sktelecom/tks-contract/tags" | grep name | head -1 |cut -d '"' -f 4) docker pull docker.pkg.github.com/sktelecom/tks-contract/tks-contract:$TAGS -docker run --name tks-contract -p 50051:50051 -d \ +docker run --name tks-contract -p 9110:9110 -d \ docker.pkg.github.com/sktelecom/tks-contract/tks-contract:$TAGS \ contract-server \ - # -enable-mockup \ - # -port 50051 + # -port 9110 ``` diff --git a/scripts/script.sql b/scripts/script.sql new file mode 100644 index 0000000..875e809 --- /dev/null +++ b/scripts/script.sql @@ -0,0 +1,14 @@ +CREATE DATABASE tks; +\c tks; +CREATE TABLE contract +( + contractor_name character varying(50) COLLATE pg_catalog."default", + contract_id uuid primary key, + available_services character varying(10)[] COLLATE pg_catalog."default", + csp_id uuid, + last_updated_ts timestamp with time zone +); + +INSERT INTO contract( + contractor_name, contract_id, available_services, csp_id, last_updated_ts) + VALUES ('tester', 'edcaa975-dde4-4c4d-94f7-36bc38fe7064', ARRAY['lma'], '3390f92b-0da8-4628-83e2-e266b1928e11', '2021-05-01'::timestamp); \ No newline at end of file From 592561a511a569c35cdcd12bc2db63fbcfcb3d4e Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Thu, 20 May 2021 10:22:28 +0900 Subject: [PATCH 4/7] fix lint errors --- pkg/postgresql/accessor.go | 20 ++++++++++++++++---- pkg/postgresql/accessor_test.go | 11 +++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/pkg/postgresql/accessor.go b/pkg/postgresql/accessor.go index 70e36eb..3ec91b6 100644 --- a/pkg/postgresql/accessor.go +++ b/pkg/postgresql/accessor.go @@ -44,7 +44,10 @@ func (p *Accessor) Get(tx *sql.Tx, fields, table string, conditions map[string]i rows, err := tx.Query(query) if err != nil { - tx.Rollback() + if errRollback := tx.Rollback(); errRollback != nil { + log.Fatal("failed to rollback transaction: ", errRollback) + return nil, errRollback + } return nil, err } return rows, nil @@ -65,7 +68,10 @@ func (p *Accessor) Insert(tx *sql.Tx, table string, values ...interface{}) (int6 } if res, err = tx.Exec(query, values...); err != nil { - tx.Rollback() + if errRollback := tx.Rollback(); errRollback != nil { + log.Fatal("failed to rollback transaction: ", errRollback) + return 0, errRollback + } return 0, err } return res.RowsAffected() @@ -90,7 +96,10 @@ func (p *Accessor) Delete(tx *sql.Tx, table string, conditions map[string]interf } if res, err = tx.Exec(query, conditionValues...); err != nil { - tx.Rollback() + if errRollback := tx.Rollback(); errRollback != nil { + log.Fatal("failed to rollback transaction: ", errRollback) + return 0, errRollback + } return 0, err } return res.RowsAffected() @@ -113,7 +122,10 @@ func (p *Accessor) Update(tx *sql.Tx, table string, values, conditions map[strin return res.RowsAffected() } if res, err = tx.Exec(query, args...); err != nil { - tx.Rollback() + if errRollback := tx.Rollback(); errRollback != nil { + log.Fatal("failed to rollback transaction: ", errRollback) + return 0, errRollback + } return 0, err } return res.RowsAffected() diff --git a/pkg/postgresql/accessor_test.go b/pkg/postgresql/accessor_test.go index c602f48..53f7685 100644 --- a/pkg/postgresql/accessor_test.go +++ b/pkg/postgresql/accessor_test.go @@ -50,14 +50,19 @@ func TestInsertWithTransaction(t *testing.T) { mock.ExpectCommit() tx, err := accessor.BeginTx() + if err != nil { + t.Errorf("an error was not expected while beginning transaction %s", err) + } count, err := accessor.Insert(tx, "records(name, id, score)", "gopher", "828cec77-1da5-4ba6-90d0-270d71be3c55", 50) - tx.Commit() if err != nil { t.Errorf("error was not expected while creating contract: %s", err) } + if err = tx.Commit(); err != nil { + t.Errorf("error was not expected while committing transaction: %s", err) + } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulilled expectations: %s", err) } @@ -92,7 +97,9 @@ func TestGet(t *testing.T) { name, id string score int ) - rows.Scan(&name, &id, &score) + if err = rows.Scan(&name, &id, &score); err != nil { + t.Errorf("error was not expected while scanning rows: %s", err) + } t.Logf("scanned row: %s %s %d", name, id, score) } } From b04450eba853474eb34cb8fcb20261079c48788b Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Thu, 20 May 2021 13:16:39 +0900 Subject: [PATCH 5/7] refactor: rename contract-server directory to server --- README.md | 4 ++-- cmd/{contract-server => server}/handlers.go | 0 cmd/{contract-server => server}/handlers_test.go | 0 cmd/{contract-server/server.go => server/main.go} | 0 cmd/{contract-server => server}/mockup_contracts.go | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename cmd/{contract-server => server}/handlers.go (100%) rename cmd/{contract-server => server}/handlers_test.go (100%) rename cmd/{contract-server/server.go => server/main.go} (100%) rename cmd/{contract-server => server}/mockup_contracts.go (100%) diff --git a/README.md b/README.md index c7b5c40..d4e2579 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This service communicates based on gRPC. You can refer to the proto files in [tk ``` go install -v ./... -contract-server -port 9110 +server -port 9110 ``` ### For docker users ``` @@ -29,7 +29,7 @@ TAGS=$(curl --silent "https://api.github.com/repos/sktelecom/tks-contract/tags" docker pull docker.pkg.github.com/sktelecom/tks-contract/tks-contract:$TAGS docker run --name tks-contract -p 9110:9110 -d \ docker.pkg.github.com/sktelecom/tks-contract/tks-contract:$TAGS \ - contract-server \ + server \ # -port 9110 ``` diff --git a/cmd/contract-server/handlers.go b/cmd/server/handlers.go similarity index 100% rename from cmd/contract-server/handlers.go rename to cmd/server/handlers.go diff --git a/cmd/contract-server/handlers_test.go b/cmd/server/handlers_test.go similarity index 100% rename from cmd/contract-server/handlers_test.go rename to cmd/server/handlers_test.go diff --git a/cmd/contract-server/server.go b/cmd/server/main.go similarity index 100% rename from cmd/contract-server/server.go rename to cmd/server/main.go diff --git a/cmd/contract-server/mockup_contracts.go b/cmd/server/mockup_contracts.go similarity index 100% rename from cmd/contract-server/mockup_contracts.go rename to cmd/server/mockup_contracts.go From 632677076bfa4f95fe68d1215084615daf89f579 Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Fri, 21 May 2021 11:12:26 +0900 Subject: [PATCH 6/7] bugfix: add query args --- pkg/postgresql/accessor.go | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/pkg/postgresql/accessor.go b/pkg/postgresql/accessor.go index 3ec91b6..78e2690 100644 --- a/pkg/postgresql/accessor.go +++ b/pkg/postgresql/accessor.go @@ -30,19 +30,19 @@ func (p *Accessor) Close() error { // Get returns result of querying from DB. // Support both non-transactional and transactional queries. func (p *Accessor) Get(tx *sql.Tx, fields, table string, conditions map[string]interface{}) (*sql.Rows, error) { - var query string - if len(conditions) != 0 { - conditionSql := getVarSyntaxFromMaps(conditions) - query = fmt.Sprintf(`SELECT %s FROM %s WHERE %s`, fields, table, conditionSql[0]) - } else { - query = fmt.Sprintf(`SELECT %s FROM %s`, fields, table) + if len(conditions) == 0 { + return p.getAll(tx, fields, table) } + args := getValueSliceFromMaps(conditions) + conditionSql := getVarSyntaxFromMaps(conditions) + query := fmt.Sprintf(`SELECT %s FROM %s WHERE %s`, fields, table, conditionSql[0]) + if tx == nil { - return p.db.Query(query) + return p.db.Query(query, args) } - rows, err := tx.Query(query) + rows, err := tx.Query(query, args) if err != nil { if errRollback := tx.Rollback(); errRollback != nil { log.Fatal("failed to rollback transaction: ", errRollback) @@ -131,18 +131,38 @@ func (p *Accessor) Update(tx *sql.Tx, table string, values, conditions map[strin return res.RowsAffected() } +// Query quries rows in DB with pure SQL statement. func (p *Accessor) Query(query string, args ...interface{}) (*sql.Rows, error) { return p.db.Query(query, args...) } +// BeginTx returns a new transaction. func (p *Accessor) BeginTx() (*sql.Tx, error) { return p.db.Begin() } +// CommitTx commits a transaction. func (p *Accessor) CommitTx(tx *sql.Tx) error { return tx.Commit() } +func (p *Accessor) getAll(tx *sql.Tx, fields, table string) (*sql.Rows, error) { + query := fmt.Sprintf(`SELECT %s FROM %s`, fields, table) + + if tx == nil { + return p.db.Query(query) + } + rows, err := tx.Query(query) + if err != nil { + if errRollback := tx.Rollback(); errRollback != nil { + log.Fatal("failed to rollback transaction: ", errRollback) + return nil, errRollback + } + return nil, err + } + return rows, nil +} + // getVarSyntax makes "$1, $2, $3..." string for SQL query. func getVarSyntax(count int) string { var ( From 9d5340f06dd02f1389b23f4ca74a8d509ca757ed Mon Sep 17 00:00:00 2001 From: Esther Kim Date: Fri, 21 May 2021 11:47:50 +0900 Subject: [PATCH 7/7] refactor: unified variable's name --- pkg/postgresql/accessor.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/postgresql/accessor.go b/pkg/postgresql/accessor.go index 78e2690..b03304a 100644 --- a/pkg/postgresql/accessor.go +++ b/pkg/postgresql/accessor.go @@ -34,15 +34,15 @@ func (p *Accessor) Get(tx *sql.Tx, fields, table string, conditions map[string]i return p.getAll(tx, fields, table) } - args := getValueSliceFromMaps(conditions) - conditionSql := getVarSyntaxFromMaps(conditions) - query := fmt.Sprintf(`SELECT %s FROM %s WHERE %s`, fields, table, conditionSql[0]) + conditionValues := getValueSliceFromMaps(conditions) + conditionKeySql := getVarSyntaxFromMaps(conditions) + query := fmt.Sprintf(`SELECT %s FROM %s WHERE %s`, fields, table, conditionKeySql[0]) if tx == nil { - return p.db.Query(query, args) + return p.db.Query(query, conditionValues...) } - rows, err := tx.Query(query, args) + rows, err := tx.Query(query, conditionValues...) if err != nil { if errRollback := tx.Rollback(); errRollback != nil { log.Fatal("failed to rollback transaction: ", errRollback) @@ -111,17 +111,17 @@ func (p *Accessor) Update(tx *sql.Tx, table string, values, conditions map[strin res sql.Result err error ) - sqlArr := getVarSyntaxFromMaps(values, conditions) - args := getValueSliceFromMaps(values, conditions) - query := fmt.Sprintf(`UPDATE %s SET %s WHERE %s`, table, sqlArr[0], sqlArr[1]) + conditionKeySql := getVarSyntaxFromMaps(values, conditions) + conditionValues := getValueSliceFromMaps(values, conditions) + query := fmt.Sprintf(`UPDATE %s SET %s WHERE %s`, table, conditionKeySql[0], conditionKeySql[1]) if tx == nil { - if res, err = p.db.Exec(query, args...); err != nil { + if res, err = p.db.Exec(query, conditionValues...); err != nil { log.Fatal(err) return 0, err } return res.RowsAffected() } - if res, err = tx.Exec(query, args...); err != nil { + if res, err = tx.Exec(query, conditionValues...); err != nil { if errRollback := tx.Rollback(); errRollback != nil { log.Fatal("failed to rollback transaction: ", errRollback) return 0, errRollback