-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatabase.go
131 lines (108 loc) · 3.04 KB
/
database.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
package main
import (
"encoding/json"
"errors"
"io/ioutil"
"sync"
)
// ShortlinkDB is an interface for the four methods a Database as is
// implemented in this file MUST support
type ShortlinkDB interface {
Load(filename string) error
Save(filename string) error
Add(key, value string) error
Get(key string) (string, error)
}
// The Database struct bundles the variables we need to keep track of
// for the database
type Database struct {
filename string
rwmutex sync.RWMutex
entries map[string]string
}
// NewDatabase creates and returns a new instance of a ShortlinkDB.
// It initializes the fileds specified in the Database type struct.
func NewDatabase(filename string) (*Database, error) {
if filename == "" {
return nil, errors.New("Empty Filename")
}
db := &Database{}
db.filename = filename
db.entries = make(map[string]string)
return db, nil
}
// Load the contents of the database from a file. The path to this file
// is provided by the filename parameter. If this parameter is empty, we
// attempt to use the filename specified when NewDatabase() was called.
func (db *Database) Load(filename string) error {
// Fallback to stored filename, if empty filename is provided
if filename == "" {
filename = db.filename
}
// Abort if filename is still empty
if filename == "" {
return errors.New("Empty Filename")
}
db.rwmutex.Lock()
defer db.rwmutex.Unlock()
db.filename = filename
data, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
db.entries = make(map[string]string)
return json.Unmarshal(data, &db.entries)
}
// Save the database to a JSON-File. The path to this file
// is provided by the filename parameter. If this parameter is empty, we
// attempt to use the filename specified when NewDatabase() was called.
func (db *Database) Save(filename string) error {
// Fallback to stored filename, if empty filename is provided
if filename == "" {
filename = db.filename
}
// Abort if filename is still empty
if filename == "" {
return errors.New("Empty Filename")
}
db.rwmutex.RLock()
defer db.rwmutex.RUnlock()
data, err := json.Marshal(db.entries)
if err != nil {
return err
}
return ioutil.WriteFile(filename, data, 0755)
}
// Add a key-value-pair to the database.
// This does NOT automatically save to file.
func (db *Database) Add(key, value string) error {
if key == "" && value == "" {
return errors.New("Provided Key and Value are empty")
} else if key == "" {
return errors.New("Provided Key is empty")
} else if value == "" {
return errors.New("Provided Value is empty")
}
db.rwmutex.Lock()
defer db.rwmutex.Unlock()
val := db.entries[key]
if val == "" {
db.entries[key] = value
} else {
return errors.New("Key is already in use")
}
return nil
}
// Get the value that belongs to a key.
func (db *Database) Get(key string) (string, error) {
if key == "" {
return "", errors.New("Provided Key is empty")
}
db.rwmutex.RLock()
val := db.entries[key]
db.rwmutex.RUnlock()
if val == "" {
return "", errors.New("No value found for provided key")
}
return val, nil
}