-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcache-db.js
More file actions
227 lines (201 loc) · 5.57 KB
/
Copy pathcache-db.js
File metadata and controls
227 lines (201 loc) · 5.57 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/**
*
* CACHE_DB
*
* A JSON database with easy multi-level setting, and timed writes
* This is useful for:
* - large files.
* - files that are rapidly written to in succession.
* - ability to quickly close and open a new database file.
*
* All data is cached until the writing stage is triggered.
*
* ## To initiate
* ==============
* let cachedb = require("./cachedb");
* let db = new cachedb();
* db.load("test"); // loads test.js, returns db object for chaining.
*
* ## To set change default write interval
* db.setTimer(60000); // will write now, then once again in 60000 milliseconds, returns db object for chaining
*
* ## To set data
* ==============
* db.set(["love", "is", "awesome"], true); // {"love":{"is":{"awesome":true}}}
* // This always returns the db object for chaining
*
* ## To get data
* ==============
* db.get(["love", "is", "awesome", "not"], false); // false
*
* ## To delete something in the cache
* ===================================
* db.delete(["love", "is", "awesome", "not"]); // returns db object for chaining
*
* ## To check if a key exists
* ===========================
* db.has(["love", "is", "awesome", "not"]); // checks if the destination exists, returns a falsy value
*
* ## To close a database
* db.close(); // writes to file clears timers, clears cache and closes the database
*
* ## To DELETE a database
* db.drop(); // same as close, except if you have a database loaded, this will delete the file
*
* This module can be used just as a easy set JSON object as well. Simply dont set a destination
* for the database to write to.
*
*/
'use strict';
const fs = require('graceful-fs');
function isObject(value) {
const type = typeof value;
return value != null && type === 'object' && !Array.isArray(value);
}
class CacheDB {
constructor() {
this.interval = 30000; // default at 30 seconds
this.dir = null;
this.cache = {};
this.changes = false;
this.writeInterval = setInterval(() => this.write(), this.interval);
}
load(dir) {
if (this.dir) this.close();
dir = dir + ".json";
if (!fs.existsSync(dir)) fs.writeFileSync(dir, "{}");
try {
this.cache = JSON.parse(fs.readFileSync(dir));
} catch (e) {
console.log("ERROR LOADING DATABASE: " + dir + "\n\n" + e.stack);
return this;
}
this.dir = dir;
this.temp = dir.replace(/\.json$/i, "_.json");
return this;
}
setTimer(value) {
if (value === this.interval) return this;
this.write();
this.interval = value;
clearInterval(this.writeInterval);
if (value === false) return this;
// restart timer
this.writeInterval = setInterval(() => this.write(), this.interval);
return this;
}
write() {
if (this.writeQueued) return false;
if (this.dir && this.changes) {
// dont try to write if it's already writing... queue up another write for later.
if (this.writing) {
this.writeQueued = true;
return;
}
// set writing to true.
this.writing = true;
// write in the temporary directory first
fs.writeFile(this.temp, JSON.stringify(this.cache), err => {
if (err) {
return console.log("ERROR WRITING TO FILE: " + err);
}
// if success, rename the file.
fs.rename(this.temp, this.dir, err => {
if (err) {
return console.log("ERROR RENAMING FILE: " + err);
}
this.writing = false;
if (this.writeQueued) {
this.writeQueued = false;
this.write();
} else {
this.changes = false;
}
});
});
}
}
getCache(path) {
// will always return err{} if path not found
if (typeof path === "string") path = [path]; // stick it into an array
let stage = this.cache;
let repeats = path.length;
for (let i = 0; i < repeats; i++) {
let p = path[i];
if (!stage[p]) return null;
if (i === repeats - 1) {
// special treatment - return the value
return stage[p];
}
stage = stage[p];
}
}
get(path, defaultValue) {
if (!path) return null;
if (typeof path === "string") path = [path]; // stick it into an array
let cache = this.getCache(path);
return cache || defaultValue;
}
search(path, defaultValue) {
return new Promise((resolve, reject) => {
let result = this.get(path, defaultValue);
resolve(result);
});
}
set(path, value) {
if (!path) return this;
if (typeof path === "string") path = [path]; // stick it into an array
// navigate to the right level of the object and save value in the cache
let stage = this.cache;
let repeats = path.length;
for (let i = 0; i < repeats; i++) {
let p = path[i];
if (i === repeats - 1) {
// special treatment - set the value
stage[p] = value;
this.changes = true;
return this;
}
if (!isObject(stage[p]) || !stage[p]) stage[p] = {};
stage = stage[p];
}
return this;
}
has(path) {
if (typeof path === "string") path = [path]; // stick it into an array
return this.getCache(path) !== null;
}
delete(path) {
// will always return null if path not found
if (typeof path === "string") path = [path]; // stick it into an array
let stage = this.cache;
let repeats = path.length;
for (let i = 0; i < repeats; i++) {
let p = path[i];
if (i === repeats - 1) {
// special treatment - set the value
delete stage[p];
this.changes = true;
return this;
}
if (!stage[p]) return null;
stage = stage[p];
}
return this;
}
drop() {
let dir = this.dir;
// close database first
this.close();
// drop the file
if (dir) fs.unlinkSync(dir);
}
close() {
this.write();
this.cache = {};
clearInterval(this.writeInterval);
this.writeInterval = null;
this.dir = null;
}
}
module.exports = CacheDB;