beanbagdb 0.5.52 → 0.5.54
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/doc-src/3_plugins.md +23 -1
- package/package.json +3 -2
- package/src/index.js +284 -265
- package/src/plugins/text_command.js +193 -0
- package/src/system_schema.js +34 -4
- package/test/couchdb.js +2 -2
- package/test/operations.test.js +1687 -286
- package/test/plugin.test.js +55 -0
- package/test/pouchdb.js +12 -6
- package/test/test1.js +146 -161
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const commands = {
|
|
5
|
+
new: {
|
|
6
|
+
parse: async (instance,parts) => {
|
|
7
|
+
let criteria = {}
|
|
8
|
+
criteria.schema = parts.length==0?"":parts.join("")
|
|
9
|
+
return criteria
|
|
10
|
+
},
|
|
11
|
+
run: async (instance,command) => {
|
|
12
|
+
if (command.criteria.schema==""){
|
|
13
|
+
// return a list of all schemas present in the DB
|
|
14
|
+
let all_schema = await instance.get("schema_list")
|
|
15
|
+
return all_schema
|
|
16
|
+
}else{
|
|
17
|
+
// return the schema object for the given schema if not found throw error
|
|
18
|
+
let schema_obj = await instance.search({"selector":{"schema":"schema","data.name":command.criteria.schema}})
|
|
19
|
+
//console.log(schema_obj)
|
|
20
|
+
if(schema_obj.docs.length==0){
|
|
21
|
+
throw new Error("Schema with this name does not exists")
|
|
22
|
+
}
|
|
23
|
+
return schema_obj.docs[0]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
help: `To create a new record. Format : new/"schema_name(optional)". If no schema name provided, a list of valid schema name is returned`
|
|
27
|
+
},
|
|
28
|
+
open:{
|
|
29
|
+
parse: async (instance,parts) => {
|
|
30
|
+
let criteria = {}
|
|
31
|
+
if (parts.length==0){
|
|
32
|
+
throw new Error("Invalid arguments.open command needs unique id")
|
|
33
|
+
}
|
|
34
|
+
let id_type = parts[0]
|
|
35
|
+
if(id_type=="id"){
|
|
36
|
+
parts.shift()
|
|
37
|
+
criteria["_id"] = parts.join("")
|
|
38
|
+
}else if(id_type=="link"){
|
|
39
|
+
parts.shift()
|
|
40
|
+
criteria["link"] = parts.join("")
|
|
41
|
+
}else if(id_type=="key"){
|
|
42
|
+
parts.shift()
|
|
43
|
+
let text= parts.join()
|
|
44
|
+
let p = text.split(",")
|
|
45
|
+
|
|
46
|
+
p.map(itm=>{
|
|
47
|
+
let p1 = itm.split("=")
|
|
48
|
+
if(p1[0]=="schema"){
|
|
49
|
+
criteria["schema"] = p1[1]
|
|
50
|
+
}else{
|
|
51
|
+
criteria["data"][p1[0]] = p1[1]
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if(!criteria["schema"]){
|
|
56
|
+
throw new Error("Key requires a schema")
|
|
57
|
+
}
|
|
58
|
+
}else{
|
|
59
|
+
throw new Error("Invalid unique key")
|
|
60
|
+
}
|
|
61
|
+
return criteria
|
|
62
|
+
},
|
|
63
|
+
run: async (instance,command) => {
|
|
64
|
+
try {
|
|
65
|
+
let data = await instance.read(command.criteria,true)
|
|
66
|
+
return data
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw error
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
help: `To open a record using it's unique id. Format : open/"id||link|key"/"value". In case of key field name must be provided as : field1=value1,fields2=value2...`
|
|
72
|
+
},
|
|
73
|
+
tool:{
|
|
74
|
+
parse : async (instance,parts)=>{
|
|
75
|
+
let criteria = {}
|
|
76
|
+
criteria.type = parts.length==0?"info":parts.join("")
|
|
77
|
+
return criteria
|
|
78
|
+
},
|
|
79
|
+
run : async (instance,command)=>{
|
|
80
|
+
let c_type = command.criteria.type
|
|
81
|
+
let data = {}
|
|
82
|
+
if (c_type=="info"){
|
|
83
|
+
// to get all basic info about the database
|
|
84
|
+
let data = {
|
|
85
|
+
meta: instance.metadata(),
|
|
86
|
+
schemas : {},
|
|
87
|
+
logs:[]
|
|
88
|
+
}
|
|
89
|
+
let schemas = await instance.get("schema_list")
|
|
90
|
+
data.schemas = schemas
|
|
91
|
+
|
|
92
|
+
let logs_doc = await instance.read({"schema":"system_settings","data":{name:"system_logs"}})
|
|
93
|
+
//console.log(logs_doc)
|
|
94
|
+
data =logs_doc.doc.data.value
|
|
95
|
+
return data
|
|
96
|
+
|
|
97
|
+
}else if(c_type=="plugins"){
|
|
98
|
+
// to show list of all plugins installed
|
|
99
|
+
// todo later not implemented yet
|
|
100
|
+
}else if(c_type=="settings"){
|
|
101
|
+
// to show the list of all setting docs available
|
|
102
|
+
let search = instance.search({"selector":{"schema":"system_settings"}})
|
|
103
|
+
return {docs:search.docs}
|
|
104
|
+
}
|
|
105
|
+
else if(c_type=="keys"){
|
|
106
|
+
// to show the list of all keys present in the db
|
|
107
|
+
let search = instance.search({"selector":{"schema":"system_keys"}})
|
|
108
|
+
return {docs:search.docs}
|
|
109
|
+
}
|
|
110
|
+
else{
|
|
111
|
+
throw new Error("Invalid tool command")
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const parse = async (instance, text) => {
|
|
118
|
+
let data = {
|
|
119
|
+
errors: [],
|
|
120
|
+
valid: false,
|
|
121
|
+
name: "",
|
|
122
|
+
criteria: {},
|
|
123
|
+
};
|
|
124
|
+
if (!text) {
|
|
125
|
+
data.errors.push(
|
|
126
|
+
"No text command provided. Format : command_name/parameter"
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
let parts = text.split("/");
|
|
130
|
+
if (parts.length == 0) {
|
|
131
|
+
data.errors.push("Invalid text command");
|
|
132
|
+
}
|
|
133
|
+
let command_name = parts[0];
|
|
134
|
+
if (!commands[command_name]) {
|
|
135
|
+
data.errors.push(
|
|
136
|
+
"Invalid command name. Valid : " + Object.keys(commands).join(",")
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
data.name = command_name;
|
|
140
|
+
try {
|
|
141
|
+
parts.shift();
|
|
142
|
+
let criteria = await commands[command_name].parse(instance,parts);
|
|
143
|
+
data.criteria = criteria;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
data.errors.push(error.message);
|
|
146
|
+
}
|
|
147
|
+
if (data.errors.length == 0) {
|
|
148
|
+
data.valid = true;
|
|
149
|
+
}
|
|
150
|
+
return data;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const run = async (instance, command) => {
|
|
154
|
+
let data = {
|
|
155
|
+
result:{},
|
|
156
|
+
errors:[],
|
|
157
|
+
valid:false
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
if (!command) {
|
|
161
|
+
data.errors.push("No command object provided ");
|
|
162
|
+
}
|
|
163
|
+
if (!command.valid){
|
|
164
|
+
data.errors["Command cannot be run"]
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
if(!commands[command.name]){
|
|
168
|
+
data.errors["Invalid command name"]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
let data1 = await commands[command.name].run(instance,command)
|
|
173
|
+
//console.log(data)
|
|
174
|
+
data.result = data1
|
|
175
|
+
} catch (error) {
|
|
176
|
+
data.errors.push(error.message)
|
|
177
|
+
}
|
|
178
|
+
if(data.errors.length==0){
|
|
179
|
+
data.valid = true
|
|
180
|
+
}
|
|
181
|
+
return data
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const parse_and_run = async(instance, text) => {
|
|
185
|
+
let command = await parse(instance,text)
|
|
186
|
+
console.log(command)
|
|
187
|
+
let command_result = await run(instance,command)
|
|
188
|
+
return command_result
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const text_command = {
|
|
192
|
+
parse,run,parse_and_run
|
|
193
|
+
};
|
package/src/system_schema.js
CHANGED
|
@@ -19,7 +19,7 @@ export const schema_schema = {
|
|
|
19
19
|
},
|
|
20
20
|
name: {
|
|
21
21
|
type: "string",
|
|
22
|
-
minLength:
|
|
22
|
+
minLength: 4,
|
|
23
23
|
maxLength: 50,
|
|
24
24
|
pattern: "^[a-zA-Z][a-zA-Z0-9_]*$",
|
|
25
25
|
description:"This is the name of the schema.It cannot be changed later"
|
|
@@ -74,16 +74,17 @@ export const schema_schema = {
|
|
|
74
74
|
default: false,
|
|
75
75
|
description:
|
|
76
76
|
"If set, only a single records with this schema will be allowed to insert in the database",
|
|
77
|
-
}
|
|
77
|
+
}
|
|
78
78
|
},
|
|
79
|
-
required :["primary_keys","non_editable_fields","
|
|
79
|
+
required :["primary_keys","non_editable_fields","encrypted_fields"]
|
|
80
80
|
},
|
|
81
81
|
},
|
|
82
82
|
required: ["name","description","schema", "settings"],
|
|
83
83
|
},
|
|
84
84
|
settings: {
|
|
85
|
-
|
|
85
|
+
primary_keys: ["name"],
|
|
86
86
|
editable_fields: ["schema", "settings","description"],
|
|
87
|
+
encrypted_fields:[]
|
|
87
88
|
},
|
|
88
89
|
};
|
|
89
90
|
|
|
@@ -160,6 +161,35 @@ export const system_schemas = {
|
|
|
160
161
|
single_record:false
|
|
161
162
|
},
|
|
162
163
|
}
|
|
164
|
+
// ,
|
|
165
|
+
// edges:{
|
|
166
|
+
// name:"edges",
|
|
167
|
+
// description:"To relate one document to another.Labels can be configured using the db_network setting document.This stores edges of a simple directed graph",
|
|
168
|
+
// schema:{
|
|
169
|
+
// required:["graph","node1","node2","label"],
|
|
170
|
+
// type:"object",
|
|
171
|
+
// additionalProperties: false,
|
|
172
|
+
// properties : {
|
|
173
|
+
// graph:{
|
|
174
|
+
// type:"string",
|
|
175
|
+
// minLength:3,
|
|
176
|
+
// default:"default",
|
|
177
|
+
// maxLength:100,
|
|
178
|
+
// description:"Name of the graph in which this edge is being added. This is managed by the db_network setting "
|
|
179
|
+
// },
|
|
180
|
+
// node1:{
|
|
181
|
+
// type:"string",
|
|
182
|
+
// description:"the source of this directed edge. this must be a valid document id."
|
|
183
|
+
// }
|
|
184
|
+
// }
|
|
185
|
+
// },
|
|
186
|
+
// settings :{
|
|
187
|
+
// primary_key:["graph","node1","node2","label"],
|
|
188
|
+
// non_editable_fields:["node1","node2","graph"],
|
|
189
|
+
// encrypted_fields:[],
|
|
190
|
+
// single_record:false
|
|
191
|
+
// }
|
|
192
|
+
// }
|
|
163
193
|
};
|
|
164
194
|
|
|
165
195
|
// this is not stored in the DB. only for validating the metadata during doc update
|
package/test/couchdb.js
CHANGED
|
@@ -41,7 +41,7 @@ export class BeanBagDB_CouchDB extends BeanBagDB {
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
utils:{
|
|
44
|
-
encrypt: (text,encryptionKey)=>{
|
|
44
|
+
encrypt: async (text,encryptionKey)=>{
|
|
45
45
|
const key = crypto.scryptSync(encryptionKey, 'salt', 32); // Derive a 256-bit key
|
|
46
46
|
const iv = crypto.randomBytes(16); // Initialization vector
|
|
47
47
|
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
@@ -49,7 +49,7 @@ export class BeanBagDB_CouchDB extends BeanBagDB {
|
|
|
49
49
|
encrypted += cipher.final('hex');
|
|
50
50
|
return iv.toString('hex') + ':' + encrypted; // Prepend the IV for later use
|
|
51
51
|
},
|
|
52
|
-
decrypt : (encryptedText, encryptionKey)=>{
|
|
52
|
+
decrypt : async (encryptedText, encryptionKey)=>{
|
|
53
53
|
const key = crypto.scryptSync(encryptionKey, 'salt', 32); // Derive a 256-bit key
|
|
54
54
|
const [iv, encrypted] = encryptedText.split(':').map(part => Buffer.from(part, 'hex'));
|
|
55
55
|
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|