beanbagdb 0.5.43 → 0.5.45

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.
@@ -0,0 +1,180 @@
1
+ export const schema_schema = {
2
+ name: "schema",
3
+ description:"Meta-schema or schema for defining other schemas",
4
+ system_generated:true,
5
+ schema: {
6
+ type: "object",
7
+ additionalProperties: false,
8
+ properties: {
9
+ system_generated:{
10
+ type:"boolean",
11
+ default:false
12
+ },
13
+ name: {
14
+ type: "string",
15
+ minLength: 5,
16
+ maxLength: 50,
17
+ pattern: "^[a-zA-Z][a-zA-Z0-9_]*$",
18
+ },
19
+ description:{
20
+ type:"string",
21
+ minLength:1,
22
+ maxLength:1000
23
+ },
24
+ schema: {
25
+ type: "object",
26
+ additionalProperties: true,
27
+ minProperties: 1,
28
+ maxProperties: 50,
29
+ },
30
+ settings: {
31
+ type: "object",
32
+ additionalProperties: true,
33
+ properties: {
34
+ primary_keys: {
35
+ type: "array",
36
+ default: [],
37
+ items: {
38
+ type: "string",
39
+ },
40
+ maxItems: 10,
41
+ },
42
+ editable_fields: {
43
+ type: "array",
44
+ default: [],
45
+ items: {
46
+ type: "string",
47
+ },
48
+ maxItems: 20,
49
+ },
50
+ encrypted_fields: {
51
+ type: "array",
52
+ default: [],
53
+ items: {
54
+ type: "string",
55
+ },
56
+ maxItems: 10,
57
+ },
58
+ single_record: {
59
+ type: "boolean",
60
+ default: false,
61
+ description:
62
+ "If set, only a single records with this schema will be allowed to insert in the database",
63
+ },
64
+ },
65
+ },
66
+ },
67
+ required: ["name","description","schema", "settings"],
68
+ },
69
+ settings: {
70
+ primary_key: ["name"],
71
+ editable_fields: ["schema", "settings"],
72
+ },
73
+ };
74
+
75
+ export const system_schemas = {
76
+ logs: {
77
+ system_generated:true,
78
+ description:"Schema for the log doc. Single log doc for the whole DB to log stuff about the DB",
79
+ name: "system_logs",
80
+ schema: {
81
+ type: "object",
82
+ additionalProperties: true,
83
+ properties: {
84
+ logs: {
85
+ type: "array",
86
+ items: {
87
+ type: "object",
88
+ additionalProperties: true,
89
+ },
90
+ },
91
+ },
92
+ },
93
+ settings: {
94
+ single_record: true
95
+ },
96
+ },
97
+ keys: {
98
+ system_generated:true,
99
+ description:"To store user defined key. this can include anything like API tokens etc. There is a special method to fetch this. The values are encrypted",
100
+ name: "system_keys",
101
+ schema: {
102
+ type: "object",
103
+ additionalProperties: true,
104
+ required:["name","value"],
105
+ properties: {
106
+ name: {
107
+ type: "string",
108
+ minLength: 5,
109
+ maxLength: 50,
110
+ pattern: "^[a-zA-Z][a-zA-Z0-9_]*$",
111
+ },
112
+ value: {
113
+ type: "string",
114
+ minLength: 5,
115
+ maxLength: 5000,
116
+ pattern: "^[^\n\r]*$",
117
+ description:"Must be a single line string"
118
+ },
119
+ note: {
120
+ type: "string",
121
+ minLength: 1,
122
+ maxLength: 5000,
123
+ pattern: "^[a-zA-Z][a-zA-Z0-9_]*$",
124
+ },
125
+ },
126
+ },
127
+ settings: {
128
+ primary_keys: ["name"],
129
+ encrypted_fields:["value"]
130
+ },
131
+ },
132
+ settings: {
133
+ system_generated:true,
134
+ description:"The system relies on these settings for proper functioning or enabling optional features.",
135
+ name: "system_settings",
136
+ schema: {
137
+ required:["name","value"],
138
+ type: "object",
139
+ additionalProperties: true,
140
+ properties: {
141
+ name: {
142
+ type: "string",
143
+ minLength: 5,
144
+ maxLength: 250,
145
+ pattern: "^[a-zA-Z][a-zA-Z0-9_]*$",
146
+ },
147
+ value: {
148
+ type: "string",
149
+ minLength: 5,
150
+ maxLength: 5000,
151
+ pattern: "^[^\n\r]*$",
152
+ description:"Must be a single line string"
153
+ },
154
+ user_editable: {
155
+ type: "boolean",
156
+ default: true,
157
+ description:
158
+ "Whether this setting is editable by the user or only by the system",
159
+ },
160
+ },
161
+ },
162
+ settings: {
163
+ primary_keys: ["name"],
164
+ editable_fields: ["value"],
165
+ },
166
+ },
167
+ };
168
+
169
+ // this is not stored in the DB. only for validating the metadata during doc update
170
+ export const editable_metadata_schema = {
171
+ additionalProperties: false,
172
+ properties:{
173
+ tags:{
174
+ type:"array",
175
+ items:{type:"string"},
176
+ default:[],
177
+ maxItems: 40,
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,231 @@
1
+ // to test initialization of the BeanBagDB class. using in memory pouch db for testing to avoid additional setup.
2
+ import PouchDB from 'pouchdb';
3
+ import pouchdbFind from 'pouchdb-find';
4
+ PouchDB.plugin(pouchdbFind)
5
+ import { scryptSync, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
6
+ const db_name = "test_database_24"
7
+ const pdb = new PouchDB(db_name);
8
+ import Ajv from 'ajv';
9
+
10
+ const doc_obj = {
11
+ name: db_name,
12
+ encryption_key: "qwertyuiopaqwsde1254",
13
+ api: {
14
+ insert: async (doc) => {
15
+ const result = await pdb.post(doc);
16
+ return result;
17
+ },
18
+ // delete: ()=>{db1.destroy},
19
+ update: async (doc) => {
20
+ const result = await pdb.put(doc);
21
+ return result;
22
+ },
23
+ search: async (query) => {
24
+ const results = await pdb.find(query);
25
+ return results; // of the form {docs:[],...}
26
+ },
27
+ get: async (id) => {
28
+ const data = await pdb.get(id);
29
+ return data;
30
+ },
31
+ delete: async (id) => {
32
+ const doc = await pdb.get(id);
33
+ const resp = await pdb.remove(doc);
34
+ return resp;
35
+ },
36
+ createIndex: async (filter) => {
37
+ const data = await pdb.createIndex(filter);
38
+ return data;
39
+ },
40
+ },
41
+ utils: {
42
+ encrypt: (text, encryptionKey) => {
43
+ const key = scryptSync(encryptionKey, "salt", 32); // Derive a 256-bit key
44
+ const iv = randomBytes(16); // Initialization vector
45
+ const cipher = createCipheriv("aes-256-cbc", key, iv);
46
+ let encrypted = cipher.update(text, "utf8", "hex");
47
+ encrypted += cipher.final("hex");
48
+ return iv.toString("hex") + ":" + encrypted; // Prepend the IV for later use
49
+ },
50
+ decrypt: (encryptedText, encryptionKey) => {
51
+ const key = scryptSync(encryptionKey, "salt", 32); // Derive a 256-bit key
52
+ const [iv, encrypted] = encryptedText
53
+ .split(":")
54
+ .map((part) => Buffer.from(part, "hex"));
55
+ const decipher = createDecipheriv("aes-256-cbc", key, iv);
56
+ let decrypted = decipher.update(encrypted, "hex", "utf8");
57
+ decrypted += decipher.final("utf8");
58
+ return decrypted;
59
+ },
60
+ ping: () => {
61
+ // @TODO ping the database to check connectivity when class is ready to use
62
+ },
63
+ validate_schema: (schema_obj, data_obj)=>{
64
+ const ajv = new Ajv({code: {esm: true}}) // options can be passed, e.g. {allErrors: true}
65
+ const validate = ajv.compile(schema_obj);
66
+ const valid = validate(data_obj);
67
+ return {valid,validate}
68
+ }
69
+ },
70
+ }
71
+
72
+ let the_correct_object = {};
73
+
74
+ import { throws, strictEqual } from "assert";
75
+
76
+ import BeanBagDB from '../src/index.js';
77
+ /**
78
+ * Initial setup
79
+ * database is the global var where the beanbag class is initialized
80
+ */
81
+ const test_set1 = [
82
+ ["name", "sample"],
83
+ ["encryption_key", "sample_key"],
84
+ ["utils", {}],
85
+ ["api", {}],
86
+ ];
87
+ const test_obj = { name: "bla", encryption_key: "1234567890opuityerqwas" };
88
+ const full_util = {util: { encrypt: () => {}, decrypt: () => {}, ping: () => {} , validate_schema:()=>{}},}
89
+ const full_api = {api: { update: () => {}, delete: () => {}, get: () => {}, search: () => {}, createIndex: () => {}}}
90
+ const test_set_api = [
91
+ [
92
+ "api.insert missing",
93
+ {
94
+ ...test_obj,
95
+ ...full_util,
96
+ api: {update: () => {}, delete: () => {}, get: () => {}, search: () => {}, createIndex: () => {}},
97
+ },
98
+ ],
99
+ [
100
+ "api.update missing",
101
+ {
102
+ ...test_obj,
103
+ ...full_util,
104
+ api: {insert: () => {}, delete: () => {}, get: () => {},search: () => {},createIndex: () => {}},
105
+ },
106
+ ],
107
+ [
108
+ "api.delete missing",
109
+ {
110
+ ...test_obj,
111
+ ...full_util,
112
+ api: { insert: () => {}, update: () => {}, get: () => {}, search: () => {}, createIndex: () => {}},
113
+ },
114
+ ],
115
+ [
116
+ "api.get missing",
117
+ {
118
+ ...test_obj,
119
+ ...full_util,
120
+ api: { insert: () => {}, update: () => {}, delete: () => {}, search: () => {}, createIndex: () => {}}
121
+ },
122
+ ],
123
+ [
124
+ "api.search missing",
125
+ {
126
+ ...test_obj,
127
+ ...full_util,
128
+ api: { insert: () => {}, update: () => {}, delete: () => {}, get: () => {}, createIndex: () => {}}
129
+ },
130
+ ],
131
+ [
132
+ "api.createIndex missing",
133
+ {
134
+ ...test_obj,
135
+ ...full_util,
136
+ api: { insert: () => {}, update: () => {}, delete: () => {}, get: () => {}, search: () => {}},
137
+ },
138
+ ],
139
+ [
140
+ "util.encrypt missing",
141
+ { ...test_obj, ...full_api, util: { decrypt: () => {}, ping: () => {}, validate_schema:()=>{} } },
142
+ ],
143
+ [
144
+ "util.decrypt missing",
145
+ { ...test_obj, ...full_api, util: { encrypt: () => {}, ping: () => {}, validate_schema:()=>{} } },
146
+ ],
147
+ [
148
+ "util.validate_schema missing",
149
+ { ...test_obj, ...full_api, util: { encrypt: () => {}, ping: () => {}, decrypt: () => {} } },
150
+ ],
151
+ [
152
+ "util.ping missing",
153
+ {
154
+ ...test_obj,
155
+ ...full_api,
156
+ util: { encrypt: () => {}, decrypt: () => {} ,validate_schema:()=>{}},
157
+ },
158
+ ],
159
+ ];
160
+
161
+ let database;
162
+
163
+ describe("Tests initialization of the BeanBagDB class without no init object", async () => {
164
+ it("Throws error", () => {
165
+ throws(() => {
166
+ database = new BeanBagDB();
167
+ }, Error);
168
+ });
169
+ });
170
+
171
+ describe("Tests initialization of the BeanBagDB class with incomplete init object", async () => {
172
+ /*
173
+ * Proper object : {name,encryption_key,api:{insert,updated,delete,search,get,createIndex},utils:{encrypt,decrypt,ping}}
174
+ */
175
+ it("Blank object throw error", () => {
176
+ throws(() => {
177
+ database = new BeanBagDB({});
178
+ }, Error);
179
+ });
180
+ it("some invalid field throws error", () => {
181
+ throws(() => {
182
+ database = new BeanBagDB({ dbname: "sample" });
183
+ }, Error);
184
+ });
185
+ test_set1.forEach((item) => {
186
+ it(`only ${item[0]} throws error`, () => {
187
+ throws(() => {
188
+ let key = item[0];
189
+ database = new BeanBagDB({ key: item[1] });
190
+ }, Error);
191
+ });
192
+ });
193
+ test_set_api.forEach((item) => {
194
+ it(`${item[0]} throws error`, () => {
195
+ throws(() => {
196
+ let obj = { ...item[1] };
197
+ database = new BeanBagDB(obj);
198
+ }, Error);
199
+ });
200
+ });
201
+ });
202
+
203
+ describe("Successful database class init", async () => {
204
+ it("global database variable not yet initialized", () => {
205
+ strictEqual(
206
+ database instanceof BeanBagDB,
207
+ false,
208
+ "The variable is not yet initialized"
209
+ );
210
+ });
211
+
212
+ it("DB init successful", () => {
213
+ database = new BeanBagDB(doc_obj);
214
+ strictEqual(
215
+ database instanceof BeanBagDB,
216
+ true,
217
+ "The variable is initialized successfully"
218
+ );
219
+ });
220
+ });
221
+
222
+ /**
223
+ * process is : create a new obj with all required inputs, run ready() , then initialize_db , then ready to perform operations
224
+ *
225
+ * to test:
226
+ * - no object
227
+ * - incomplete objects and inner objects
228
+ * - good example
229
+ *
230
+ * initialized by ready not called ,
231
+ */
@@ -0,0 +1 @@
1
+ // to test database operations. assuming the class is initialized successfully
package/test/test1.js ADDED
@@ -0,0 +1,157 @@
1
+ // // require("dotenv").config();
2
+ // import 'dotenv/config'
3
+ // // import * as cbbdb from "../src/couchdb.js"
4
+ // // const cbbdb = require("../src/couchdb.js");
5
+ // // const pbbdb = require("../src/pouchdb.js");
6
+ // import BeanBagDB_PouchDB from "../src/pouchdb.js";
7
+ // import BeanBagDB_CouchDB from "../src/couchdb.js";
8
+ // // const pl1 = require("./helper.js")
9
+
10
+ // (async()=>{
11
+ // // console.log(process.env.cdburl)
12
+ // let db = new BeanBagDB_CouchDB(process.env.cdburl, process.env.cdbname, "sample_key");
13
+ // try {
14
+ // await db.ready();
15
+ // await db.initialize_db();
16
+ // await db.update_indexes()
17
+ // } catch (error) {
18
+ // console.log(error);
19
+ // }
20
+ // })()
21
+
22
+ // async function main1() {
23
+ // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
24
+
25
+ // try {
26
+ // await db.ready();
27
+ // await db.initialize_db();
28
+ // await db.update_indexes()
29
+ // } catch (error) {
30
+ // console.log(error);
31
+ // }
32
+ // }
33
+
34
+ // async function main2() {
35
+ // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
36
+ // await db.ready();
37
+ // // await db.update_indexes()
38
+ // sample_setting_docs = [
39
+ // {
40
+ // name: "sample1",
41
+ // value: "sample thing here",
42
+ // },
43
+ // {
44
+ // name: "no_value",
45
+ // },
46
+ // {
47
+ // value: "incorrect name",
48
+ // },
49
+ // {
50
+ // name: "sample1",
51
+ // value: "sample thing here",
52
+ // },
53
+ // {
54
+ // name: "sample1",
55
+ // value: "primary key check",
56
+ // },
57
+ // {
58
+ // name: "Sample2",
59
+ // value: "normal insert",
60
+ // },
61
+ // {
62
+ // value: "No name provided",
63
+ // },
64
+ // ];
65
+ // let t = sample_setting_docs.length
66
+ // for (let i = 0; i < t; i++) {
67
+ // try {
68
+ // let newid = await db.insert("system_settings",sample_setting_docs[i])
69
+ // console.log(newid)
70
+ // } catch (error) {
71
+ // console.log("Error "+i)
72
+ // console.error(error)
73
+ // continue
74
+ // }
75
+ // }
76
+ // }
77
+
78
+ // async function main3() {
79
+ // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
80
+ // await db.ready();
81
+ // // await db.update_indexes()
82
+ // sample_setting_docs = [
83
+ // {
84
+ // name: "sample1",
85
+ // value: "sample thing here",
86
+ // },
87
+ // {
88
+ // name: "sample2",
89
+ // value: "sample thing here again",
90
+ // },
91
+
92
+ // {
93
+ // name: "sample1",
94
+ // value: "sample thing here again",
95
+ // },
96
+ // ];
97
+ // let t = sample_setting_docs.length
98
+ // for (let i = 0; i < t; i++) {
99
+ // try {
100
+ // let newid = await db.insert("system_keys",sample_setting_docs[i])
101
+ // console.log(newid)
102
+ // } catch (error) {
103
+ // console.log("Error "+i)
104
+ // console.error(error)
105
+ // continue
106
+ // }
107
+ // }
108
+ // }
109
+
110
+
111
+ // async function main4(){
112
+ // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
113
+ // await db.ready();
114
+ // let doc1 = await db.get("e94b5eebe6b3c6dab8e2508d5908717c")
115
+ // console.log(doc1)
116
+ // let doc2 = await db.get_doc("system_keys",{"name":"sample2"})
117
+ // console.log(doc2)
118
+ // let doc3 = await db.get_doc("system_logs")
119
+ // console.log(doc3)
120
+ // }
121
+
122
+ // async function main5(){
123
+ // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
124
+ // await db.ready();
125
+ // let id = "e94b5eebe6b3c6dab8e2508d5908717c"
126
+ // let rec_1 = await db.get(id)
127
+ // let rec1 = rec_1.doc
128
+ // console.log(rec1)
129
+ // let rec1u = await db.update(id,"",{data:{"value":"secret key updated"},meta:{tags:["testing1","testing2","money"]}})
130
+ // console.log(rec1u)
131
+ // let r1 = await db.get(id)
132
+ // console.log(r1)
133
+ // }
134
+
135
+ // async function main6(){
136
+ // let db = new pbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
137
+ // await db.ready()
138
+ // //await db.initialize_db()
139
+
140
+ // }
141
+
142
+ // // main1().then(() => {console.log("Bye.");}).catch();
143
+
144
+ // // main3().then(() => {console.log("Bye.");}).catch();
145
+
146
+ // // main4().then(() => {console.log("Bye.");}).catch();
147
+
148
+ // // main5().then(() => {console.log("Bye.");}).catch();
149
+
150
+ // // main6().then(() => {console.log("Bye.");}).catch();
151
+
152
+
153
+ // // (async ()=>{
154
+ // // let db = new cbbdb(process.env.cdburl, process.env.cdbname, "sample_key");
155
+ // // await db.ready();
156
+ // // db.load_plugin("sample",pl1)
157
+ // // })();