beanbagdb 0.5.77 → 0.6.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beanbagdb",
3
- "version": "0.5.77",
3
+ "version": "0.6.0",
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
@@ -85,6 +85,68 @@ export class BeanBagDB {
85
85
  //////////////////// Setup methods /////////////////////////////////////
86
86
  ////////////////////////////////////////////////////////////////////////
87
87
 
88
+ /**
89
+ * This is the list of methods that are compatible with JSON-REST API. Each command either has no params or takes just one json param as input
90
+ */
91
+ static rest_enabled = {
92
+ "ready":{
93
+ use: "Makes the database ready to use"
94
+ },
95
+ "metadata":{
96
+ use: "Returns metadata related to the current BeanBagDB instance "
97
+ },
98
+ "initialize_app":{
99
+ use:"To install/initialize an external app",
100
+ input: "{...app_data}"
101
+ },
102
+ "update_indexes":{
103
+ use:"Updates the indexes in the database for better searching"
104
+ },
105
+ "create":{
106
+ input:"{schema,data,meta}",
107
+ use:"Creates a new doc"
108
+
109
+ },
110
+ "read":{
111
+ input:"{criteria,include_schema:false}",
112
+ use:"Returns a doc. 3 ways to search for a doc : by _id, by link or by the primary key of the schema "
113
+ },
114
+ "update":{
115
+ input:"{criteria,updates}",
116
+ use:"Updates a document"
117
+ },
118
+ "delete":{
119
+ input:"{criteria}",
120
+ use:"Deletes a doc"
121
+ },
122
+ "search":{
123
+ input:"{criteria:{selector:{...}}}",
124
+ use:"To search in the database"
125
+ },
126
+ "get":{
127
+ input:"{type,criteria}",
128
+ use:"Returns special types of documents "
129
+ },
130
+ "create_edge":{
131
+ input:"{node1:{..criteria},node2:{..criteria},edge_name,edge_label}",
132
+ use:"Creates a new edge in the system's simple directed graph "
133
+ },
134
+ "util_get_now_unix_timestamp":{
135
+ use:"Returns the current UNIX timestamp"
136
+ },
137
+ "util_validate_data":{
138
+ input:"{schema:{},data:{}}",
139
+ use:"Validate the given data against the given schema and returns errors/validated doc"
140
+ },
141
+ "util_validate_schema_object":{
142
+ input:"{...schema_object...}",
143
+ use:"Validated the schema document without inserting it in the DB"
144
+
145
+ },
146
+ "util_generate_random_link":{
147
+ use:"Returns a random link"
148
+ }
149
+ }
88
150
  /**
89
151
  * Database object metadata
90
152
  * @typedef {Object} DBMetaData
@@ -162,8 +224,8 @@ export class BeanBagDB {
162
224
  // this works on its own but is usually called by ready automatically if required
163
225
  // check for schema_scehma : if yes, check if latest and upgrade if required, if no create a new schema doc
164
226
  try {
165
- let app_data = await this.initialize_db(sys_sch.default_app)
166
- console.log(app_data)
227
+ let app_data = await this.initialize_app(sys_sch.default_app)
228
+ // console.log(app_data)
167
229
  this.meta.beanbagdb_version_db = this._version;
168
230
  this.active = true;
169
231
  return app_data
@@ -175,14 +237,23 @@ export class BeanBagDB {
175
237
 
176
238
  }
177
239
 
178
- async initialize_db(app_data){
179
- // app_data : meta(name,description), schemas[] , default_records:[]
180
- // TODO check if add_data is valid
240
+ /**
241
+ * Install/Updates an app in the database.
242
+ * This should be called before using any
243
+ * @param {Object} app_data
244
+ */
245
+ async initialize_app(app_data_input){
181
246
  // calculate the app_version
247
+ if(!app_data_input){throw new Error("app_data_input is required")}
248
+ let app_data = this.util_validate_data({schema:sys_sch.app_data_schema,data:app_data_input})
182
249
  let latest_version = 0
183
- app_data.schemas.map(sch=>{latest_version = latest_version + sch.version})
250
+ app_data.schemas.map(sch=>{
251
+ latest_version = latest_version + sch.version
252
+ // update the source of schemas to the app
253
+ sch["settings"]["install_source"] = `app:${app_data.app_id}`
254
+ })
184
255
  app_data.records.map(sch=>{latest_version = latest_version + sch.version})
185
-
256
+
186
257
 
187
258
  // check if app setting record exists
188
259
  let version_search = await this.db_api.search({
@@ -191,6 +262,7 @@ export class BeanBagDB {
191
262
 
192
263
  let update_required = true
193
264
  let doc
265
+
194
266
  if (version_search.docs.length > 0) {
195
267
  doc = version_search.docs[0];
196
268
  if(doc["data"]["value"]["version"] == latest_version){
@@ -212,7 +284,7 @@ export class BeanBagDB {
212
284
  steps.push(`checking.${schema_name}`)
213
285
  try {
214
286
  // console.log(schema_name)
215
- let schema1 = await this.get("schema",{name:schema_name})
287
+ let schema1 = await this.get({type:"schema",criteria:{name:schema_name}})
216
288
  if (schema1["data"]["version"] != schema_data.version) {
217
289
  steps.push(`old.${schema_name}.v.${schema1["data"]["version"]}`);
218
290
  let full_doc = await this.db_api.get(schema1["_id"]);
@@ -257,7 +329,7 @@ export class BeanBagDB {
257
329
  const record_title = app_data.records[index]["title"]
258
330
  steps.push(`checking.records.${record_title}`)
259
331
  try {
260
- let new_doc = await this.create(schema_name,schema_data,app_data.records[index]["meta"])
332
+ let new_doc = await this.create({schema:schema_name,data:schema_data,meta:app_data.records[index]["meta"]})
261
333
  steps.push(`doc.${record_title}.created`)
262
334
  } catch (error) {
263
335
  if(!(error instanceof DocCreationError)){
@@ -266,10 +338,11 @@ export class BeanBagDB {
266
338
  }
267
339
  }
268
340
 
269
- let app_doc = { ... app_data.meta, version: latest_version}
341
+ let app_doc = { ... app_data.meta,app_id: app_data.app_id ,version: latest_version}
270
342
  try {
271
343
  // modify the app setting doc
272
- await this.modify_setting(app_data.meta.name,app_doc,"update")
344
+ // console.log(app_doc,)
345
+ await this.modify_setting(app_data.app_id,app_doc,"update")
273
346
 
274
347
  // add a new log
275
348
  let new_log_doc = this._get_blank_doc("system_log")
@@ -316,20 +389,28 @@ export class BeanBagDB {
316
389
  * This method validates the input data and schema before inserting a new document into the database.
317
390
  *
318
391
  * @async
319
- * @param {string} schema - The schema name for the document, e.g., "contact".
320
- * @param {object} data - The document data, e.g., { "name": "", "mobile": "", ... }.
321
- * @param {object} [meta={}] - Optional metadata associated with the document.
322
- * @param {object} [settings={}] - Optional settings that may affect document creation behavior.
392
+
393
+ * @param {object} input - The document details, e.g.,{ schema:"name",data: { "name": "", "mobile": "", ... }}.
394
+ * @param {string} [input.schema] - The schema name for the document, e.g., "contact".
395
+ * @param {object} [input.data={}] - the data for the document.
396
+ * @param {object} [input.meta={}] - Optional metadata associated with the document.
323
397
  * @returns {Promise<{id: string}>} - A promise that resolves with the newly inserted document's ID.
324
398
  * @throws {Error} - Throws an error if insertion checks fail or if there is an issue with the database operation.
325
399
  */
326
- async create(schema, data, meta = {}, settings = {}) {
400
+ async create(input) {
327
401
  this._check_ready_to_use();
328
- if(!schema){throw new DocCreationError(`No schema provided`)}
329
- if(schema=="setting_edge"){throw new DocCreationError("This type of record can only be created through the create_edge api")}
330
- if(Object.keys(data).length==0){throw new DocCreationError(`No data provided`)}
402
+
403
+ let v_errors = []
404
+ if(!input.schema){v_errors.push("schema is required")}
405
+ if(!input.data){v_errors.push("data is required")}
406
+ if(v_errors.length>0){
407
+ throw new DocCreationError(`${v_errors.join(",")}.`)
408
+ }
409
+
410
+ if(input.schema=="setting_edge"){throw new DocCreationError("This type of record can only be created through the create_edge api")}
411
+ if(Object.keys(input.data).length==0){throw new DocCreationError(`No data provided`)}
331
412
  try {
332
- let doc_obj = await this._insert_pre_checks(schema, data,meta, settings);
413
+ let doc_obj = await this._insert_pre_checks(input.schema, input.data,input?.meta||{}, input?.settings||{});
333
414
  let new_rec = await this.db_api.insert(doc_obj);
334
415
  return {_id:new_rec["id"],_rev : new_rec["rev"] ,...doc_obj};
335
416
  } catch (error) {
@@ -352,15 +433,14 @@ export class BeanBagDB {
352
433
  * @param {string} [criteria.link] - A unique link identifier for the document.
353
434
  * @param {string} [criteria.schema] - The schema name used when searching by primary keys.
354
435
  * @param {Object} [criteria.data] - Data object containing the schema's primary keys for search.
355
- *
356
- * @param {boolean} [include_schema=false] - Whether to include the schema object in the returned result.
436
+ * @param {string} [criteria.include_schema] - Whether to include the schema object in the returned result.
357
437
  *
358
438
  * @returns {Promise<Object>} - Returns an object with the document (`doc`) and optionally the schema (`schema`).
359
439
  *
360
440
  * @throws {DocNotFoundError} If no document is found for the given criteria.
361
441
  * @throws {ValidationError} If invalid search criteria are provided.
362
442
  */
363
- async read(criteria, include_schema = false) {
443
+ async read(criteria) {
364
444
  // todo : decrypt doc
365
445
  this._check_ready_to_use()
366
446
  let obj = { doc: null }
@@ -376,7 +456,7 @@ export class BeanBagDB {
376
456
  if (linkSearch.docs.length == 0) {throw new DocNotFoundError(BeanBagDB.error_codes.doc_not_found)}
377
457
  obj.doc = linkSearch.docs[0];
378
458
  } else if (criteria.hasOwnProperty("schema") & criteria.hasOwnProperty("data")) {
379
- data_schema = await this.get("schema",{"name":criteria.schema})
459
+ data_schema = await this.get({type:"schema",criteria:{"name":criteria.schema}})
380
460
  let A = data_schema["data"]["settings"]["primary_keys"];
381
461
  let search_criteria = { schema: criteria.schema };
382
462
  A.forEach((itm) => {
@@ -392,11 +472,14 @@ export class BeanBagDB {
392
472
  throw new ValidationError(`Invalid criteria to read a document. Valid ways : {"schema":"schema_name","data":{...primary key}} or {"_id":""} or {"link":""} `)
393
473
  }
394
474
  if (!data_schema){
395
- data_schema = await this.get("schema",{"name":obj.doc.schema})
475
+ data_schema = await this.get({type:"schema",criteria:{"name":obj.doc.schema}})
396
476
  }
397
- if(include_schema) {obj.schema = data_schema["data"]}
477
+
478
+ if(criteria.include_schema) {obj.schema = data_schema["data"]}
479
+
398
480
  // decrypt the document
399
481
  obj.doc = await this._decrypt_doc(data_schema["data"], obj.doc)
482
+
400
483
  return obj;
401
484
  }
402
485
 
@@ -413,11 +496,12 @@ export class BeanBagDB {
413
496
  * - Yes, but a validation check ensures that primary key policies are not violated before the update is applied.
414
497
  *
415
498
  *
416
- * @param {Object} doc_search_criteria - The criteria used to search for the document (e.g., {"_id": "document_id"}, {"link": "some_link"}, {"schema": "schema_name", "data": {primary_key_fields}}).
417
- * @param {String} rev_id - The document's revision ID (`_rev`) used for version control and conflict detection.
418
- * @param {Object} updates - The updated values for the document, structured as `{data: {}, meta: {}}`. Only the fields to be updated need to be provided.
419
- * @param {String} [update_source="api"] - Identifies the source of the update (default: "api").
420
- * @param {Boolean} [save_conflict=true] - If `true`, conflicting updates will be saved separately in case of revision mismatches.
499
+ * @param {Object} params - Object to fetch and update data
500
+ * @param {Object} [params.criteria] - The criteria used to search for the document (e.g., {"_id": "document_id"}, {"link": "some_link"}, {"schema": "schema_name", "data": {primary_key_fields}}).
501
+ * @param {Object} [params.updates] - The updated values for the document, structured as `{data: {}, meta: {}}`. Only the fields to be updated need to be provided.
502
+ * @param {String} [params.rev_id] - The document's revision ID (`_rev`) used for version control and conflict detection.
503
+ * @param {String} [params.update_source="api"] - Identifies the source of the update (default: "api").
504
+ * @param {Boolean} [params.save_conflict=true] - If `true`, conflicting updates will be saved separately in case of revision mismatches.
421
505
  *
422
506
  * **Behavior**:
423
507
  * - Retrieves the document based on the provided search criteria.
@@ -436,11 +520,24 @@ export class BeanBagDB {
436
520
  * @throws {DocUpdateError} - If a document with conflicting primary keys already exists.
437
521
  * @throws {ValidationError} - If the provided data or metadata is invalid according to the schema.
438
522
  */
439
- async update(doc_search_criteria, updates, rev_id="", update_source = "api", save_conflict = true) {
523
+ async update(params) {
524
+
440
525
  this._check_ready_to_use();
526
+
527
+ const {
528
+ criteria,
529
+ updates,
530
+ rev_id = "",
531
+ update_source = "api",
532
+ save_conflict = true
533
+ } = params;
534
+
535
+ if(!criteria){throw new DocUpdateError("Doc search criteria not provided")}
536
+ if(!updates){throw new DocUpdateError("No updates provided")}
537
+
441
538
  // making a big assumption here : primary key fields cannot be edited
442
539
  // so updating the doc will not generate primary key conflicts
443
- let req_data = await this.read(doc_search_criteria, true);
540
+ let req_data = await this.read({...criteria, include_schema: true});
444
541
  let schema = req_data.schema;
445
542
  let full_doc = req_data.doc;
446
543
  // @TODO fix this : what to do if the rev id does not match
@@ -451,6 +548,11 @@ export class BeanBagDB {
451
548
  // }
452
549
  // }
453
550
 
551
+ // system generated schemas cannot be edited
552
+ if(full_doc.schema=="schema"&&full_doc.data.system_generated==true){
553
+ throw new DocUpdateError("System schemas cannot be updated using this API");
554
+ }
555
+
454
556
  // update new value depending on settings.non_editable_fields (if does not exists, all fields are editable)
455
557
  let all_fields = Object.keys(schema.schema.properties);
456
558
  let unedit_fields = schema.settings["non_editable_fields"];
@@ -462,7 +564,7 @@ export class BeanBagDB {
462
564
  // todo : what if additionalField are allowed ??
463
565
  let updated_data = { ...full_doc.data, ...allowed_updates };
464
566
 
465
- this.util_validate_data(schema.schema, updated_data);
567
+ updated_data = this.util_validate_data({schema:schema.schema,data: updated_data});
466
568
 
467
569
  // primary key check if multiple records can be created
468
570
  if (schema.settings["primary_keys"].length > 0) {
@@ -489,7 +591,7 @@ export class BeanBagDB {
489
591
  let m_sch = sys_sch.editable_metadata_schema;
490
592
  let editable_fields = Object.keys(m_sch["properties"]);
491
593
  let allowed_meta = this.util_filter_object(updates.meta, editable_fields);
492
- this.util_validate_data(m_sch, allowed_meta);
594
+ allowed_meta = this.util_validate_data({schema:m_sch, data:allowed_meta});
493
595
  // if update has a link ,then check if it already exists
494
596
  if (allowed_meta.link){
495
597
  let search = await this.search({ selector: {"meta.link":allowed_meta.link} })
@@ -520,50 +622,7 @@ export class BeanBagDB {
520
622
  }
521
623
 
522
624
 
523
- /**
524
- * Check if the setting with the given name exists. New record created if not found. If found data is updated based on the updated_mode and the data type of the existing data
525
- * If existing value is an array, and update_mode is append "value" is appended to the current value array.
526
- * if existing value is an object, update_mode "append" will update fields that exists in the new object,
527
- * for both data types, new value is replaced in update_mode : "replace"
528
- * @param {string} name The name of the setting
529
- * @param {object} value Value to be modified
530
- * @param {string} mode
531
- */
532
- async modify_setting(name,value,update_mode){
533
- if(!name||!value||!update_mode){
534
- throw new DocUpdateError("All 3 inputs (setting name, value and update_mode) are required")
535
- }
536
- let doc_search = await this.db_api.search({
537
- selector: { schema: "system_setting", "data.name": name },
538
- });
539
-
540
- if (!["append", "update"].includes(update_mode)) {
541
- throw new DocUpdateError("Invalid update_mode");
542
- }
543
-
544
- if (doc_search.docs.length > 0) {
545
- // doc already exists,
546
- let doc = { ...doc_search.docs[0] };
547
- if (Array.isArray(value)) {
548
- doc.data.value = update_mode === "append" ? [...doc.data.value, value] : value; // "update" mode replaces the value
549
- } else {
550
- doc.data.value = update_mode === "append" ? { ...doc.data.value, ...value } : value; // "update" mode replaces the value
551
- }
552
- // finally update it
553
- doc["meta"]["updated_on"] = this.util_get_now_unix_timestamp();
554
- // caution : db api is being used directly
555
- await this.db_api.update(doc);
556
- return doc;
557
625
 
558
- } else {
559
- // doc does not exists, generate a new one
560
- let new_log_doc = this._get_blank_doc("system_setting")
561
- new_log_doc.data = {value, name}
562
- await this.db_api.insert(new_log_doc);
563
-
564
-
565
- }
566
- }
567
626
 
568
627
  /**
569
628
  * Deletes a document from the database by its ID.
@@ -575,7 +634,7 @@ export class BeanBagDB {
575
634
  async delete(criteria) {
576
635
  this._check_ready_to_use();
577
636
  let doc = await this.read(criteria)
578
- const delete_blocked = ["schema","setting","key"]
637
+ const delete_blocked = ["schema","system_setting","system_log"]
579
638
  if (delete_blocked.includes(doc.schema)){
580
639
  throw new Error(`Deletion of ${doc.schema} doc is not support yet.`)
581
640
  }
@@ -611,9 +670,11 @@ export class BeanBagDB {
611
670
  * for a given schema. It handles system-related data and throws errors for invalid document types
612
671
  * or if the document is not found.
613
672
  *
614
- * @param {String} special_doc_type - The type of special document to fetch. Supported types include:
673
+ * @param {Object} [input={}] - Criteria used to search for the special document.
674
+
675
+ * @param {String} input.type - The type of special document to fetch. Supported types include:
615
676
  * - 'schema': Retrieves a schema document based on the criteria provided.
616
- * @param {Object} [criteria={}] - Criteria used to search for the special document.
677
+ * @param {Object} [input.criteria={}] - Criteria used to search for the special document.
617
678
  * For example, to search for a schema, the criteria should include the name.
618
679
  *
619
680
  * @throws {ValidationError} Throws if the `special_doc_type` is not recognized.
@@ -621,7 +682,8 @@ export class BeanBagDB {
621
682
  *
622
683
  * @returns {Object} The fetched special document based on the type and criteria.
623
684
  */
624
- async get(special_doc_type,criteria={}){
685
+ async get(input){
686
+
625
687
  // this method returns special types of documents such as schema doc, or a blank doc for a given schema and other system related things
626
688
  const fetch_docs = {
627
689
  // to return schema object for the given name
@@ -652,6 +714,7 @@ export class BeanBagDB {
652
714
  system_defined : doc.data.system_generated,
653
715
  description: doc.data.description,
654
716
  link: doc.meta.link,
717
+ title:doc.data.title,
655
718
  _id:doc._id
656
719
  })
657
720
  })
@@ -660,14 +723,19 @@ export class BeanBagDB {
660
723
 
661
724
  }
662
725
  }
663
- if(Object.keys(fetch_docs).includes(special_doc_type)){
664
- let data = await fetch_docs[special_doc_type](criteria)
726
+ if(!input.type){throw new ValidationError("No type provided. Must be: "+Object.keys(fetch_docs).join(","))}
727
+ if(Object.keys(fetch_docs).includes(input.type)){
728
+ let data = await fetch_docs[input.type](input?.criteria||{})
665
729
  return data
666
730
  }else{
667
- throw new ValidationError("Invalid special doc type. Must be : "+Object.keys(fetch_docs).join(","))
731
+ throw new ValidationError("Invalid name. Must be : "+Object.keys(fetch_docs).join(","))
668
732
  }
669
733
  }
670
734
 
735
+
736
+ //////////////////// methods for special use , requires to be called using the class (rather than the rest api)
737
+
738
+
671
739
  /**
672
740
  * To load a plugin in the current BeanBagDB instance.
673
741
  * Plug_module has to be loaded manually first. It must export an object containing fields: `actions` and `schema`.
@@ -699,6 +767,51 @@ export class BeanBagDB {
699
767
  // }
700
768
  }
701
769
 
770
+ /**
771
+ * Check if the setting with the given name exists. New record created if not found. If found data is updated based on the updated_mode and the data type of the existing data
772
+ * If existing value is an array, and update_mode is append "value" is appended to the current value array.
773
+ * if existing value is an object, update_mode "append" will update fields that exists in the new object,
774
+ * for both data types, new value is replaced in update_mode : "replace"
775
+ * @param {string} name The name of the setting
776
+ * @param {object} value Value to be modified
777
+ * @param {string} mode
778
+ */
779
+ async modify_setting(name,value,update_mode){
780
+ if(!name||!value||!update_mode){
781
+ throw new DocUpdateError("All 3 inputs (setting name, value and update_mode) are required")
782
+ }
783
+ let doc_search = await this.db_api.search({
784
+ selector: { schema: "system_setting", "data.name": name },
785
+ });
786
+
787
+ if (!["append", "update"].includes(update_mode)) {
788
+ throw new DocUpdateError("Invalid update_mode");
789
+ }
790
+
791
+ if (doc_search.docs.length > 0) {
792
+ // doc already exists,
793
+ let doc = { ...doc_search.docs[0] };
794
+ if (Array.isArray(value)) {
795
+ doc.data.value = update_mode === "append" ? [...doc.data.value, value] : value; // "update" mode replaces the value
796
+ } else {
797
+ doc.data.value = update_mode === "append" ? { ...doc.data.value, ...value } : value; // "update" mode replaces the value
798
+ }
799
+ // finally update it
800
+ doc["meta"]["updated_on"] = this.util_get_now_unix_timestamp();
801
+ // caution : db api is being used directly
802
+ await this.db_api.update(doc);
803
+ return doc;
804
+
805
+ } else {
806
+ // doc does not exists, generate a new one
807
+ let new_log_doc = this._get_blank_doc("system_setting")
808
+ new_log_doc.data = {value, name}
809
+ await this.db_api.insert(new_log_doc);
810
+
811
+
812
+ }
813
+ }
814
+
702
815
  ///////////////////////////////////////////////////////////
703
816
  //////////////// simple directed graph ////////////////////////
704
817
  //////////////////////////////////////////////////////////
@@ -711,7 +824,8 @@ export class BeanBagDB {
711
824
  * @param {*} edge_label
712
825
  * @returns {Object}
713
826
  */
714
- async create_edge(node1,node2,edge_name,edge_label=""){
827
+ async create_edge(input){
828
+ const {node1,node2,edge_name,edge_label=""} = input
715
829
  this._check_ready_to_use();
716
830
  if(!edge_name){throw new ValidationError("edge_name required")}
717
831
  if(Object.keys(node1)==0){throw new ValidationError("node1 required")}
@@ -756,7 +870,7 @@ async create_edge(node1,node2,edge_name,edge_label=""){
756
870
  }
757
871
 
758
872
  if(errors.length==0){
759
- let edge = await this.create("system_edge",{node1: node1id , node2: node1id ,edge_name:edge_name })
873
+ let edge = await this.create({schema:"system_edge",data:{node1: node1id , node2: node1id ,edge_name:edge_name }})
760
874
  return edge
761
875
  }else{
762
876
  throw new RelationError(errors)
@@ -765,8 +879,8 @@ async create_edge(node1,node2,edge_name,edge_label=""){
765
879
  } catch (error) {
766
880
  if(error instanceof DocNotFoundError){
767
881
  let doc = {node1:"*",node2:"*",name:edge_name,label:edge_label}
768
- let new_doc = await this.create("system_edge_constraint",doc)
769
- let edge = await this.create("system_edge",{node1: n1.doc._id,node2: n2.doc._id,edge_name:edge_name })
882
+ let new_doc = await this.create({schema:"system_edge_constraint",data:doc})
883
+ let edge = await this.create({schema:"system_edge",data:{node1: n1.doc._id,node2: n2.doc._id,edge_name:edge_name }})
770
884
  return edge
771
885
  }else{
772
886
  throw error
@@ -835,7 +949,7 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
835
949
  const schema_data = schemas[index]
836
950
  steps.push(`checking.${schema_name}`)
837
951
  try {
838
- let schema1 = await this.get("schema",{name:schema_name})
952
+ let schema1 = await this.get({type:"schema",criteria:{name:schema_name}})
839
953
  if (schema1["data"]["version"] != schema_data.version) {
840
954
  steps.push(`old.${schema_name}.v.${schema1["data"]["version"]}`);
841
955
  let full_doc = await this.db_api.get(schema1["_id"]);
@@ -951,9 +1065,9 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
951
1065
  * @returns {Object}
952
1066
  */
953
1067
  _get_blank_schema_doc(schema_name, schema_object, data) {
954
- this.util_validate_data(schema_object, data);
1068
+ let new_data = this.util_validate_data({schema:schema_object, data});
955
1069
  let obj = this._get_blank_doc(schema_name);
956
- obj["data"] = data;
1070
+ obj["data"] = new_data;
957
1071
  return obj;
958
1072
  }
959
1073
 
@@ -1024,11 +1138,13 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1024
1138
  if (sch_search.docs.length == 0) {throw new DocCreationError(`The schema "${schema}" does not exists`)}
1025
1139
  let schemaDoc = sch_search.docs[0]["data"];
1026
1140
  // validate data
1027
- this.util_validate_data(schemaDoc.schema, data);
1141
+ if(!schemaDoc.active){throw new DocCreationError(`The schema "${schema}" is not active`)}
1142
+
1143
+ let new_data = this.util_validate_data({schema:schemaDoc.schema, data});
1028
1144
 
1029
1145
  // validate meta
1030
- if(Object.keys.length>0){
1031
- this.util_validate_data(sys_sch.editable_metadata_schema, meta)
1146
+ if(Object.keys(meta).length>0){
1147
+ meta = this.util_validate_data({schema:sys_sch.editable_metadata_schema, data:meta})
1032
1148
  }
1033
1149
 
1034
1150
 
@@ -1042,25 +1158,25 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1042
1158
  // @TODO : for schema dos: settings fields must be in schema field
1043
1159
  if (schema == "schema") {
1044
1160
  //more checks are required
1045
- this.util_validate_schema_object(data);
1161
+ this.util_validate_schema_object(new_data);
1046
1162
  }
1047
1163
  // @TODO : check if single record setting is set to true
1048
1164
  //console.log(schemaDoc)
1049
1165
  // duplicate check
1050
1166
  if (schemaDoc.settings["primary_keys"].length > 0) {
1051
1167
  let primary_obj = { schema: schema };
1052
- schemaDoc.settings["primary_keys"].map((ky) => {primary_obj["data." + ky] = data[ky];});
1168
+ schemaDoc.settings["primary_keys"].map((ky) => {primary_obj["data." + ky] = new_data[ky];});
1053
1169
  let prim_search = await this.search({ selector: primary_obj });
1054
1170
  if (prim_search.docs.length > 0) {
1055
1171
  throw new DocCreationError(`Document with the given primary key (${schemaDoc.settings["primary_keys"].join(",")}) already exists in the schema "${schema}"`);
1056
1172
  }
1057
1173
  }
1058
1174
  // encrypt if required
1059
- let new_data = { ...data };
1175
+
1060
1176
  if (schemaDoc.settings["encrypted_fields"].length > 0) {
1061
1177
  // todo test if encryption is successful
1062
1178
  for (let itm of schemaDoc.settings["encrypted_fields"]) {
1063
- new_data[itm] = await this.utils.encrypt(data[itm], this.encryption_key);
1179
+ new_data[itm] = await this.utils.encrypt(new_data[itm], this.encryption_key);
1064
1180
  }
1065
1181
  }
1066
1182
 
@@ -1086,29 +1202,14 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1086
1202
  */
1087
1203
  util_get_now_unix_timestamp() {return Math.floor(Date.now() / 1000)}
1088
1204
 
1089
- /**
1090
- * Validates that the required fields are present in the provided object.
1091
- *
1092
- * @param {string[]} requiredFields - An array of field names that are required.
1093
- * @param {object} obj - The object to check for the required fields.
1094
- * @throws {ValidationError} If any of the required fields are missing, an error is thrown.
1095
- */
1205
+
1096
1206
  util_check_required_fields(requiredFields, obj) {
1097
1207
  for (const field of requiredFields) {
1098
1208
  if (!obj[field]) {throw new ValidationError(`The field ${field} is required.`)}
1099
1209
  }
1100
1210
  }
1101
1211
 
1102
- /**
1103
- * Filters an object, returning a new object that only contains the specified fields.
1104
- *
1105
- * @param {Object} obj - The object to filter.
1106
- * @param {Array<String>} fields - An array of field names to retain in the filtered object.
1107
- *
1108
- * @returns {Object} - A new object containing only the fields that exist in `obj` from the `fields` array.
1109
- *
1110
- * **Example**:
1111
- *
1212
+ /** Filters an object, returning a new object that only contains the specified fields.
1112
1213
  * const data = { name: "Alice", age: 25, location: "NY" };
1113
1214
  * const result = util_filter_object(data, ["name", "age"]);
1114
1215
  * // result: { name: "Alice", age: 25 }
@@ -1122,18 +1223,22 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1122
1223
  }, {});
1123
1224
  }
1124
1225
 
1125
-
1126
1226
  /**
1127
- * Validates a data object against a provided JSON schema
1227
+ * Validates a data object against a provided JSON schema and returns a valid data object (with default value for missing field for which default values are defined in the schema )
1128
1228
  * It relies on the external API provided by the user
1129
1229
  * @param {Object} schema_obj - The JSON schema object to validate against
1130
1230
  * @param {Object} data_obj - The data object to validate
1131
1231
  * @throws {Error} If the data object does not conform to the schema
1132
1232
  */
1133
- util_validate_data(schema_obj, data_obj) {
1134
- const { valid, validate } = this.utils.validate_schema(schema_obj,data_obj)
1233
+ util_validate_data(input) {
1234
+ if(!input.schema){throw new ValidationError("schema is required")}
1235
+ if(!input.data){throw new ValidationError("data is required")}
1236
+
1237
+ const { valid, validate , data} = this.utils.validate_schema(input.schema,input.data)
1135
1238
  if (!valid) {
1136
1239
  throw new ValidationError(validate.errors);
1240
+ }else{
1241
+ return data
1137
1242
  }
1138
1243
  }
1139
1244
 
@@ -1248,7 +1353,7 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1248
1353
  * "banana-earth-rain".
1249
1354
  *
1250
1355
  */
1251
- util_generate_random_link(type=1) {
1356
+ util_generate_random_link(input={type:1}) {
1252
1357
  const options = {
1253
1358
  0:()=>{
1254
1359
  // prettier-ignore
@@ -1262,7 +1367,7 @@ async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgr
1262
1367
 
1263
1368
  }
1264
1369
  }
1265
- return options[type]()
1370
+ return options[input.type]()
1266
1371
  }
1267
1372
  }
1268
1373