-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstorage_engine.go
131 lines (112 loc) · 3.16 KB
/
storage_engine.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
package main
import (
"database/sql"
"errors"
"fmt"
"log"
"strings"
// needed for SQLite driver
_ "github.com/mattn/go-sqlite3"
)
const createStatement string = `
CREATE TABLE IF NOT EXISTS %v (
key TEXT NOT NULL PRIMARY KEY,
value TEXT
);
`
const file string = "KeyValueStorage.db"
type StorageEngine interface {
Create(storageName string, key string, value string) error
Retrieve(storageName string, key string) (string, error)
Update(storageName string, key string, value string) error
Delete(storageName string, key string) error
}
type StorageEngineImpl struct {
db *sql.DB
}
func (c *StorageEngineImpl) NewStorageEngine() (*StorageEngineImpl, error) {
db, err := sql.Open("sqlite3", file)
if err != nil {
return nil, err
}
return &StorageEngineImpl{
db: db,
}, nil
}
func (c *StorageEngineImpl) Create(storageName string, key string, value string) error {
res, err := c.db.Exec(
fmt.Sprintf("INSERT INTO %v VALUES(?,?);", strings.ToUpper(storageName)), key, value)
if err != nil {
//TODO check how to recognize that table does not exist yet and if table does not exist, create it and try again
if err != nil {
log.Printf("Storage %v does not yet exist, creating...", storageName)
if _, err := c.db.Exec(fmt.Sprintf(createStatement, storageName)); err != nil {
return err
}
err = nil
res, err = c.db.Exec(
fmt.Sprintf("INSERT INTO %v VALUES(?,?);", strings.ToUpper(storageName)), key, value)
if err != nil {
return err
}
} else {
return err
}
}
if _, err = res.LastInsertId(); err != nil {
return err
}
log.Printf("Created on storage %v with key %v value %v", storageName, key, value)
return nil
}
func (c *StorageEngineImpl) Update(storageName string, key string, value string) error {
_, err := c.db.Exec(
fmt.Sprintf("UPDATE %v SET value = ? where key = ?;", storageName), value, key)
if err != nil {
return err
}
return nil
}
func (c *StorageEngineImpl) Delete(storageName string, key string) error {
_, err := c.db.Exec(
fmt.Sprintf("DELETE FROM %v where key = ?;", storageName), key)
if err != nil {
return err
}
return nil
}
var ErrIDNotFound = errors.New("Key not found")
func (c *StorageEngineImpl) Retrieve(storageName string, key string) (string, error) {
log.Printf("Getting %v", key)
// Query DB row based on ID
row := c.db.QueryRow(fmt.Sprintf("SELECT value FROM %v WHERE key=?", storageName), key)
var err error
var value *string
if err = row.Scan(&value); err == sql.ErrNoRows {
log.Printf("Id not found")
return "", ErrIDNotFound
}
return *value, err
}
//TODO use as example when implementing queries
/**func (c *StorageEngineImpl) List(offset int) ([]*api.Activity, error) {
log.Printf("Getting list from offset %d\n", offset)
// Query DB row based on ID
rows, err := c.db.Query("SELECT * FROM StorageEngineImpl WHERE ID > ? ORDER BY id DESC LIMIT 100", offset)
if err != nil {
return nil, err
}
defer rows.Close()
data := []*api.Activity{}
for rows.Next() {
i := api.Activity{}
var time time.Time
err = rows.Scan(&i.Id, &time, &i.Description)
if err != nil {
return nil, err
}
i.Time = timestamppb.New(time)
data = append(data, &i)
}
return data, nil
}**/