-
Notifications
You must be signed in to change notification settings - Fork 0
/
gsqlitehandler.go
141 lines (124 loc) · 3.64 KB
/
gsqlitehandler.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
// Written 2016 by Marcin 'Zbroju' Zbroinski.
// Use of this source code is governed by a GNU General Public License
// that can be found in the LICENSE file.
// Version 2.0.0
package gsqlitehandler
import (
"database/sql"
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3"
"os"
)
// Error messages
const (
errFileNotExists = "file does not exist"
errFileAlreadyExists = "file already exists"
errFileCannotBeCreated = "file cannot be created"
errFileCannotBeOpen = "file cannot be open"
errFileNotAppDB = "given file is not a valid file"
)
// SqliteDB struct is the basic wrapper type for sqlite object.
type SqliteDB struct {
Path string
Properties map[string]string
Handler *sql.DB
}
// New returns new SqliteDB object with Path and properties initialized.
func New(dbPath string, properties map[string]string) *SqliteDB {
tmpDB := new(SqliteDB)
tmpDB.Path = dbPath
tmpDB.Properties = properties
return tmpDB
}
// CreateNew creates tables from the given SQL code (sqlCreateTablesStmt) and PROPERTIES table.
// PROPERTIES table is populated with SqliteDB Properties key-value pair(s).
func (d *SqliteDB) CreateNew(sqlCreateTablesStmt string) error {
// Check if file exist and if so - return error
if _, err := os.Stat(d.Path); !os.IsNotExist(err) {
return errors.New(errFileAlreadyExists)
}
// Open file
var fileErr error
if d.Handler, fileErr = sql.Open("sqlite3", d.Path);fileErr != nil {
return errors.New(errFileCannotBeCreated)
}
defer d.Handler.Close()
// Create tables
sqlStmt := fmt.Sprintf("BEGIN TRANSACTION;CREATE TABLE properties (key TEXT, value TEXT);%sCOMMIT;", sqlCreateTablesStmt)
if _, err := d.Handler.Exec(sqlStmt);err != nil {
os.Remove(d.Path)
return errors.New(errFileCannotBeCreated)
}
// Insert properties values
tx, err := d.Handler.Begin()
if err != nil {
os.Remove(d.Path)
return errors.New(errFileCannotBeCreated)
}
stmt, err := tx.Prepare("INSERT INTO properties VALUES (?,?);")
if err != nil {
os.Remove(d.Path)
return errors.New(errFileCannotBeCreated)
}
defer stmt.Close()
for key, value := range d.Properties {
_, err := stmt.Exec(key, value)
if err != nil {
tx.Rollback()
os.Remove(d.Path)
return errors.New(errFileCannotBeCreated)
}
}
tx.Commit()
// Return nil for error
return nil
}
// Open tries to open the SqliteDB for given Path and checks if the database has the same tags (PROPERTIES) as
// current SqliteDB Properties. If so, returns true. Otherwise it returns false.
func (d *SqliteDB) Open() error {
var fileErr error
// Test if a file exist
if _, err := os.Stat(d.Path); os.IsNotExist(err) {
return errors.New(errFileNotExists)
}
if d.Handler, fileErr = sql.Open("sqlite3", d.Path);fileErr != nil {
return errors.New(errFileCannotBeOpen)
}
if d.isCorrectDB() == false {
return errors.New(errFileNotAppDB)
} else {
return nil
}
}
// Close zeroes Path and Properties and eventually closes Handler.
func (d *SqliteDB) Close() {
d.Path = ""
d.Properties = make(map[string]string)
d.Handler.Close()
}
// isCorrectDB compares tags from table PROPERTIES with the SqliteDB Properties.
// Returns true if the tags in table PROPERTIES are equal to Sqlite Properties, or false otherwise.
func (d *SqliteDB) isCorrectDB() bool {
rows, err := d.Handler.Query("SELECT KEY, VALUE FROM PROPERTIES;")
if err != nil {
return false
}
defer rows.Close()
var tagCounter int
for rows.Next() {
var key, value string
err = rows.Scan(&key, &value)
if err != nil {
return false
}
if d.Properties[key] != "" && d.Properties[key] != value {
return false
}
tagCounter++
}
if len(d.Properties) != tagCounter {
return false
}
return true
}