-
Notifications
You must be signed in to change notification settings - Fork 0
/
nodbstore.js
261 lines (235 loc) · 6.17 KB
/
nodbstore.js
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
const now = () => (new Date()).getTime()
/**
* An interface of storage that will work with the db
*/
class Storage {
init() {}
write() {}
load() {}
}
/**
* A database that work with memory but can work with other stores
*/
class NoDBStore {
constructor() {
this.conf = {
lastId: 0
}
this.data = []
this._data = {}
this._stores = []
}
/**
* Add a storage that he will write
* @param {NoDBStore.Storage} store the storage to add
*/
addStore(store) {
if (
typeof store.init === 'function' &&
typeof store.write === 'function' &&
typeof store.load === 'function'
) {
store.nodb = this
store.init()
this._stores.push(store)
} else {
throw new Error('A store need to be extended by NoDBStore.Storage')
}
}
/**
* Get the database as a JS object
* @return {object} export of the db
*/
toObj() {
return {
conf: this.conf,
data: this.data
}
}
/**
* Get the database as a json format
* @return {string} JSON export of the db
*/
toJson() {
return JSON.stringify(this.toObj())
}
/**
* Will write in all storage
*/
write() {
const json = this.toJson()
for (let i = 0; i < this._stores.length; i++) {
this._stores[i].write(json)
}
}
/**
* Load the database from an Object
* @param {object} db object of the export of database
*/
loadObj(db) {
this.conf = db.conf
this.data = db.data
this._update_data()
}
/**
* Load the database from a JSON string
* @param {string} json json of the database
*/
loadJson(json) {
this.loadObj(JSON.parse(json))
}
/**
* Load the db from a store
* @param {NoDBStore.Storage} store the store that he will load the db
*/
loadFromStore(store) {
store.load()
}
_update_data() {
this._data = {}
for (let i = 0; i < this.data.length; i++) {
const d = this.data[i]
this._data[d._id] = d
}
}
/**
* Import the database from a json file
* @param {string} dbPath path to the db file
*/
import (dbPath) {
this.loadFile(dbPath, false)
}
/**
* Test if an entry exists with this id
* @param {any} id id to test
* @return {boolean}
*/
exists(id) {
return this.get(id) !== undefined
}
/**
* Get the entry by his id, !! DO NOT EDIT _ID
* @param {integer} id the id of the entry that u want
* @return {any} the entry
*/
get(id) {
return this._data[id]
}
/**
* Get the index (this.data) of entry from his _id
* @param {integer} id _id of the entry
* @return {integer} the index or -1 if not found
*/
indexOf(id) {
for (let i = 0; i < this.data.length; i++) {
if (this.data[i]._id === id) return i
}
return -1
}
/**
* Create an entry if _id is undefined or update it if _id is defined and exists in the db (else throw an error)
* @param {any} datas entry to add or update with this
* @return {any} the entry
*/
put(datas) {
if (datas._id === undefined) { // insertMode
datas._id = this.conf.lastId++
datas._createdAt = now()
this._data[datas._id] = datas
this.data.push(datas)
} else { // updateMode
if (this.exists(datas._id) === false) {
throw new Error('Db have no entry with id : ' + datas._id)
}
const edited = this.get(datas._id)
for (const key in datas) {
edited[key] = datas[key]
}
edited._updatedAt = now()
}
this.write()
return this.get(datas._id)
}
/**
* Overwrite an entry with the following data (an existing entry is required with _id specified) (slower than a put)
* @param {any} data to OverWrite entry _id with this
* @return {any} the entry
*/
overwrite(datas) {
if (this.exists(datas._id) === false) {
throw new Error('Db has no entry with id : ' + datas._id)
}
const old = this.get(datas._id)
datas._createdAt = old._createdAt
datas._updatedAt = now()
this._data[datas._id] = datas
this.data[this.indexOf(datas._id)] = datas
this.write()
return datas
}
/**
* Remove an entry by is id
* @param {any} id the id of the entry to remove
* @param {boolean} softDelete dont delete from db , just add _removedAt : now() (default false)
* @return {any} the removed entry
*/
remove(id, softDelete = false) {
if (this.exists(id) === false) {
throw new Error('Db have no entry with id : ' + id)
}
let old = this.get(id)
if (softDelete === false) {
delete this._data[id]
this.data.splice(this.indexOf(id), 1)
}
old._removedAt = now()
this.write()
return old
}
/**
* Find one element !! you work directly on the item, if you edit it , it will not be updated in the file
* @param {function} filter (entry,index) function that return true if the entry is what you want
* @param {boolean} fromEnd start from end
* @return {any} the entry if it finded one else null
*/
findOne(filter = () => true, fromEnd = false) {
if (fromEnd === false) {
for (let i = 0; i < this.data.length; i++) {
const entry = this.data[i]
if (filter(entry, i) === true) return entry
}
} else {
for (let i = this.data.length - 1; i > 0; i--) {
const entry = this.data[i]
if (filter(entry, i) === true) return entry
}
}
return null
}
/**
* Find all elements !! you work directly on the item, if you edit it , it will not be updated in the file unless you do a writeFile after
* Can be used as a foreach
* @param {function} filter (entry,index) function that return true if the entry is what you want
* @return {array} entries that matched the filter
*/
find(filter = () => true) {
const res = []
for (let i = 0; i < this.data.length; i++) {
const entry = this.data[i]
if (filter(entry, i) === true) res.push(entry)
}
return res
}
/**
* Do something on all elements
* @param {function} action (entry, index) do what you want with each entry
*/
forEach(action = () => {}) {
for (let i = 0; i < this.data.length; i++) {
action(this.data[i], i)
}
this.write()
}
}
NoDBStore.Storage = Storage
module.exports = NoDBStore