-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.go
155 lines (131 loc) · 3.31 KB
/
init.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
145
146
147
148
149
150
151
152
153
154
155
package sql
import (
"database/sql"
_ "embed"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
_ "github.com/mattn/go-sqlite3"
"github.com/sirupsen/logrus"
"github.com/stregato/master/woland/core"
)
//go:embed sqlite.sql
var InitDDL string
var db *sql.DB
var DbPath string
func createTables() error {
parts := strings.Split(InitDDL, "\n\n")
for line, part := range parts {
if strings.Trim(part, " ") == "" {
continue
}
if !strings.HasPrefix(part, "-- ") {
logrus.Errorf("unexpected break without a comment in '%s'", part)
}
cr := strings.Index(part, "\n")
if cr == -1 {
logrus.Error("invalid comment without CR")
return os.ErrInvalid
}
key, ql := part[3:cr], part[cr+1:]
if strings.HasPrefix(key, "INIT") {
_, err := db.Exec(ql)
if err != nil {
logrus.Errorf("cannot execute SQL Init stmt (line %d) '%s': %v", line, ql, err)
return err
}
core.Info("SQL Init stmt (line %d) '%s' executed", line, ql)
} else {
err := prepareStatement(key, ql, line)
if err != nil {
return err
}
}
}
return nil
}
// LoadSQLFromFile loads the sql queries from the provided file path. It panics in case the file cannot be loaded
func LoadSQLFromFile(name string) error {
ddl, err := os.ReadFile(name)
if core.IsErr(err, nil, "cannot load SQL queries from %s: %v", name) {
return err
}
InitDDL = string(ddl)
return nil
}
var MemoryDBPath = ":memory:"
var TempDB = filepath.Join(os.TempDir(), "woland-test.db")
func OpenDB(dbPath string) error {
if db != nil {
return nil
}
DbPath = dbPath
if DbPath != MemoryDBPath {
_, err := os.Stat(DbPath)
if errors.Is(err, os.ErrNotExist) {
err := os.WriteFile(dbPath, []byte{}, 0644)
if err != nil {
logrus.Errorf("cannot create SQLite db in %s: %v", DbPath, err)
return err
}
} else if err != nil {
logrus.Errorf("cannot access SQLite db file %s: %v", DbPath, err)
}
}
var err error
db, err = sql.Open("sqlite3", DbPath)
// db, err = sql.Open("sqlite3", DbPath+"cache=shared&mode=rwc")
if err != nil {
logrus.Errorf("cannot open SQLite db in %s: %v", DbPath, err)
return err
}
// db.SetMaxOpenConns(1)
core.Info("DB %s opened", DbPath)
return createTables()
}
func CloseDB() error {
if db == nil {
return os.ErrClosed
}
err := db.Close()
db = nil
queriesCache = map[string]string{}
stmtCache = map[string]*sql.Stmt{}
core.Info("DB %s closed", DbPath)
return err
}
func DeleteDB(dbPath string) error {
var err error
if db == nil {
db, err = sql.Open("sqlite3", dbPath)
if core.IsErr(err, nil, "cannot open SQLite db in %s: %v", dbPath) {
return err
}
}
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table'")
if core.IsErr(err, nil, "cannot list tables in SQLite db in %s: %v", dbPath) {
return err
}
defer rows.Close()
var tableName string
for rows.Next() {
err = rows.Scan(&tableName)
if core.IsErr(err, nil, "cannot scan table name in SQLite db in %s: %v", dbPath) {
continue
}
_, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName))
if core.IsErr(err, nil, "cannot drop table %s in SQLite db in %s: %v", tableName, dbPath) {
continue
}
}
CloseDB()
os.Create(dbPath)
err = os.Remove(dbPath)
if core.IsErr(err, nil, "cannot delete SQLite db in %s: %v", dbPath) {
return err
}
core.Info("DB %s deleted", dbPath)
return nil
}