beanbagdb 0.8.3 → 0.8.5
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 +83 -1
- package/src/system_schema.js +35 -2
- package/test/operations.test.js +18 -0
- package/test/pouchdb.js +5 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -39,11 +39,12 @@ export class BeanBagDB {
|
|
|
39
39
|
* @param {function} db_instance.utils.decrypt - Decrypts a document.
|
|
40
40
|
* @param {function} db_instance.utils.ping - Checks the database connection.
|
|
41
41
|
* @param {function} db_instance.utils.validate_schema - Validates the database schema.
|
|
42
|
+
* @param {function} db_instance.utils.compile_template - Compiles a text template with data. {}
|
|
42
43
|
*/
|
|
43
44
|
constructor(db_instance) {
|
|
44
45
|
this.util_check_required_fields(["name", "encryption_key", "api", "utils", "db_name"],db_instance)
|
|
45
46
|
this.util_check_required_fields(["insert", "update", "delete", "search", "get", "createIndex"],db_instance.api)
|
|
46
|
-
this.util_check_required_fields(["encrypt", "decrypt", "ping", "validate_schema"],db_instance.utils)
|
|
47
|
+
this.util_check_required_fields(["encrypt", "decrypt", "ping", "validate_schema","compile_template"],db_instance.utils)
|
|
47
48
|
|
|
48
49
|
if (db_instance.encryption_key.length < 20) {
|
|
49
50
|
throw new ValidationError([{ message: BeanBagDB.error_codes.key_short }]);
|
|
@@ -445,6 +446,7 @@ export class BeanBagDB {
|
|
|
445
446
|
* @param {string} [criteria.schema] - The schema name used when searching by primary keys.
|
|
446
447
|
* @param {Object} [criteria.data] - Data object containing the schema's primary keys for search.
|
|
447
448
|
* @param {string} [criteria.include_schema] - Whether to include the schema object in the returned result.
|
|
449
|
+
* @param {string} [criteria.text_template] - The name of the text template. If provided, an additional field called 'view' is returned with the document in the specified text format.
|
|
448
450
|
*
|
|
449
451
|
* @returns {Promise<Object>} - Returns an object with the document (`doc`) and optionally the schema (`schema`).
|
|
450
452
|
*
|
|
@@ -491,6 +493,12 @@ export class BeanBagDB {
|
|
|
491
493
|
// decrypt the document
|
|
492
494
|
obj.doc = await this._decrypt_doc(data_schema["data"], obj.doc)
|
|
493
495
|
|
|
496
|
+
if(criteria.text_template){
|
|
497
|
+
let doc_view = this._compile_template(criteria.text_template,data_schema["data"],obj.doc)
|
|
498
|
+
obj["view"] = doc_view
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
|
|
494
502
|
return obj;
|
|
495
503
|
}
|
|
496
504
|
|
|
@@ -1045,6 +1053,80 @@ _check_nodes_edge(node1Rule, node2Rule, schema1, schema2) {
|
|
|
1045
1053
|
//////////////// Internal methods ////////////////////////
|
|
1046
1054
|
//////////////////////////////////////////////////////////
|
|
1047
1055
|
|
|
1056
|
+
_compile_template(template_name,schema_doc,doc_obj){
|
|
1057
|
+
/**
|
|
1058
|
+
* generates text for the doc by compiling the provided template.
|
|
1059
|
+
*/
|
|
1060
|
+
try {
|
|
1061
|
+
if(!template_name||!schema_doc||!doc_obj){
|
|
1062
|
+
throw new Error("Incomplete info provided")
|
|
1063
|
+
}
|
|
1064
|
+
let template_info = schema_doc.settings?.text_templates[template_name]
|
|
1065
|
+
if(!template_info){
|
|
1066
|
+
throw Error("Template not found")
|
|
1067
|
+
}
|
|
1068
|
+
if (template_info.engine == "js_script") {
|
|
1069
|
+
|
|
1070
|
+
const runScript = (script, data) => {
|
|
1071
|
+
const cleanScript = script
|
|
1072
|
+
.replace(/\\n/g, '\n')
|
|
1073
|
+
.replace(/\\t/g, '\t')
|
|
1074
|
+
.trim();
|
|
1075
|
+
|
|
1076
|
+
if (!cleanScript) {
|
|
1077
|
+
throw new Error("Empty script provided");
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const funcBody = `
|
|
1081
|
+
"use strict";
|
|
1082
|
+
const {doc, schema} = arguments[0] || {};
|
|
1083
|
+
${cleanScript}
|
|
1084
|
+
`;
|
|
1085
|
+
|
|
1086
|
+
try {
|
|
1087
|
+
const func = new Function(funcBody);
|
|
1088
|
+
const result = func(data);
|
|
1089
|
+
if (result && typeof result.text === 'string') {
|
|
1090
|
+
return result;
|
|
1091
|
+
}
|
|
1092
|
+
throw new Error("Script must return {text: '...'}");
|
|
1093
|
+
} catch (parseError) {
|
|
1094
|
+
throw new Error(`Script parse error: ${parseError.message}\nScript: ${cleanScript.substring(0, 100)}...`);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
|
|
1098
|
+
let result = runScript(template_info.template, {
|
|
1099
|
+
doc: doc_obj,
|
|
1100
|
+
schema: schema_doc,
|
|
1101
|
+
});
|
|
1102
|
+
// if (!result.text) {
|
|
1103
|
+
// throw new Error("js_script template must return {'text': '...'}");
|
|
1104
|
+
// }
|
|
1105
|
+
return result.text;
|
|
1106
|
+
} else if (this.utils.compile_template[template_info.engine]) {
|
|
1107
|
+
let result = this.utils.compile_template[template_info.engine](
|
|
1108
|
+
template_info.template,
|
|
1109
|
+
{
|
|
1110
|
+
doc: doc_obj,
|
|
1111
|
+
schema: schema_doc,
|
|
1112
|
+
},
|
|
1113
|
+
);
|
|
1114
|
+
if (!result.text) {
|
|
1115
|
+
throw new Error(`${template_name} template must return {'text': '...'}`);
|
|
1116
|
+
}
|
|
1117
|
+
return result.text
|
|
1118
|
+
} else {
|
|
1119
|
+
throw Error(
|
|
1120
|
+
`The engine ${template_info.engine} is not available in the current instance of BBDB.`,
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
let text = `Unable to compile the template ${template_name}.Error: ${error.message}`
|
|
1126
|
+
return text
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1048
1130
|
|
|
1049
1131
|
async _upgrade_schema_in_bulk(schemas,log_upgrade=false,log_message="Schema Upgrade in bulk"){
|
|
1050
1132
|
// TODO add a check to now allow default system schema to be updated from this method
|
package/src/system_schema.js
CHANGED
|
@@ -11,7 +11,7 @@ export const default_app = {
|
|
|
11
11
|
active: true,
|
|
12
12
|
description: "Meta-schema or the schema for defining other schemas",
|
|
13
13
|
system_generated: true,
|
|
14
|
-
version: 1.
|
|
14
|
+
version: 1.30,
|
|
15
15
|
title: "Schema document",
|
|
16
16
|
schema: {
|
|
17
17
|
type: "object",
|
|
@@ -133,6 +133,39 @@ export const default_app = {
|
|
|
133
133
|
default: "human",
|
|
134
134
|
description:
|
|
135
135
|
"The height and width should be 25px",
|
|
136
|
+
},
|
|
137
|
+
text_templates: {
|
|
138
|
+
"type": "object",
|
|
139
|
+
"title":"Text templates for the schema",
|
|
140
|
+
"description":"Define templates that compile and generate text for an individual document in the database",
|
|
141
|
+
"default":{ "json_string":{engine:"js_script","format":"plain",template: "const pretty = JSON.stringify(doc, null, 2);\nreturn {text: pretty};","description":"Generates a stringified JSON as plain text"} },
|
|
142
|
+
"patternProperties": {
|
|
143
|
+
"^[a-zA-Z_][a-zA-Z0-9_]*$": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"required": ["engine", "template"],
|
|
146
|
+
"properties": {
|
|
147
|
+
"engine": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"enum": ["handlebars","ejs","js_script","mustache"],
|
|
150
|
+
"description": "The templating engine used to render the template. js_script is when the template is code in javascript. All template compiler must returns an object `{text:'...'}`"
|
|
151
|
+
},
|
|
152
|
+
"format": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"description": "The output format of the template. Eg plain,markdown,html,tex"
|
|
155
|
+
},
|
|
156
|
+
"description": {
|
|
157
|
+
"type": "string",
|
|
158
|
+
"description": "A human-readable description of the template"
|
|
159
|
+
},
|
|
160
|
+
"template": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"description": "The actual template string (must be compatible with the selected engine). Assume that the engine has access to the following json: { doc:{meta, data, app, _schema, schema, id} , ... other related data}"
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
"additionalProperties": false
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"additionalProperties": false,
|
|
136
169
|
}
|
|
137
170
|
},
|
|
138
171
|
required: [
|
|
@@ -390,7 +423,7 @@ export const default_app = {
|
|
|
390
423
|
schema: {
|
|
391
424
|
type: "object",
|
|
392
425
|
additionalProperties: true,
|
|
393
|
-
required: ["script","type","version"],
|
|
426
|
+
required: ["script","type","version","name"],
|
|
394
427
|
properties: {
|
|
395
428
|
type: {
|
|
396
429
|
type: "string",
|
package/test/operations.test.js
CHANGED
|
@@ -1040,6 +1040,24 @@ describe("Doc read tests", async () => {
|
|
|
1040
1040
|
let data = await database3.read({schema:"book",data:{"title":record_good_book1.title,"author":record_good_book1.author},include_schema:false})
|
|
1041
1041
|
assert(Object.keys(data).length==1)
|
|
1042
1042
|
})
|
|
1043
|
+
|
|
1044
|
+
it('check if view is not included', async () => {
|
|
1045
|
+
let data = await database3.read({schema:"book",data:{"title":record_good_book1.title,"author":record_good_book1.author}})
|
|
1046
|
+
assert(!data.view, "view property should not exist");
|
|
1047
|
+
})
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
it('check if view is included even if template name not found', async () => {
|
|
1051
|
+
let data = await database3.read({schema:"book",data:{"title":record_good_book1.title,"author":record_good_book1.author},text_template:"json"})
|
|
1052
|
+
console.log(data)
|
|
1053
|
+
assert('view' in data);
|
|
1054
|
+
})
|
|
1055
|
+
|
|
1056
|
+
it('check if view is included , template name is found', async () => {
|
|
1057
|
+
let data = await database3.read({schema:"book",data:{"title":record_good_book1.title,"author":record_good_book1.author},text_template:"json_string"})
|
|
1058
|
+
console.log(data)
|
|
1059
|
+
assert('view' in data);
|
|
1060
|
+
})
|
|
1043
1061
|
})
|
|
1044
1062
|
|
|
1045
1063
|
/**
|