· 6 years ago · Mar 10, 2019, 09:06 PM
1package db
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7
8 "github.com/gchaincl/sqlhooks"
9 sqlite3 "github.com/mattn/go-sqlite3"
10)
11
12const (
13 SQLiteDBBackendType = "sqlitedb"
14)
15
16type dbHooks struct {
17}
18
19func (h *dbHooks) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
20 //log.Printf("before> ctx = %+v, q=%s, args = %+v\n", ctx, query, args)
21 return ctx, nil
22}
23
24func (h *dbHooks) After(ctx context.Context, query string, args ...interface{}) (context.Context, error) {
25 return ctx, nil
26}
27
28func init() {
29 sql.Register("sqlite-hook", sqlhooks.Wrap(&sqlite3.SQLiteDriver{}, &dbHooks{}))
30
31 registerDBCreator(SQLiteDBBackendType, func(name string, dir string) (DB, error) {
32 return NewSQLiteDB(name, dir)
33 }, false)
34}
35
36var _ DB = (*SQLiteDB)(nil)
37
38type SQLiteDB struct {
39 *sql.DB
40}
41
42func NewSQLiteDB(name, dir string) (*SQLiteDB, error) {
43 dsn := fmt.Sprintf("file:%s/%s.sqlite", dir, name)
44 db, err := sql.Open("sqlite-hook", dsn)
45 if err != nil {
46 return nil, err
47 }
48
49 if err := migrate(db); err != nil {
50 return nil, err
51 }
52
53 return &SQLiteDB{db}, nil
54}
55
56func migrate(db *sql.DB) error {
57 _, err := db.Exec(
58 `CREATE TABLE IF NOT EXISTS store (
59 key BLOB PRIMARY KEY NOT NULL,
60 value BLOB
61 );
62 `,
63 )
64
65 return err
66}
67
68func (db *SQLiteDB) Get(key []byte) []byte {
69 var value []byte
70
71 if err := db.QueryRow(`SELECT value FROM store WHERE key = ?`, key).Scan(&value); err != nil {
72 if err == sql.ErrNoRows {
73 return nil
74 }
75 panic(err)
76 }
77
78 if value == nil {
79 return []byte{}
80 }
81
82 return value
83}
84
85func (db *SQLiteDB) Has(key []byte) bool {
86 return db.Get(key) != nil
87}
88
89func (db *SQLiteDB) Set(key []byte, value []byte) {
90 _, err := db.Exec(`INSERT OR REPLACE INTO store (key, value) VALUES(?, ?)`, key, value)
91 if err != nil {
92 panic(err)
93 }
94}
95
96func (db *SQLiteDB) SetSync(key []byte, value []byte) {
97 db.Set(key, value)
98}
99
100func (db *SQLiteDB) Delete(key []byte) {
101 _, err := db.Exec(`DELETE FROM store WHERE key = ?`, key)
102 if err != nil {
103 panic(err)
104 }
105}
106
107func (db *SQLiteDB) DeleteSync(key []byte) {
108 db.Delete(key)
109}
110
111func (db *SQLiteDB) Iterator(start []byte, end []byte) Iterator {
112 return newSqliteIterator(db.DB, start, end, false)
113}
114
115func (db *SQLiteDB) ReverseIterator(start []byte, end []byte) Iterator {
116 return newSqliteIterator(db.DB, start, end, true)
117}
118
119func (db *SQLiteDB) Close() {
120}
121
122func (db *SQLiteDB) NewBatch() Batch {
123 panic("not implemented")
124}
125
126func (db *SQLiteDB) Print() {
127 panic("not implemented")
128}
129
130func (db *SQLiteDB) Stats() map[string]string {
131 panic("not implemented")
132}
133
134type sqliteIterator struct {
135 rows *sql.Rows
136 start []byte
137 end []byte
138
139 valid bool
140 key []byte
141 value []byte
142}
143
144func newSqliteIterator(db *sql.DB, start, end []byte, reverse bool) *sqliteIterator {
145 var query = "SELECT key, value FROM store"
146 var args []interface{}
147
148 if start != nil && end == nil {
149 query += " WHERE key >= ?"
150 args = []interface{}{start}
151 } else if start == nil && end != nil {
152 query += " WHERE key < ?"
153 args = []interface{}{end}
154 } else if start != nil && end != nil {
155 query += " WHERE key >= ? AND key < ?"
156 args = []interface{}{start, end}
157 }
158
159 if reverse {
160 query += " ORDER BY key DESC"
161 }
162
163 rows, err := db.Query(query, args...)
164 if err != nil {
165 panic(err)
166 }
167
168 itr := &sqliteIterator{
169 rows: rows,
170 start: start,
171 end: end,
172 valid: true,
173 }
174
175 itr.Next()
176
177 return itr
178}
179
180func (itr *sqliteIterator) Domain() ([]byte, []byte) {
181 return itr.start, itr.end
182}
183
184func (itr *sqliteIterator) Close() {
185 itr.rows.Close()
186}
187
188func (itr *sqliteIterator) Key() []byte {
189 if !itr.valid {
190 panic("Iterator reached invalid state")
191 }
192 return itr.key
193}
194
195func (itr *sqliteIterator) Value() []byte {
196 if !itr.valid {
197 panic("Iterator reached invalid state")
198 }
199 return itr.value
200}
201
202func (itr *sqliteIterator) Next() {
203 if !itr.valid {
204 panic("Iterator reached invalid state")
205 }
206
207 itr.valid = itr.rows.Next()
208 if itr.valid {
209 if err := itr.rows.Scan(&itr.key, &itr.value); err != nil {
210 panic(err)
211 }
212 }
213}
214
215func (itr *sqliteIterator) Valid() bool {
216 return itr.valid
217}