Skip to content

Commit 79ab6fc

Browse files
committed
Refactor code
1 parent 2877590 commit 79ab6fc

File tree

4 files changed

+369
-79
lines changed

4 files changed

+369
-79
lines changed

entity/entity.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package entity
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"fmt"
7+
"reflect"
8+
"sort"
9+
"strconv"
10+
"strings"
11+
)
12+
13+
type Entity struct {
14+
Id string `yaml:"id" mapstructure:"id" json:"id,omitempty" gorm:"column:id" bson:"_id,omitempty" dynamodbav:"id,omitempty" firestore:"id,omitempty"`
15+
Name *string `yaml:"name" mapstructure:"name" json:"name,omitempty" gorm:"column:name" bson:"name,omitempty" dynamodbav:"name,omitempty" firestore:"name,omitempty"`
16+
Email *string `yaml:"email" mapstructure:"email" json:"email,omitempty" gorm:"column:email" bson:"email,omitempty" dynamodbav:"email,omitempty" firestore:"email,omitempty"`
17+
Phone *string `yaml:"phone" mapstructure:"phone" json:"phone,omitempty" gorm:"column:phone" bson:"phone,omitempty" dynamodbav:"phone,omitempty" firestore:"phone,omitempty"`
18+
Url *string `yaml:"url" mapstructure:"url" json:"url,omitempty" gorm:"column:url" bson:"url,omitempty" dynamodbav:"url,omitempty" firestore:"url,omitempty"`
19+
}
20+
21+
type EntityPort interface {
22+
Load(ctx context.Context, id string) (*Entity, error)
23+
Query(ctx context.Context, ids []string) ([]Entity, error)
24+
}
25+
26+
type EntityAdapter struct {
27+
db *sql.DB
28+
Select string
29+
BuildParam func(int) string
30+
}
31+
32+
func NewEntityAdapter(db *sql.DB, query string, opts ...func(i int) string) *EntityAdapter {
33+
var buildParam func(i int) string
34+
if len(opts) > 0 && opts[0] != nil {
35+
buildParam = opts[0]
36+
} else {
37+
buildParam = getBuild(db)
38+
}
39+
return &EntityAdapter{
40+
db: db,
41+
Select: query,
42+
BuildParam: buildParam,
43+
}
44+
}
45+
46+
func (r *EntityAdapter) Load(ctx context.Context, id string) (*Entity, error) {
47+
p := make([]string, 0)
48+
p = append(p, id)
49+
users, err := r.Query(ctx, p)
50+
if err != nil {
51+
return nil, err
52+
}
53+
if len(users) > 0 {
54+
return &users[0], nil
55+
}
56+
return nil, nil
57+
}
58+
59+
func (r *EntityAdapter) Query(ctx context.Context, ids []string) ([]Entity, error) {
60+
var users []Entity
61+
if len(ids) == 0 {
62+
return users, nil
63+
}
64+
le := len(ids)
65+
p := make([]interface{}, 0)
66+
for _, str := range ids {
67+
p = append(p, str)
68+
}
69+
var arrValue []string
70+
for i := 1; i <= le; i++ {
71+
param := r.BuildParam(i)
72+
arrValue = append(arrValue, param)
73+
}
74+
query := r.Select + fmt.Sprintf(" in (%s)", strings.Join(arrValue, ","))
75+
rows, err := r.db.QueryContext(ctx, query, p...)
76+
defer rows.Close()
77+
78+
for rows.Next() {
79+
var row Entity
80+
if err := rows.Scan(&row.Id, &row.Name, &row.Email, &row.Phone, &row.Url); err != nil {
81+
return users, err
82+
}
83+
users = append(users, row)
84+
}
85+
if err = rows.Err(); err != nil {
86+
return users, err
87+
}
88+
SortById(users)
89+
return users, nil
90+
}
91+
92+
func ToMap(rows []Entity) map[string]*Entity {
93+
rs := make(map[string]*Entity, 0)
94+
for _, row := range rows {
95+
rs[row.Id] = &row
96+
}
97+
return rs
98+
}
99+
100+
func Unique(s []string) []string {
101+
inResult := make(map[string]bool)
102+
var result []string
103+
for _, str := range s {
104+
if _, ok := inResult[str]; !ok {
105+
inResult[str] = true
106+
result = append(result, str)
107+
}
108+
}
109+
return result
110+
}
111+
func SortById(entities []Entity) {
112+
sort.Slice(entities, func(i, j int) bool { return entities[i].Id < entities[j].Id })
113+
}
114+
func BinarySearch(id string, a []Entity) (result int, searchCount int) {
115+
mid := len(a) / 2
116+
x := strings.Compare(a[mid].Id, id)
117+
switch {
118+
case len(a) == 0:
119+
result = -1 // not found
120+
case x > 0:
121+
result, searchCount = BinarySearch(id, a[:mid])
122+
case x < 0:
123+
result, searchCount = BinarySearch(id, a[mid+1:])
124+
if result >= 0 { // if anything but the -1 "not found" result
125+
result += mid + 1
126+
}
127+
default: // a[mid] == id
128+
result = mid // found
129+
}
130+
searchCount++
131+
return
132+
}
133+
func getBuild(db *sql.DB) func(i int) string {
134+
driver := reflect.TypeOf(db.Driver()).String()
135+
switch driver {
136+
case "*pq.Driver":
137+
return buildDollarParam
138+
case "*godror.drv":
139+
return buildOracleParam
140+
case "*mssql.Driver":
141+
return buildMsSqlParam
142+
default:
143+
return buildParam
144+
}
145+
}
146+
func buildParam(i int) string {
147+
return "?"
148+
}
149+
func buildOracleParam(i int) string {
150+
return ":" + strconv.Itoa(i)
151+
}
152+
func buildMsSqlParam(i int) string {
153+
return "@p" + strconv.Itoa(i)
154+
}
155+
func buildDollarParam(i int) string {
156+
return "$" + strconv.Itoa(i)
157+
}

