beanbagdb 0.7.1 → 0.8.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beanbagdb",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "description": "A JS library to introduce a schema layer to a No-SQL local database",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
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.plugins = {};
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
- async ready() {
187
- // TODO Ping db
188
- console.log("running ready....")
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 (this.active) {
200
- console.log("Ready");
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
- console.log("Not ready. Init required")
203
- //throw new Error("Initialization required")
204
- await this.initialize();
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
@@ -595,7 +605,8 @@ export class BeanBagDB {
595
605
  if (updates.meta) {
596
606
  let m_sch = sys_sch.editable_metadata_schema;
597
607
  let editable_fields = Object.keys(m_sch["properties"]);
598
- let allowed_meta = this.util_filter_object(updates.meta, editable_fields);
608
+ //let allowed_meta = this.util_filter_object(updates.meta, editable_fields);
609
+ let allowed_meta = {...full_doc["meta"], ...allowed_meta}
599
610
  allowed_meta = this.util_validate_data({schema:m_sch, data:allowed_meta});
600
611
  // if update has a link ,then check if it already exists
601
612
  if (allowed_meta.link){
@@ -610,9 +621,55 @@ export class BeanBagDB {
610
621
  }
611
622
  }
612
623
 
613
- full_doc["meta"] = { ...full_doc["meta"], ...allowed_meta };
624
+ full_doc["meta"] = {...allowed_meta} ;
614
625
  something_to_update = true
615
626
  }
627
+
628
+ /**
629
+ * to update app data
630
+ * app { key:{mode:"update|replace|append|remove",data:{}} }
631
+ */
632
+
633
+ if(updates.app){
634
+ if(!full_doc.app){ full_doc["app"]={}}
635
+ //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" `)}
636
+ Object.entries(updates.app).forEach(([appName, update]) => {
637
+ if (!update || typeof update !== 'object' || !update.mode || !update.data) {
638
+ console.warn(`Invalid update format for ${appName}`);
639
+ throw new DocUpdateError(`Invalid update format for app ${appName}. Must be an object {mode:"update|replace|append|remove", data:{} }`)
640
+ }
641
+ switch (update.mode) {
642
+ case 'update':
643
+ full_doc.app[appName] = {
644
+ ...full_doc.app[appName],
645
+ ...update.data
646
+ };
647
+ something_to_update = true
648
+ break;
649
+ case 'replace':
650
+ full_doc.app[appName] = update.data;
651
+ something_to_update = true
652
+ break;
653
+ case 'append':
654
+ Object.entries(update.data).forEach(([key, value]) => {
655
+ if (!Array.isArray(full_doc.app[appName]?.[key])) {
656
+ full_doc.app[appName] = full_doc.app[appName] || {};
657
+ full_doc.app[appName][key] = [];
658
+ }
659
+ full_doc.app[appName][key].push(value);
660
+ });
661
+ something_to_update = true
662
+ break;
663
+ case 'remove':
664
+ delete full_doc.app[appName];
665
+ something_to_update = true
666
+ break;
667
+ default:
668
+ throw new DocUpdateError( `Unknown mode: ${update.mode} app ${appName}. Must be an object {mode:"update|replace|append|remove", data:{} }`)
669
+ }
670
+ });
671
+ }
672
+
616
673
  if(something_to_update){
617
674
  // encrypt the data again since read returns decrypted data
618
675
  full_doc = await this._encrypt_doc(schema, full_doc);
@@ -767,26 +824,18 @@ export class BeanBagDB {
767
824
  * @param {string} plugin_name
768
825
  * @param {object} plugin_module
769
826
  */
770
- async load_plugin(plugin_name, plugin_module) {
827
+ async load_scripts(app_name, app_module) {
771
828
  this._check_ready_to_use();
772
- this.plugins[plugin_name] = {};
773
- //console.log(plugin_module)
774
- if(plugin_module.actions){
775
- for (let func_name in plugin_module.actions) {
776
- if (typeof plugin_module.actions[func_name] == "function") {
777
- this.plugins[plugin_name][func_name] = plugin_module.actions[func_name].bind(null,this)
829
+ this.apps[app_name] = {};
830
+ if(app_module){
831
+ for (let func_name in app_module) {
832
+ if (typeof app_module[func_name] == "function") {
833
+ this.apps[app_name][func_name] = app_module[func_name].bind(null,this)
778
834
  }
779
835
  }
836
+ }else{
837
+ console.log("app_module is blank")
780
838
  }
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
839
  }
791
840
 
792
841
  /**
@@ -900,7 +949,6 @@ async _create_edge(input){
900
949
  errors.push("max limit reached")
901
950
  }
902
951
  }
903
-
904
952
  if(errors.length==0){
905
953
  // let edge = await this.create({schema:"system_edge",data:})
906
954
  return {node1: node1id , node2: node2id ,edge_name:edge_name ,note:note,level_weight}
@@ -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 = `${schema_name} document - ${dt}`
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, meta = {}, settings = {}) {
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
 
@@ -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
  };
@@ -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==13)
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==9) // schema,book,setting,key,edge,edge_constraints
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