/
databaseNib.go
149 lines (126 loc) · 3.73 KB
/
databaseNib.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
package tracker
import (
"errors"
"fmt"
"os"
"strings"
"github.com/jinzhu/gorm"
// Needed for sqlite gorm support.
_ "github.com/mattn/go-sqlite3"
)
// NIBLookup struct is used to represent entries in the database.
type NIBLookup struct {
ID int64
NIBID string `sql:"size:256;unique" gorm:"column:nib_id"`
Path string `sql:"size:4096;unique"`
}
// TableName returns the name of the SQLite NIB table.
func (n NIBLookup) TableName() string {
return "nib_lookups"
}
// NewDatabaseNIBTracker initializes a new object which uses a database
// to track NIB changes and implements the NIBTracker repository.
func NewDatabaseNIBTracker(dbLocation string, repositoryPath string) (NIBTracker, error) {
nibTracker := &DatabaseNIBTracker{
dbLocation: dbLocation,
repositoryPath: repositoryPath,
}
_, statErr := os.Stat(dbLocation)
db, err := gorm.Open("sqlite3", nibTracker.dbLocation)
nibTracker.db = &db
if err == nil && os.IsNotExist(statErr) {
err = nibTracker.createDb()
}
return nibTracker, err
}
// DatabaseNIBTracker implements the NIBTracker interface and utilizes
// a sqlite database backend for persistence.
type DatabaseNIBTracker struct {
dbLocation string
db *gorm.DB
repositoryPath string
}
// createDb initializes the tables in the database structure.
func (d *DatabaseNIBTracker) createDb() error {
db := d.db.CreateTable(&NIBLookup{})
return db.Error
}
// Add registers the given nibID for the given path.
func (d *DatabaseNIBTracker) Add(path string, nibID string) error {
if len(path) > MaxPathSize {
return errors.New("Path longer than maximal allowed path.")
}
tx := d.db.Begin()
res, err := d.get(path, tx)
var db *gorm.DB
if err == nil && res != nil {
res.NIBID = nibID
fmt.Println("SAVE")
db = tx.Save(res)
} else {
res = &NIBLookup{
NIBID: nibID,
Path: path,
}
db = tx.Create(res)
}
tx.Commit()
return db.Error
}
// whereFor returns a where statement for the
func (d *DatabaseNIBTracker) whereFor(path string, db *gorm.DB) *gorm.DB {
return db.Where(map[string]interface{}{"path": path})
}
// lookupToNIB converts the lookup nib to a search response.
func (d *DatabaseNIBTracker) lookupToNIB(nibLookup *NIBLookup) *NIBSearchResponse {
return &NIBSearchResponse{
NIBID: nibLookup.NIBID,
Path: nibLookup.Path,
repositoryPath: d.repositoryPath,
}
}
// get returns the database object for the given path.
func (d *DatabaseNIBTracker) get(path string, db *gorm.DB) (*NIBLookup, error) {
stmt := d.whereFor(path, db)
data := &NIBLookup{}
res := stmt.First(data)
if res.Error != nil {
return nil, res.Error
}
return data, nil
}
// Get returns the nibID for the given path.
func (d *DatabaseNIBTracker) Get(path string) (*NIBSearchResponse, error) {
data, err := d.get(path, d.db)
if err != nil {
return nil, err
}
return d.lookupToNIB(data), err
}
// SearchPrefix returns all nibIDs with the given path.
// The map being returned has the paths
func (d *DatabaseNIBTracker) SearchPrefix(prefix string) ([]*NIBSearchResponse, error) {
var resp []NIBLookup
prefix = strings.TrimSuffix(prefix, "/")
directoryPrefix := prefix + "/"
db := d.db.Where("path LIKE ? or path = ?", directoryPrefix+"%", prefix).Find(&resp)
searchResponse := []*NIBSearchResponse{}
for _, item := range resp {
searchResponse = append(searchResponse, d.lookupToNIB(&item))
}
return searchResponse, db.Error
}
// Remove removes the given path from being tracked.
func (d *DatabaseNIBTracker) Remove(path string) error {
tx := d.db.Begin()
db := d.whereFor(path, tx).Delete(NIBLookup{})
if db.Error != nil {
tx.Rollback()
} else if db.Error == nil && db.RowsAffected < 1 {
tx.Rollback()
return errors.New("Entry not found")
} else {
tx.Commit()
}
return db.Error
}