-
Notifications
You must be signed in to change notification settings - Fork 0
/
sqlite.go
134 lines (116 loc) · 2.75 KB
/
sqlite.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
package sqlite
import (
"database/sql"
"fmt"
"os"
"path/filepath"
_ "github.com/mattn/go-sqlite3"
)
// TODO: blob.Storage is a completely wrong level of abstraction for this, implement this as a data.Table
func Open(path string) (*sql.DB, error) {
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0700)); err != nil {
return nil, err
}
return sql.Open("sqlite3", fmt.Sprintf("file:%s", path))
}
/*
type Storage struct {
db *sql.DB
table string
}
var _ blob.SortedStorage = (*Storage)(nil)
func NewStorage(db *sql.DB, table string) *Storage {
if _, err := db.Exec(fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (
ref TEXT PRIMARY KEY,
data_size INTEGER,
data BLOB
)
`, table)); err != nil {
panic("failed to create sqlite table: " + err.Error())
}
return &Storage{db: db, table: table}
}
func (s *Storage) Get(ctx context.Context, ref blob.Ref) blob.Blob {
return blob.ByteFunc(func() ([]byte, error) {
var buf []byte
if err := s.db.QueryRowContext(ctx, fmt.Sprintf(`
SELECT data FROM %s
WHERE ref = ?
`, s.table), ref).Scan(&buf); err != nil {
if err == sql.ErrNoRows {
return nil, os.ErrNotExist
}
return nil, err
}
return buf, nil
})
}
func (s *Storage) Set(ctx context.Context, ref blob.Ref, r io.Reader) error {
buf, err := io.ReadAll(r)
if err != nil {
return err
}
_, err = s.db.ExecContext(ctx, fmt.Sprintf(`
INSERT INTO %s (ref, data_size, data) VALUES (?, ?, ?)
ON CONFLICT(ref) DO UPDATE SET
data_size = excluded.data_size,
data = excluded.data
`, s.table), ref, len(buf), buf)
return err
}
func (s *Storage) Iter(ctx context.Context, after blob.Ref) rx.Iter[blob.RefBlob] {
return &iter{s: s, ctx: ctx, after: after.String()}
}
type iter struct {
s *Storage
ctx context.Context
after string
rows *sql.Rows
ref string
data []byte
err error
}
func (it *iter) Next() bool {
if it.rows == nil {
if it.rows, it.err = it.s.db.QueryContext(it.ctx, fmt.Sprintf(`
SELECT ref, data FROM %s WHERE ref > ?
ORDER BY ref ASC
`, it.s.table), it.after); it.err != nil {
return false
}
}
if !it.rows.Next() {
return false
}
it.err = it.rows.Scan(&it.ref, &it.data)
return it.err == nil
}
func (it iter) Value() blob.RefBlob {
return blob.RefBlob{
Ref: blob.ParseRef(it.ref),
Blob: blob.FromBytes(it.data),
}
}
func (it iter) Close() error {
var closeErr error
if it.rows != nil {
closeErr = it.rows.Close()
}
if it.err != nil {
return closeErr
}
return it.err
}
func (s *Storage) Delete(ctx context.Context, refs ...blob.Ref) error {
// TODO: optimize (use a single query)
for _, ref := range refs {
if _, err := s.db.ExecContext(ctx, fmt.Sprintf(`
DELETE FROM %s WHERE ref = ?
`, s.table), ref); err != nil {
return err
}
}
return nil
}
*/