sql_util.go

Lines changed: 8 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ func QueryMap(ctx context.Context, db *sql.DB, transform func(s string) string,
124124
}
125125
return res, nil
126126
}
127-
func Query(ctx context.Context, db *sql.DB, fieldsIndex map[string]int, results interface{}, sql string, values ...interface{}) error {
127+
func Query(ctx context.Context, db Executor, fieldsIndex map[string]int, results interface{}, sql string, values ...interface{}) error {
128128
return QueryWithArray(ctx, db, fieldsIndex, results, nil, sql, values...)
129129
}
130-
func ExecContext(ctx context.Context, db *sql.DB, query string, args ...interface{}) (sql.Result, error){
130+
func ExecContext(ctx context.Context, db Executor, query string, args ...interface{}) (sql.Result, error){
131131
tx := GetTx(ctx)
132132
if tx != nil {
133133
return tx.ExecContext(ctx, query, args...)
@@ -204,7 +204,7 @@ func QueryContextWithArray(ctx context.Context, db *sql.DB, fieldsIndex map[stri
204204
}
205205
return nil
206206
}
207-
func QueryWithArray(ctx context.Context, db *sql.DB, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
207+
func QueryWithArray(ctx context.Context, db Executor, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
208208
driver.Valuer
209209
sql.Scanner
210210
}, sql string, values ...interface{}) error {
@@ -231,10 +231,10 @@ func QueryWithArray(ctx context.Context, db *sql.DB, fieldsIndex map[string]int,
231231
}
232232
return nil
233233
}
234-
func QueryWithMap(ctx context.Context, db *sql.DB, results interface{}, sql string, values []interface{}, options...map[string]int) error {
234+
func QueryWithMap(ctx context.Context, db Executor, results interface{}, sql string, values []interface{}, options...map[string]int) error {
235235
return QueryWithMapAndArray(ctx, db, results, nil, sql, values, options...)
236236
}
237-
func QueryWithMapAndArray(ctx context.Context, db *sql.DB, results interface{}, toArray func(interface{}) interface {
237+
func QueryWithMapAndArray(ctx context.Context, db Executor, results interface{}, toArray func(interface{}) interface {
238238
driver.Valuer
239239
sql.Scanner
240240
}, sql string, values []interface{}, options...map[string]int) error {
@@ -244,75 +244,16 @@ func QueryWithMapAndArray(ctx context.Context, db *sql.DB, results interface{},
244244
}
245245
return QueryWithArray(ctx, db, fieldsIndex, results, toArray, sql, values...)
246246
}
247-
func Select(ctx context.Context, db *sql.DB, results interface{}, sql string, values ...interface{}) error {
247+
func Select(ctx context.Context, db Executor, results interface{}, sql string, values ...interface{}) error {
248248
return SelectWithArray(ctx, db, results, nil, sql, values...)
249249
}
250-
func SelectWithArray(ctx context.Context, db *sql.DB, results interface{}, toArray func(interface{}) interface {
250+
func SelectWithArray(ctx context.Context, db Executor, results interface{}, toArray func(interface{}) interface {
251251
driver.Valuer
252252
sql.Scanner
253253
}, sql string, values ...interface{}) error {
254254
return QueryWithArray(ctx, db, nil, results, toArray, sql, values...)
255255
}
256-
func QueryTx(ctx context.Context, tx *sql.Tx, fieldsIndex map[string]int, results interface{}, sql string, values ...interface{}) error {
257-
return QueryTxWithArray(ctx, tx, fieldsIndex, results, nil, sql, values...)
258-
}
259-
func QueryTxWithArray(ctx context.Context, tx *sql.Tx, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
260-
driver.Valuer
261-
sql.Scanner
262-
}, sql string, values ...interface{}) error {
263-
rows, er1 := tx.QueryContext(ctx, sql, values...)
264-
if er1 != nil {
265-
return er1
266-
}
267-
defer rows.Close()
268-
269-
modelType := reflect.TypeOf(results).Elem().Elem()
270-
tb, er3 := Scan(rows, modelType, fieldsIndex, toArray)
271-
if er3 != nil {
272-
return er3
273-
}
274-
for _, element := range tb {
275-
appendToArray(results, element)
276-
}
277-
er4 := rows.Close()
278-
if er4 != nil {
279-
return er4
280-
}
281-
// Rows.Err will report the last error encountered by Rows.Scan.
282-
if er5 := rows.Err(); er5 != nil {
283-
return er5
284-
}
285-
return nil
286-
}
287-
func QueryByStatement(ctx context.Context, stm *sql.Stmt, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
288-
driver.Valuer
289-
sql.Scanner
290-
}, values ...interface{}) error {
291-
rows, er1 := stm.QueryContext(ctx, values...)
292-
if er1 != nil {
293-
return er1
294-
}
295-
defer rows.Close()
296-
297-
modelType := reflect.TypeOf(results).Elem().Elem()
298-
tb, er3 := Scan(rows, modelType, fieldsIndex, toArray)
299-
if er3 != nil {
300-
return er3
301-
}
302-
for _, element := range tb {
303-
appendToArray(results, element)
304-
}
305-
er4 := rows.Close()
306-
if er4 != nil {
307-
return er4
308-
}
309-
// Rows.Err will report the last error encountered by Rows.Scan.
310-
if er5 := rows.Err(); er5 != nil {
311-
return er5
312-
}
313-
return nil
314-
}
315-
func QueryAndCount(ctx context.Context, db *sql.DB, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
256+
func QueryAndCount(ctx context.Context, db Executor, fieldsIndex map[string]int, results interface{}, toArray func(interface{}) interface {
316257
driver.Valuer
317258
sql.Scanner
318259
}, count *int64, sql string, values ...interface{}) error {

url/url.go

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"database/sql"
66
"fmt"
77
"reflect"
8+
"sort"
89
"strconv"
910
"strings"
1011
)
@@ -15,16 +16,18 @@ type URL struct {
1516
Url *string `yaml:"url" mapstructure:"url" json:"url,omitempty" gorm:"column:url" bson:"url,omitempty" dynamodbav:"url,omitempty" firestore:"url,omitempty"`
1617
}
1718

19+
type URLPort interface {
20+
Load(ctx context.Context, id string) (*URL, error)
21+
Query(ctx context.Context, ids []string) ([]URL, error)
22+
}
23+
1824
type URLAdapter struct {
1925
db *sql.DB
20-
Table string
21-
Id string
22-
Name string
23-
Url string
26+
Select string
2427
BuildParam func(int) string
2528
}
2629

27-
func NewURLAdapter(db *sql.DB, table string, id string, text string, url string, opts ...func(i int) string) (*URLAdapter, error) {
30+
func NewURLAdapter(db *sql.DB, query string, opts ...func(i int) string) (*URLAdapter, error) {
2831
var buildParam func(i int) string
2932
if len(opts) > 0 && opts[0] != nil {
3033
buildParam = opts[0]
@@ -33,15 +36,25 @@ func NewURLAdapter(db *sql.DB, table string, id string, text string, url string,
3336
}
3437
return &URLAdapter{
3538
db: db,
36-
Table: table,
37-
Id: id,
38-
Name: text,
39-
Url: url,
39+
Select: query,
4040
BuildParam: buildParam,
4141
}, nil
4242
}
4343

44-
func (r *URLAdapter) Load(ctx context.Context, ids []string) ([]URL, error) {
44+
func (r *URLAdapter) Load(ctx context.Context, id string) (*URL, error) {
45+
p := make([]string, 0)
46+
p = append(p, id)
47+
values, err := r.Query(ctx, p)
48+
if err != nil {
49+
return nil, err
50+
}
51+
if len(values) > 0 {
52+
return &values[0], nil
53+
}
54+
return nil, nil
55+
}
56+
57+
func (r *URLAdapter) Query(ctx context.Context, ids []string) ([]URL, error) {
4558
var values []URL
4659
if len(ids) == 0 {
4760
return values, nil
@@ -56,7 +69,7 @@ func (r *URLAdapter) Load(ctx context.Context, ids []string) ([]URL, error) {
5669
param := r.BuildParam(i)
5770
arrValue = append(arrValue, param)
5871
}
59-
query := fmt.Sprintf("select %s, %s, %s from %s where %s in (%s)", r.Id, r.Name, r.Url, r.Table, r.Id, strings.Join(arrValue, ","))
72+
query := r.Select + fmt.Sprintf(" in (%s)", strings.Join(arrValue, ","))
6073
rows, err := r.db.QueryContext(ctx, query, p...)
6174
defer rows.Close()
6275

@@ -70,6 +83,7 @@ func (r *URLAdapter) Load(ctx context.Context, ids []string) ([]URL, error) {
7083
if err = rows.Err(); err != nil {
7184
return values, err
7285
}
86+
SortById(values)
7387
return values, nil
7488
}
7589

@@ -92,7 +106,28 @@ func Unique(s []string) []string {
92106
}
93107
return result
94108
}
95-
109+
func SortById(urls []URL) {
110+
sort.Slice(urls, func(i, j int) bool { return urls[i].Id < urls[j].Id })
111+
}
112+
func BinarySearch(id string, a []URL) (result int, searchCount int) {
113+
mid := len(a) / 2
114+
x := strings.Compare(a[mid].Id, id)
115+
switch {
116+
case len(a) == 0:
117+
result = -1 // not found
118+
case x > 0:
119+
result, searchCount = BinarySearch(id, a[:mid])
120+
case x < 0:
121+
result, searchCount = BinarySearch(id, a[mid+1:])
122+
if result >= 0 { // if anything but the -1 "not found" result
123+
result += mid + 1
124+
}
125+
default: // a[mid] == id
126+
result = mid // found
127+
}
128+
searchCount++
129+
return
130+
}
96131
func getBuild(db *sql.DB) func(i int) string {
97132
driver := reflect.TypeOf(db.Driver()).String()
98133
switch driver {

0 commit comments

Comments
 (0)