beanbagdb 0.7.0 → 0.8.0
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/package.json +1 -1
- package/src/index.js +94 -30
- package/src/system_schema.js +26 -1
- package/test/operations.test.js +2 -2
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -60,7 +60,7 @@ export class BeanBagDB {
|
|
|
60
60
|
};
|
|
61
61
|
this._version = this._get_current_version();
|
|
62
62
|
this.active = false;
|
|
63
|
-
this.
|
|
63
|
+
this.apps = {}; // this is where external apps load their scripts
|
|
64
64
|
console.log("Run ready() now");
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -183,9 +183,9 @@ export class BeanBagDB {
|
|
|
183
183
|
* @async
|
|
184
184
|
* @returns {Promise<void>} - Resolves when the database has been verified and initialized.
|
|
185
185
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
console.log("
|
|
186
|
+
|
|
187
|
+
async check_ready(){
|
|
188
|
+
console.log("checking if DB is ready to be used")
|
|
189
189
|
let version_search = await this.db_api.search({
|
|
190
190
|
selector: { schema: "system_setting", "data.name": "beanbagdb_system" },
|
|
191
191
|
})
|
|
@@ -196,12 +196,22 @@ export class BeanBagDB {
|
|
|
196
196
|
this.active = doc["data"]["value"]["version"] == this._version;
|
|
197
197
|
this.meta.beanbagdb_version_db = doc["data"]["value"]["version"];
|
|
198
198
|
}
|
|
199
|
-
if
|
|
200
|
-
|
|
199
|
+
if(!this.active){console.log("Version mismatch.Init of default required")}
|
|
200
|
+
return this.active
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async ready(init_automatically=true) {
|
|
204
|
+
let ready = await this.check_ready()
|
|
205
|
+
|
|
206
|
+
if (ready) {
|
|
207
|
+
console.log("Ready.Set.Go");
|
|
201
208
|
} else {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
if(init_automatically){
|
|
210
|
+
console.log("Initializing")
|
|
211
|
+
await this.initialize();
|
|
212
|
+
}else{
|
|
213
|
+
throw new Error("DB cannot be used because there is a version mismatch between the DB and the script. Since automatically init flag was set to true, exiting")
|
|
214
|
+
}
|
|
205
215
|
}
|
|
206
216
|
}
|
|
207
217
|
|
|
@@ -411,7 +421,7 @@ export class BeanBagDB {
|
|
|
411
421
|
// if(input.schema=="system_edge"){throw new DocCreationError("This type of record can only be created through the create_edge api")}
|
|
412
422
|
if(Object.keys(input.data).length==0){throw new DocCreationError(`No data provided`)}
|
|
413
423
|
try {
|
|
414
|
-
let doc_obj = await this._insert_pre_checks(input.schema, input.data,input?.meta||{}, input?.settings||{});
|
|
424
|
+
let doc_obj = await this._insert_pre_checks(input.schema, input.data,input?.meta||{}, input?.app||{} ,input?.settings||{});
|
|
415
425
|
let new_rec = await this.db_api.insert(doc_obj);
|
|
416
426
|
return {_id:new_rec["id"],_rev : new_rec["rev"] ,...doc_obj};
|
|
417
427
|
} catch (error) {
|
|
@@ -534,7 +544,7 @@ export class BeanBagDB {
|
|
|
534
544
|
} = params;
|
|
535
545
|
|
|
536
546
|
if(!criteria){throw new DocUpdateError("Doc search criteria not provided")}
|
|
537
|
-
if(!updates){throw new DocUpdateError("No updates provided")}
|
|
547
|
+
if(!updates){throw new DocUpdateError("No updates provided. Format {'update':{'data':{...selected fields},'meta':{},'app':{... used by apps to manage app data} }}")}
|
|
538
548
|
|
|
539
549
|
// making a big assumption here : primary key fields cannot be edited
|
|
540
550
|
// so updating the doc will not generate primary key conflicts
|
|
@@ -613,6 +623,52 @@ export class BeanBagDB {
|
|
|
613
623
|
full_doc["meta"] = { ...full_doc["meta"], ...allowed_meta };
|
|
614
624
|
something_to_update = true
|
|
615
625
|
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* to update app data
|
|
629
|
+
* app { key:{mode:"update|replace|append|remove",data:{}} }
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
if(updates.app){
|
|
633
|
+
if(!full_doc.app){ full_doc["app"]={}}
|
|
634
|
+
//if(update_source=="api"){throw new DocUpdateError(`Invalid update source. Only an app can update app data of the doc. You must specify an app name as "update_source" `)}
|
|
635
|
+
Object.entries(updates.app).forEach(([appName, update]) => {
|
|
636
|
+
if (!update || typeof update !== 'object' || !update.mode || !update.data) {
|
|
637
|
+
console.warn(`Invalid update format for ${appName}`);
|
|
638
|
+
throw new DocUpdateError(`Invalid update format for app ${appName}. Must be an object {mode:"update|replace|append|remove", data:{} }`)
|
|
639
|
+
}
|
|
640
|
+
switch (update.mode) {
|
|
641
|
+
case 'update':
|
|
642
|
+
full_doc.app[appName] = {
|
|
643
|
+
...full_doc.app[appName],
|
|
644
|
+
...update.data
|
|
645
|
+
};
|
|
646
|
+
something_to_update = true
|
|
647
|
+
break;
|
|
648
|
+
case 'replace':
|
|
649
|
+
full_doc.app[appName] = update.data;
|
|
650
|
+
something_to_update = true
|
|
651
|
+
break;
|
|
652
|
+
case 'append':
|
|
653
|
+
Object.entries(update.data).forEach(([key, value]) => {
|
|
654
|
+
if (!Array.isArray(full_doc.app[appName]?.[key])) {
|
|
655
|
+
full_doc.app[appName] = full_doc.app[appName] || {};
|
|
656
|
+
full_doc.app[appName][key] = [];
|
|
657
|
+
}
|
|
658
|
+
full_doc.app[appName][key].push(value);
|
|
659
|
+
});
|
|
660
|
+
something_to_update = true
|
|
661
|
+
break;
|
|
662
|
+
case 'remove':
|
|
663
|
+
delete full_doc.app[appName];
|
|
664
|
+
something_to_update = true
|
|
665
|
+
break;
|
|
666
|
+
default:
|
|
667
|
+
throw new DocUpdateError( `Unknown mode: ${update.mode} app ${appName}. Must be an object {mode:"update|replace|append|remove", data:{} }`)
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
616
672
|
if(something_to_update){
|
|
617
673
|
// encrypt the data again since read returns decrypted data
|
|
618
674
|
full_doc = await this._encrypt_doc(schema, full_doc);
|
|
@@ -767,26 +823,18 @@ export class BeanBagDB {
|
|
|
767
823
|
* @param {string} plugin_name
|
|
768
824
|
* @param {object} plugin_module
|
|
769
825
|
*/
|
|
770
|
-
async
|
|
826
|
+
async load_scripts(app_name, app_module) {
|
|
771
827
|
this._check_ready_to_use();
|
|
772
|
-
this.
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
this.plugins[plugin_name][func_name] = plugin_module.actions[func_name].bind(null,this)
|
|
828
|
+
this.apps[app_name] = {};
|
|
829
|
+
if(app_module){
|
|
830
|
+
for (let func_name in app_module) {
|
|
831
|
+
if (typeof app_module[func_name] == "function") {
|
|
832
|
+
this.apps[app_name][func_name] = app_module[func_name].bind(null,this)
|
|
778
833
|
}
|
|
779
834
|
}
|
|
835
|
+
}else{
|
|
836
|
+
console.log("app_module is blank")
|
|
780
837
|
}
|
|
781
|
-
|
|
782
|
-
if(plugin_module.schemas){
|
|
783
|
-
await this._upgrade_schema_in_bulk(plugin_module.schemas,true,`Updating ${plugin_name} plugin schemas`)
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// Check if the plugin has an on_load method and call it
|
|
787
|
-
// if (typeof this.plugins[plugin_name].on_load === "function") {
|
|
788
|
-
// await this.plugins[plugin_name].on_load();
|
|
789
|
-
// }
|
|
790
838
|
}
|
|
791
839
|
|
|
792
840
|
/**
|
|
@@ -1075,16 +1123,16 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1075
1123
|
throw new Error("Schema name not provided for the blank doc");
|
|
1076
1124
|
}
|
|
1077
1125
|
let dt = this.util_get_now_unix_timestamp()
|
|
1078
|
-
let title = `${
|
|
1126
|
+
let title = `${dt}`
|
|
1079
1127
|
let doc = {
|
|
1080
1128
|
data: {},
|
|
1081
1129
|
meta: {
|
|
1082
1130
|
created_on: dt,
|
|
1083
1131
|
tags: [],
|
|
1084
|
-
app: {},
|
|
1085
1132
|
link: this.util_generate_random_link(), // there is a link by default. overwrite this if user provided one but only before checking if it is unique
|
|
1086
1133
|
title: title
|
|
1087
1134
|
},
|
|
1135
|
+
app:{},
|
|
1088
1136
|
schema: schema_name,
|
|
1089
1137
|
};
|
|
1090
1138
|
return doc;
|
|
@@ -1165,7 +1213,7 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1165
1213
|
*
|
|
1166
1214
|
* @throws {Error} If validation fails, or the document already exists.
|
|
1167
1215
|
*/
|
|
1168
|
-
async _insert_pre_checks(schema, data,
|
|
1216
|
+
async _insert_pre_checks(schema, data, meta = {}, app={} ,settings = {}) {
|
|
1169
1217
|
// schema search
|
|
1170
1218
|
let sch_search = await this.search({selector: { schema: "schema", "data.name": schema }})
|
|
1171
1219
|
if (sch_search.docs.length == 0) {throw new DocCreationError(`The schema "${schema}" does not exists`)}
|
|
@@ -1182,6 +1230,19 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1182
1230
|
if(Object.keys(meta).length>0){
|
|
1183
1231
|
meta = this.util_validate_data({schema:sys_sch.editable_metadata_schema, data:meta})
|
|
1184
1232
|
}
|
|
1233
|
+
|
|
1234
|
+
if(Object.keys(app).length>0){
|
|
1235
|
+
let app_schema = {
|
|
1236
|
+
"type": "object",
|
|
1237
|
+
"patternProperties": {
|
|
1238
|
+
".*": {
|
|
1239
|
+
"type": "object"
|
|
1240
|
+
}
|
|
1241
|
+
},
|
|
1242
|
+
"additionalProperties": false
|
|
1243
|
+
}
|
|
1244
|
+
let app1 = this.util_validate_data({schema:app_schema, data:app})
|
|
1245
|
+
}
|
|
1185
1246
|
|
|
1186
1247
|
|
|
1187
1248
|
// duplicate meta.link check
|
|
@@ -1226,6 +1287,9 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
|
|
|
1226
1287
|
if(meta){
|
|
1227
1288
|
doc_obj["meta"] = {...doc_obj["meta"],...meta};
|
|
1228
1289
|
}
|
|
1290
|
+
if(app){
|
|
1291
|
+
doc_obj["app"] = app
|
|
1292
|
+
}
|
|
1229
1293
|
return doc_obj;
|
|
1230
1294
|
}
|
|
1231
1295
|
|
package/src/system_schema.js
CHANGED
|
@@ -286,7 +286,7 @@ export const default_app = {
|
|
|
286
286
|
title: "Edge in the system graph",
|
|
287
287
|
active: true,
|
|
288
288
|
system_generated: true,
|
|
289
|
-
version: 1,
|
|
289
|
+
version: 1.5,
|
|
290
290
|
description: "To define edges in the simple directed graph of records.",
|
|
291
291
|
schema: {
|
|
292
292
|
type: "object",
|
|
@@ -428,6 +428,31 @@ export const default_app = {
|
|
|
428
428
|
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-braces-asterisk" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.114 8.063V7.9c1.005-.102 1.497-.615 1.497-1.6V4.503c0-1.094.39-1.538 1.354-1.538h.273V2h-.376C2.25 2 1.49 2.759 1.49 4.352v1.524c0 1.094-.376 1.456-1.49 1.456v1.299c1.114 0 1.49.362 1.49 1.456v1.524c0 1.593.759 2.352 2.372 2.352h.376v-.964h-.273c-.964 0-1.354-.444-1.354-1.538V9.663c0-.984-.492-1.497-1.497-1.6M14.886 7.9v.164c-1.005.103-1.497.616-1.497 1.6v1.798c0 1.094-.39 1.538-1.354 1.538h-.273v.964h.376c1.613 0 2.372-.759 2.372-2.352v-1.524c0-1.094.376-1.456 1.49-1.456v-1.3c-1.114 0-1.49-.362-1.49-1.456V4.352C14.51 2.759 13.75 2 12.138 2h-.376v.964h.273c.964 0 1.354.444 1.354 1.538V6.3c0 .984.492 1.497 1.497 1.6M7.5 11.5V9.207l-1.621 1.621-.707-.707L6.792 8.5H4.5v-1h2.293L5.172 5.879l.707-.707L7.5 6.792V4.5h1v2.293l1.621-1.621.707.707L9.208 7.5H11.5v1H9.207l1.621 1.621-.707.707L8.5 9.208V11.5z"/></svg>`
|
|
429
429
|
},
|
|
430
430
|
},
|
|
431
|
+
{
|
|
432
|
+
name: "system_text",
|
|
433
|
+
system_generated: true,
|
|
434
|
+
title: "Plain text",
|
|
435
|
+
active: true,
|
|
436
|
+
version: 1,
|
|
437
|
+
description: "Plain text nothing more",
|
|
438
|
+
schema: {
|
|
439
|
+
type: "object",
|
|
440
|
+
additionalProperties: false,
|
|
441
|
+
required: [],
|
|
442
|
+
properties: {
|
|
443
|
+
text: {
|
|
444
|
+
type: "string",
|
|
445
|
+
default:"Text..."
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
settings: {
|
|
450
|
+
primary_keys: [],
|
|
451
|
+
non_editable_fields: [],
|
|
452
|
+
encrypted_fields: [],
|
|
453
|
+
svg_icon25:`<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-justify-left" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5m0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5m0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5m0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5"/></svg>`
|
|
454
|
+
},
|
|
455
|
+
},
|
|
431
456
|
],
|
|
432
457
|
records: [],
|
|
433
458
|
};
|
package/test/operations.test.js
CHANGED
|
@@ -1371,7 +1371,7 @@ describe("Doc search tests", async () => {
|
|
|
1371
1371
|
it('all docs', async () => {
|
|
1372
1372
|
try {
|
|
1373
1373
|
let udata = await database3.search({selector:{}})
|
|
1374
|
-
assert(udata.docs.length==
|
|
1374
|
+
assert(udata.docs.length==14)
|
|
1375
1375
|
} catch (error) {
|
|
1376
1376
|
//console.log(error)
|
|
1377
1377
|
throw error
|
|
@@ -1391,7 +1391,7 @@ describe("Doc search tests", async () => {
|
|
|
1391
1391
|
it('read docs 2', async () => {
|
|
1392
1392
|
try {
|
|
1393
1393
|
let udata = await database3.search({selector:{"schema":"schema"}})
|
|
1394
|
-
assert(udata.docs.length==
|
|
1394
|
+
assert(udata.docs.length==10) // schema,book,setting,key,edge,edge_constraints
|
|
1395
1395
|
} catch (error) {
|
|
1396
1396
|
//console.log(error)
|
|
1397
1397
|
throw error
|