-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata.go
144 lines (112 loc) · 2.47 KB
/
data.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package database
import (
"fmt"
"sync"
"log"
"strings"
"database/sql"
)
type Keyer interface {
Key() string
Company() string
}
type Scannable interface {
Scan(...interface{}) error
}
type LoaderFunc func(s Scannable) (Keyer, error)
type Base struct {
single LoaderFunc
table string
columns []string
keyName string
immutable bool
editable bool
lm sync.Map
cns string
db *sql.DB
}
func New(db *sql.DB, table string, columns []string, keyname string, single LoaderFunc, isImmutable, canBeEdited bool) *Base {
return &Base{
single,
table,
columns,
keyname,
isImmutable,
canBeEdited,
sync.Map{},
"`" + strings.Join(columns, "`, `") + "`",
db,
}
}
func (b *Base) FromKey(id interface{}) (Keyer, error) {
if v, ok := b.lm.Load(id); ok {
return v.(Keyer), nil
}
v, err := b.single(b.db.QueryRow(fmt.Sprintf("SELECT %v FROM %v WHERE %v = ?", b.cns, b.table, b.keyName), id))
if err == nil {
b.lm.Store(id, v)
}
return v, err
}
func (b *Base) FromKeys(ids ...interface{}) (map[string]Keyer, error) {
firstIt := true
var oe error
m := make(map[string]Keyer)
sqlIds := make([]interface{}, len(ids))
doWork:
a := 0
for _, id := range ids {
if v, ok := b.lm.Load(id); ok {
kb := v.(Keyer)
m[kb.Key()] = kb
} else {
sqlIds[a] = id
a++
}
}
// When we to add stuff, reslice and retrieve from database
if a > 0 && firstIt {
firstIt = false
sqlIds = sqlIds[:a]
q := fmt.Sprintf("SELECT %v FROM %v WHERE %v in (?%v)", b.cns, b.table, b.keyName, strings.Repeat(", ?", a-1))
oe = b.FromQuery(q, sqlIds...)
// Load the new keys from the local versions
ids = sqlIds
goto doWork
}
return m, oe
}
func (b *Base) LoadAll() error {
return b.FromQuery(fmt.Sprintf("SELECT %v FROM %v", b.cns, b.table))
}
func (b *Base) FromQuery(q string, v ...interface{}) error {
rows, err := b.db.Query(q, v...)
if err != nil {
log.Println("Error retrieving multiple kickbacks", err)
return err
}
defer rows.Close()
var oe error
for rows.Next() {
k, e := b.single(rows)
if e != nil && oe == nil {
log.Println("Error retrieving single from database")
oe = e
}
// Store in syncmap
b.lm.Store(k.Key(), k)
}
return oe
}
func (b *Base) Iterate(a func(interface{}, interface{}) bool) {
b.lm.Range(a)
}
func (b *Base) PIterate(a func(interface{}, interface{}) bool) {
b.lm.Range(func(k, v interface{}) bool {
go a(k, v)
return true
})
}
func (b *Base) Delete(key interface{}) {
b.lm.Delete(key)
}