cradova 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -19
- package/dist/index.d.ts +26 -0
- package/dist/index.js +468 -0
- package/dist/rolled-cradova.js +2366 -0
- package/dist/scripts/JsonDB.d.ts +287 -0
- package/dist/scripts/JsonDB.js +633 -0
- package/dist/scripts/Router.d.ts +5 -0
- package/dist/scripts/Router.js +170 -0
- package/dist/scripts/Screen.d.ts +51 -0
- package/dist/scripts/Screen.js +107 -0
- package/dist/scripts/ajax.d.ts +28 -0
- package/dist/scripts/ajax.js +63 -0
- package/dist/scripts/fns.d.ts +84 -0
- package/dist/scripts/fns.js +307 -0
- package/dist/scripts/init.d.ts +1 -0
- package/dist/scripts/init.js +25 -0
- package/dist/scripts/loadCss.d.ts +1 -0
- package/dist/scripts/loadCss.js +194 -0
- package/dist/scripts/memory.d.ts +12 -0
- package/dist/scripts/memory.js +46 -0
- package/dist/scripts/store.d.ts +12 -0
- package/dist/scripts/store.js +64 -0
- package/dist/scripts/swipe.d.ts +1 -0
- package/dist/scripts/swipe.js +114 -0
- package/dist/scripts/track.d.ts +12 -0
- package/dist/scripts/track.js +150 -0
- package/dist/scripts/widget.d.ts +8 -0
- package/dist/scripts/widget.js +21 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.js +1 -0
- package/index.ts +336 -147
- package/package.json +18 -11
- package/scripts/JsonDB.ts +134 -130
- package/scripts/Router.ts +94 -24
- package/scripts/Screen.ts +99 -39
- package/scripts/{littleAxios.ts → ajax.ts} +44 -6
- package/scripts/fns.ts +341 -0
- package/scripts/init.ts +11 -4
- package/scripts/loadCss.ts +194 -0
- package/scripts/memory.ts +44 -0
- package/scripts/store.ts +32 -21
- package/scripts/style.css +189 -0
- package/scripts/swipe.ts +4 -4
- package/scripts/track.ts +171 -0
- package/scripts/widget.ts +17 -15
- package/tsconfig.json +18 -98
- package/types.ts +15 -1
- package/{online-only-after-initial-cache.ts → workers/online-only-after-initial-cache.ts} +14 -11
- package/{service-worker.ts → workers/service-worker.ts} +17 -10
- package/docs/README.md +0 -0
- package/manifest.json +0 -38
- package/scripts/Metrics.ts +0 -66
- package/scripts/animate.ts +0 -55
- package/scripts/createState.ts +0 -27
- package/scripts/css.ts +0 -47
- package/scripts/dispatcher.ts +0 -158
- package/scripts/fetcher.ts +0 -31
- package/scripts/file-system.ts +0 -173
- package/scripts/fullscreen.ts +0 -21
- package/scripts/localStorage.ts +0 -19
- package/scripts/media.ts +0 -51
- package/scripts/promptbeforeleave.ts +0 -10
- package/scripts/reuse.ts +0 -79
- package/scripts/speaker.ts +0 -25
- package/scripts/uuid.ts +0 -10
- package/types.d.ts +0 -0
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON DB DataBase MIT Licence © 2022
|
|
3
|
+
* ************************************
|
|
4
|
+
* Created by Friday Candour @uiedbooker
|
|
5
|
+
* email > fridaymaxtour@gmail.com
|
|
6
|
+
* github > www.github.com/FridayCandour
|
|
7
|
+
* telegram > @uiedbooker
|
|
8
|
+
* JSONDB @version 1.0.0
|
|
9
|
+
* */
|
|
10
|
+
export const JSONDBversion = "1.0.0";
|
|
11
|
+
let fs, isNode = false, _dirname;
|
|
12
|
+
(async function () {
|
|
13
|
+
if (!globalThis.localStorage) {
|
|
14
|
+
isNode = true;
|
|
15
|
+
}
|
|
16
|
+
})();
|
|
17
|
+
const schema = class {
|
|
18
|
+
constructor(schema_configuration_object, validators) {
|
|
19
|
+
// validations
|
|
20
|
+
if (!schema_configuration_object.columns) {
|
|
21
|
+
throw new Error("JSONDB: can't create an empty table should have some columns");
|
|
22
|
+
}
|
|
23
|
+
validators.validateColumns(schema_configuration_object.columns);
|
|
24
|
+
const isEmptyObject = function (obj) {
|
|
25
|
+
// for checking for empty objects
|
|
26
|
+
for (const _name in obj) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
31
|
+
if (schema_configuration_object.relations &&
|
|
32
|
+
!isEmptyObject(schema_configuration_object.relations)) {
|
|
33
|
+
validators.validateRelations(schema_configuration_object.relations);
|
|
34
|
+
}
|
|
35
|
+
// assignment
|
|
36
|
+
this.base_name = "";
|
|
37
|
+
this.name = schema_configuration_object.name;
|
|
38
|
+
this.last_index = -1;
|
|
39
|
+
this.columns = schema_configuration_object.columns;
|
|
40
|
+
this.relations = schema_configuration_object.relations || null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export class JSONDBTableWrapper {
|
|
44
|
+
constructor(self, keys) {
|
|
45
|
+
this.put = async (name, value) => {
|
|
46
|
+
if (isNode) {
|
|
47
|
+
await fs.writeFile(name + ".json", JSON.stringify(value), "utf-8");
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
localStorage.setItem(name, JSON.stringify(value));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
this.get = async (name) => {
|
|
54
|
+
if (!isNode) {
|
|
55
|
+
return JSON.parse(localStorage.getItem(name));
|
|
56
|
+
}
|
|
57
|
+
const data = await fs.readFile(_dirname + "/" + name + ".json", {
|
|
58
|
+
encoding: "utf-8",
|
|
59
|
+
});
|
|
60
|
+
if (data) {
|
|
61
|
+
return JSON.parse(data);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new Error("JSONDB: error failed to retrieve entities from database ");
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
this.validator = (incoming, tables) => {
|
|
68
|
+
// works for type, nulllable and unique validations.
|
|
69
|
+
const outgoing = {};
|
|
70
|
+
for (const prop in this.self.columns) {
|
|
71
|
+
if (this.self.columns[prop].nullable !== true &&
|
|
72
|
+
!Object.hasOwnProperty.call(incoming, prop)) {
|
|
73
|
+
throw new Error("JSONDB: error failed to validate incoming data because " +
|
|
74
|
+
prop +
|
|
75
|
+
" is required for " +
|
|
76
|
+
this.self.name +
|
|
77
|
+
" Schema");
|
|
78
|
+
}
|
|
79
|
+
if (!this.self.columns[prop].nullable &&
|
|
80
|
+
typeof incoming[prop] !== this.self.columns[prop].type) {
|
|
81
|
+
throw new Error("JSONDB: error failed to validate incoming data because " +
|
|
82
|
+
prop +
|
|
83
|
+
"'s value " +
|
|
84
|
+
incoming[prop] +
|
|
85
|
+
" has got a wrong data type of " +
|
|
86
|
+
typeof incoming[prop] +
|
|
87
|
+
" for " +
|
|
88
|
+
this.self.name +
|
|
89
|
+
" should be " +
|
|
90
|
+
this.self.columns[prop].type +
|
|
91
|
+
" type instead");
|
|
92
|
+
}
|
|
93
|
+
if (this.self.columns[prop].unique === true) {
|
|
94
|
+
for (let i = 0; i < tables.length; i++) {
|
|
95
|
+
const element = tables[i];
|
|
96
|
+
if (element[prop] === incoming[prop]) {
|
|
97
|
+
throw new Error("JSONDB: error failed to validate incoming data because " +
|
|
98
|
+
prop +
|
|
99
|
+
" is unique for " +
|
|
100
|
+
this.self.name +
|
|
101
|
+
" Schema can't have more than one instance");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// cleaning time
|
|
106
|
+
outgoing[prop] = incoming[prop];
|
|
107
|
+
}
|
|
108
|
+
return outgoing;
|
|
109
|
+
};
|
|
110
|
+
this.self = self;
|
|
111
|
+
this.keys = keys;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Save with relations
|
|
115
|
+
* ---------------------
|
|
116
|
+
* @type .saveWithRelations(target table, schema, schema | schema[]) => Promise(object)
|
|
117
|
+
* @example
|
|
118
|
+
* // single relation
|
|
119
|
+
await PollTable.saveWithRelations(MessageTable, Poll, message);
|
|
120
|
+
// arrays of relations
|
|
121
|
+
await PollTable.saveWithRelations(MessageTable, Poll, allMessages);
|
|
122
|
+
*/
|
|
123
|
+
async saveWithRelations(table, incoming, relations) {
|
|
124
|
+
if (!relations || !table) {
|
|
125
|
+
throw new TypeError("JsonDB: error saving with relations table name or relation cannot be null " +
|
|
126
|
+
JSON.stringify(relations) +
|
|
127
|
+
" " +
|
|
128
|
+
JSON.stringify(table));
|
|
129
|
+
}
|
|
130
|
+
if (!table.self || !table.self.name) {
|
|
131
|
+
throw new TypeError("JsonDB: error saving with relations table is invalid " +
|
|
132
|
+
JSON.stringify(table));
|
|
133
|
+
}
|
|
134
|
+
const db = await this.get(this.self.base_name);
|
|
135
|
+
db.last_access_time = Date();
|
|
136
|
+
if (incoming && typeof incoming.index !== "number") {
|
|
137
|
+
throw new Error("JsonDB: save before saving with relations");
|
|
138
|
+
}
|
|
139
|
+
db.tables[this.self.name][incoming.index] = incoming;
|
|
140
|
+
if (relations && Array.isArray(relations)) {
|
|
141
|
+
for (let i = 0; i < relations.length; i++) {
|
|
142
|
+
if (db.Entities[this.self.name].relations[table.self.name]) {
|
|
143
|
+
if (db.Entities[this.self.name].relations[table.self.name].type ===
|
|
144
|
+
"many") {
|
|
145
|
+
db.tables[this.self.name][incoming.index].relations[table.self.name] = !db.tables[this.self.name][incoming.index].relations[table.self.name]
|
|
146
|
+
? [relations[i]]
|
|
147
|
+
: [
|
|
148
|
+
...db.tables[this.self.name][incoming.index].relations[table.self.name],
|
|
149
|
+
relations[i],
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
db.tables[this.self.name][incoming.index].relations[table.self.name] = relations[i];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
if (relations) {
|
|
160
|
+
if (db.Entities[this.self.name].relations[table.self.name]) {
|
|
161
|
+
if (db.Entities[this.self.name].relations[table.self.name].type ===
|
|
162
|
+
"many") {
|
|
163
|
+
db.tables[this.self.name][incoming.index].relations[table.self.name] = !db.tables[this.self.name][incoming.index].relations[table.self.name]
|
|
164
|
+
? [relations]
|
|
165
|
+
: [
|
|
166
|
+
...db.tables[this.self.name][incoming.index].relations[table.self.name],
|
|
167
|
+
relations,
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
db.tables[this.self.name][incoming.index].relations[table.self.name] = relations;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
await this.put(this.self.base_name, db);
|
|
177
|
+
return db.tables[this.self.name][incoming.index];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Save table into a Jsondb instance
|
|
181
|
+
* -----------------------------
|
|
182
|
+
* @type .save(schema)=> Promise(object)
|
|
183
|
+
* @example
|
|
184
|
+
await PollTable.save(poll)
|
|
185
|
+
*/
|
|
186
|
+
async save(incoming) {
|
|
187
|
+
// db.tables[this.self.name] = db.tables[this.self.name].sort(
|
|
188
|
+
// (a, b) => a.index - b.index
|
|
189
|
+
// );
|
|
190
|
+
const db = await this.get(this.self.base_name);
|
|
191
|
+
db.last_access_time = Date();
|
|
192
|
+
if (typeof incoming.index !== "number") {
|
|
193
|
+
incoming = this.validator(incoming, db.tables[this.self.name]);
|
|
194
|
+
if (this.self.relations && !incoming.relations) {
|
|
195
|
+
incoming.relations = {};
|
|
196
|
+
}
|
|
197
|
+
db.Entities[this.self.name].last_index += 1;
|
|
198
|
+
incoming.index = db.Entities[this.self.name].last_index;
|
|
199
|
+
db.tables[this.self.name].push(incoming);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
db.tables[this.self.name][incoming.index] = incoming;
|
|
203
|
+
}
|
|
204
|
+
await this.put(this.self.base_name, db);
|
|
205
|
+
return incoming;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Save table into a Jsondb instance
|
|
209
|
+
* -----------------------------
|
|
210
|
+
* @type .remove(schema)=> Promise(object)
|
|
211
|
+
* @example
|
|
212
|
+
await PollTable.remove(poll)
|
|
213
|
+
*/
|
|
214
|
+
async remove(entity) {
|
|
215
|
+
const db = await this.get(this.self.base_name);
|
|
216
|
+
db.last_access_time = Date();
|
|
217
|
+
// db.tables[this.self.name].splice(entity.index, 1);
|
|
218
|
+
db.tables[this.self.name][entity.index] = null;
|
|
219
|
+
await this.put(this.self.base_name, db);
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Save table into a Jsondb instance
|
|
224
|
+
* -----------------------------
|
|
225
|
+
* @type .count(schema)=> Promise(number)
|
|
226
|
+
* @example
|
|
227
|
+
await PollTable.count(poll)
|
|
228
|
+
*/
|
|
229
|
+
async count() {
|
|
230
|
+
const db = await this.get(this.self.base_name);
|
|
231
|
+
db.last_access_time = Date();
|
|
232
|
+
return db.tables[this.self.name].length;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Save table into a Jsondb instance
|
|
236
|
+
* -----------------------------
|
|
237
|
+
* @type .getAll()=> Promise(object[])
|
|
238
|
+
* @example
|
|
239
|
+
await PollTable.getAll()
|
|
240
|
+
*/
|
|
241
|
+
async getAll() {
|
|
242
|
+
const db = await this.get(this.self.base_name);
|
|
243
|
+
db.last_access_time = Date();
|
|
244
|
+
return db.tables[this.self.name];
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* get entities with any of the values specifiled from a Jsondb instance
|
|
248
|
+
* -----------------------------
|
|
249
|
+
* @type .getWhereAny({prop: value}, number | undefind)=> Promise(object)
|
|
250
|
+
* @example
|
|
251
|
+
await PollTable.getWhereAny({name: "friday", age: 121, class: "senior"}) // gets all
|
|
252
|
+
await PollTable.getWhereAny({email: "fridaymaxtour@gmail.com"}, 2) // gets 2 if they are up to two
|
|
253
|
+
*/
|
|
254
|
+
async getWhereAny(props, number) {
|
|
255
|
+
const results = [];
|
|
256
|
+
let all;
|
|
257
|
+
const db = await this.get(this.self.base_name);
|
|
258
|
+
db.last_access_time = Date();
|
|
259
|
+
all = db.tables[this.self.name];
|
|
260
|
+
for (let i = 0; i < all.length; i++) {
|
|
261
|
+
const element = all[i];
|
|
262
|
+
for (const [k, v] of Object.entries(props)) {
|
|
263
|
+
if (element[k] && element[k] === v) {
|
|
264
|
+
results.push(element);
|
|
265
|
+
if (typeof number === "number" && results.length === number) {
|
|
266
|
+
return results;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return results;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* get entities with the given prop of type "string" where the values specifiled is included
|
|
275
|
+
* -----------------------------
|
|
276
|
+
* @type .getWhereAnyPropsIncludes({prop: value}, number | undefind)=> Promise(object)
|
|
277
|
+
*
|
|
278
|
+
* @example prop must be type string!
|
|
279
|
+
*
|
|
280
|
+
await PollTable.getWhereAnyPropsIncludes({name: "fri"}) // gets all
|
|
281
|
+
await PollTable.getWhereAnyPropsIncludes({name: "fri"}, 2) // gets 2 if they are up to two
|
|
282
|
+
*/
|
|
283
|
+
async getWhereAnyPropsIncludes(props, number) {
|
|
284
|
+
const results = [];
|
|
285
|
+
const db = await this.get(this.self.base_name);
|
|
286
|
+
db.last_access_time = Date();
|
|
287
|
+
const all = db.tables[this.self.name];
|
|
288
|
+
for (let i = 0; i < all.length; i++) {
|
|
289
|
+
const element = all[i];
|
|
290
|
+
for (const [k, v] of Object.entries(props)) {
|
|
291
|
+
if (element[k] && typeof v === "string" && element[k].includes(v)) {
|
|
292
|
+
results.push(element);
|
|
293
|
+
if (typeof number === "number" && results.length === number) {
|
|
294
|
+
return results;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return results;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* get an entity with the values specifiled from a Jsondb instance
|
|
303
|
+
* -----------------------------
|
|
304
|
+
* @type .getOne({prop: value})=> Promise(object)
|
|
305
|
+
* @example
|
|
306
|
+
|
|
307
|
+
await PollTable.getOne({email: "fridaymaxtour@gamail.com"}) // gets one
|
|
308
|
+
|
|
309
|
+
*/
|
|
310
|
+
async getOne(props) {
|
|
311
|
+
let results = null;
|
|
312
|
+
const db = await this.get(this.self.base_name);
|
|
313
|
+
db.last_access_time = Date();
|
|
314
|
+
const all = db.tables[this.self.name];
|
|
315
|
+
for (let i = 0; i < all.length; i++) {
|
|
316
|
+
const element = all[i];
|
|
317
|
+
for (const [k, v] of Object.entries(props)) {
|
|
318
|
+
if (element[k] && element[k] === v) {
|
|
319
|
+
results = element;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return results;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const JSONDBConnection = class {
|
|
328
|
+
constructor(Entities, keys) {
|
|
329
|
+
this.Entities = Entities;
|
|
330
|
+
this.keys = keys;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Get a table from JSONDB
|
|
334
|
+
*------------------------
|
|
335
|
+
* @example
|
|
336
|
+
*
|
|
337
|
+
*
|
|
338
|
+
const details = {
|
|
339
|
+
password: "password",
|
|
340
|
+
username: "jsondb_username",
|
|
341
|
+
};
|
|
342
|
+
// getting connection instance into JSONDB
|
|
343
|
+
const connection = await database.createJSONDBConnection(details);
|
|
344
|
+
// getting a table
|
|
345
|
+
const MessageTable = connection.getTable("Message");
|
|
346
|
+
* */
|
|
347
|
+
getTable(table_name) {
|
|
348
|
+
for (const [tableName, table] of Object.entries(this.Entities)) {
|
|
349
|
+
if (table_name === tableName) {
|
|
350
|
+
return new JSONDBTableWrapper(table, this.keys);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* Create a new JSONDB object
|
|
358
|
+
*------------------------
|
|
359
|
+
* @class
|
|
360
|
+
|
|
361
|
+
* const database = new JSONDB()
|
|
362
|
+
*
|
|
363
|
+
* Creates a new JSONDB object
|
|
364
|
+
*
|
|
365
|
+
* .
|
|
366
|
+
* */
|
|
367
|
+
export class JSONDB {
|
|
368
|
+
constructor() {
|
|
369
|
+
this.DB_NAME = "";
|
|
370
|
+
this.username = "";
|
|
371
|
+
this.encrypted = false;
|
|
372
|
+
this.initialised = false;
|
|
373
|
+
this.time_created = Date();
|
|
374
|
+
this.version = JSONDBversion;
|
|
375
|
+
this.last_access_time = "";
|
|
376
|
+
this.visuality = "";
|
|
377
|
+
this.Entities = {};
|
|
378
|
+
this.tables = {};
|
|
379
|
+
}
|
|
380
|
+
async getDB(name) {
|
|
381
|
+
if (!isNode) {
|
|
382
|
+
return JSON.parse(localStorage.getItem(name));
|
|
383
|
+
}
|
|
384
|
+
const data = await fs.readFile(_dirname + "/" + name + ".json", {
|
|
385
|
+
encoding: "utf-8",
|
|
386
|
+
});
|
|
387
|
+
if (data) {
|
|
388
|
+
return JSON.parse(data);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
throw new Error("JSONDB: error failed to retrieve entities from database ");
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Schema constructor for Jsondb
|
|
396
|
+
* -----------------------------
|
|
397
|
+
*
|
|
398
|
+
* name @type string
|
|
399
|
+
*
|
|
400
|
+
* columns @type object {
|
|
401
|
+
*
|
|
402
|
+
* type > @type any of number > string > boolean > blob and must be specified
|
|
403
|
+
*
|
|
404
|
+
* nullable @type bolean true > false default false
|
|
405
|
+
*
|
|
406
|
+
* unique @type bolean true > false default false
|
|
407
|
+
*
|
|
408
|
+
* }
|
|
409
|
+
*
|
|
410
|
+
* relations @type object {
|
|
411
|
+
*
|
|
412
|
+
* target: entity schema @type object,
|
|
413
|
+
*
|
|
414
|
+
* attachment_name: @type string,
|
|
415
|
+
*
|
|
416
|
+
* type : @type string should be "many" or "one"
|
|
417
|
+
*
|
|
418
|
+
* }
|
|
419
|
+
*
|
|
420
|
+
*
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
*
|
|
424
|
+
* const MessageSchema = database.schema({
|
|
425
|
+
name: "Message",
|
|
426
|
+
columns: {
|
|
427
|
+
vote: {
|
|
428
|
+
type: "number",
|
|
429
|
+
},
|
|
430
|
+
time: {
|
|
431
|
+
type: "string",
|
|
432
|
+
nullable: true,
|
|
433
|
+
},
|
|
434
|
+
value: {
|
|
435
|
+
type: "string",
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
*
|
|
440
|
+
* const PollSchema = new JSONDB.schema({
|
|
441
|
+
name: "Poll",
|
|
442
|
+
columns: {
|
|
443
|
+
value: {
|
|
444
|
+
type: "varchar",
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
relations: {
|
|
448
|
+
Message: {
|
|
449
|
+
target: Message,
|
|
450
|
+
type: "many-to-one",
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
*/
|
|
455
|
+
schema(schema_configuration_object) {
|
|
456
|
+
return new schema(schema_configuration_object, {
|
|
457
|
+
validateColumns: this.validateColumns,
|
|
458
|
+
validateRelations: this.validateRelations,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Create a new JSONDB instance
|
|
463
|
+
*------------------------
|
|
464
|
+
* @example
|
|
465
|
+
* // creates a JSONDB object
|
|
466
|
+
* const Database = new JSONDB()
|
|
467
|
+
* // database configuration object
|
|
468
|
+
* const config = {
|
|
469
|
+
DB_NAME: "my db",
|
|
470
|
+
password: "password",
|
|
471
|
+
username: "jsondb_username",
|
|
472
|
+
encrypted: false,
|
|
473
|
+
}
|
|
474
|
+
// Creates a new JSONDB instance
|
|
475
|
+
* Database.init(config)
|
|
476
|
+
* */
|
|
477
|
+
async init(config) {
|
|
478
|
+
console.log(`\x1B[32m JSONDB version ${JSONDBversion} \x1B[39m`);
|
|
479
|
+
this.initialised = true;
|
|
480
|
+
this.DB_NAME = config.name;
|
|
481
|
+
this.password = config.password || "";
|
|
482
|
+
this.username = config.username || "";
|
|
483
|
+
this.encrypted = config.encrypted || false;
|
|
484
|
+
this.time_created = Date();
|
|
485
|
+
this.tables = {};
|
|
486
|
+
try {
|
|
487
|
+
let wasThere;
|
|
488
|
+
if (isNode) {
|
|
489
|
+
wasThere = this.getDB(config.name);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
wasThere = localStorage.getItem(config.name);
|
|
493
|
+
}
|
|
494
|
+
if (wasThere) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
catch (error) { }
|
|
499
|
+
if (!config.password) {
|
|
500
|
+
throw new Error("JSONDB: error password is empty ");
|
|
501
|
+
}
|
|
502
|
+
if (!config.username) {
|
|
503
|
+
throw new Error("JSONDB: error username is empty ");
|
|
504
|
+
}
|
|
505
|
+
if (isNode) {
|
|
506
|
+
await fs.writeFile(config.name + ".json", JSON.stringify(this), "utf-8");
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
let db = JSON.stringify(this);
|
|
510
|
+
localStorage.setItem(config.name, db);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Create secure connection a Jsondb instance
|
|
515
|
+
* -----------------------------
|
|
516
|
+
* @example
|
|
517
|
+
*
|
|
518
|
+
* const details = {
|
|
519
|
+
password: "password",
|
|
520
|
+
username: "jsondb_username",
|
|
521
|
+
};
|
|
522
|
+
const connection = await database.createJSONDBConnection(details);
|
|
523
|
+
*/
|
|
524
|
+
async createJSONDBConnection(details) {
|
|
525
|
+
if (!this.initialised) {
|
|
526
|
+
throw new Error("JSONDB: you haven't create a JSONDB instance yet");
|
|
527
|
+
}
|
|
528
|
+
if (details.username !== this.username ||
|
|
529
|
+
details.password !== this.password) {
|
|
530
|
+
throw new Error("JSONDB: Access Denied");
|
|
531
|
+
}
|
|
532
|
+
const connection = await this.getDB(this.DB_NAME);
|
|
533
|
+
connection.last_access_time = Date();
|
|
534
|
+
return new JSONDBConnection(connection.Entities);
|
|
535
|
+
}
|
|
536
|
+
validateRelations(relations) {
|
|
537
|
+
const types = ["many", "one"];
|
|
538
|
+
for (const relation in relations) {
|
|
539
|
+
const value = relations[relation];
|
|
540
|
+
if (typeof value.target !== "object") {
|
|
541
|
+
throw new Error("JSONDB: wrong relationship target type given " +
|
|
542
|
+
value.target +
|
|
543
|
+
" should be object only");
|
|
544
|
+
}
|
|
545
|
+
if (!types.includes(value.type)) {
|
|
546
|
+
throw new Error("JSONDB: wrong relationship type given " +
|
|
547
|
+
value.type +
|
|
548
|
+
" should be many or one");
|
|
549
|
+
}
|
|
550
|
+
if (value.cascade && typeof value.cascade !== "boolean") {
|
|
551
|
+
throw new Error("JSONDB: wrong cascade value given " +
|
|
552
|
+
value.cascade +
|
|
553
|
+
" should be true or false");
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
validateColumns(columns) {
|
|
558
|
+
const types = ["number", "string", "boolean", "blob"];
|
|
559
|
+
for (const column in columns) {
|
|
560
|
+
const value = columns[column];
|
|
561
|
+
if (column) {
|
|
562
|
+
if (!types.includes(value.type)) {
|
|
563
|
+
throw new Error("JSONDB: wrong data type given " +
|
|
564
|
+
value.type +
|
|
565
|
+
" only number, string, boolean and blob are accepted");
|
|
566
|
+
}
|
|
567
|
+
if (value.unique && typeof value.unique !== "boolean") {
|
|
568
|
+
throw new Error("JSONDB: wrong unique value given " +
|
|
569
|
+
value.unique +
|
|
570
|
+
" should be true or false");
|
|
571
|
+
}
|
|
572
|
+
if (value.nullable && typeof value.nullable !== "boolean") {
|
|
573
|
+
throw new Error("JSONDB: wrong nullable value given " +
|
|
574
|
+
value.nullable +
|
|
575
|
+
" should be true or false");
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Assemble Entities into Jsondb
|
|
582
|
+
* -----------------------------
|
|
583
|
+
* @example
|
|
584
|
+
*
|
|
585
|
+
* const MessageSchema = database.schema({
|
|
586
|
+
name: "Message",
|
|
587
|
+
columns: {
|
|
588
|
+
vote: {
|
|
589
|
+
type: "number",
|
|
590
|
+
},
|
|
591
|
+
time: {
|
|
592
|
+
type: "string",
|
|
593
|
+
nullable: true,
|
|
594
|
+
},
|
|
595
|
+
value: {
|
|
596
|
+
type: "string",
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
database.assemble([MessageSchema]);
|
|
602
|
+
*
|
|
603
|
+
*/
|
|
604
|
+
async assemble(allEntities) {
|
|
605
|
+
if (!this.initialised) {
|
|
606
|
+
throw new Error("JSONDB: you haven't create a JSONDB instance yet");
|
|
607
|
+
}
|
|
608
|
+
try {
|
|
609
|
+
const wasThere = await this.getDB(this.DB_NAME);
|
|
610
|
+
if (wasThere) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
catch (error) { }
|
|
615
|
+
if (!Array.isArray(allEntities) || typeof allEntities[0] !== "object") {
|
|
616
|
+
throw new Error("JSONDB: invalid entity array list, can't be assembled");
|
|
617
|
+
}
|
|
618
|
+
for (let i = 0; i < allEntities.length; i++) {
|
|
619
|
+
this.Entities[allEntities[i].name] = allEntities[i];
|
|
620
|
+
this.Entities[allEntities[i].name].base_name = this.DB_NAME;
|
|
621
|
+
this.tables[allEntities[i].name] = [];
|
|
622
|
+
}
|
|
623
|
+
if (isNode) {
|
|
624
|
+
await fs.writeFile(this.DB_NAME + ".json", JSON.stringify(this), "utf-8");
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
localStorage.setItem(this.DB_NAME, JSON.stringify(this));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* @exports
|
|
633
|
+
*/
|