sorla-db 1.0.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.
@@ -0,0 +1,196 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Simple Data Example</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ </head>
8
+ <body>
9
+ <p><b>Total Items:</b> <span id="total-items"></span></p><hr>
10
+
11
+ <h3>Add you data:</h3>
12
+ <div>
13
+ <label>Name</label>
14
+ <input type="text" id="name" placeholder="Name">
15
+ </div>
16
+ <div>
17
+ <label>Inscription</label>
18
+ <input type="number" step="1" min="1" id="inscription" placeholder="Inscription">
19
+ </div>
20
+ <div>
21
+ <label>Age</label>
22
+ <input type="number" step="1" min="1" id="age" placeholder="Age">
23
+ </div>
24
+ <div>
25
+ <label>Father</label>
26
+ <input type="text" id="father" placeholder="Father">
27
+ </div>
28
+ <div>
29
+ <label>Mother</label>
30
+ <input type="text" id="mother" placeholder="Mother">
31
+ </div>
32
+ <button type="button" id="add-data">Add data</button>
33
+ <hr>
34
+
35
+ <h3>Seach data</h3>
36
+ <div>
37
+ <label>Search by</label>
38
+ <input type="text" id="search-name" placeholder="Search by">
39
+ <select id="search-name-type">
40
+ <option value="name">Name</option>
41
+ <option value="inscription">Inscription</option>
42
+ <option value="age">Age</option>
43
+ <option value="parents.father">Father</option>
44
+ <option value="parents.mother">Mother</option>
45
+ </select>
46
+ <button type="button" id="search-by-btn">Search</button>
47
+ </div>
48
+
49
+ <div>
50
+ <textarea id="search-result" cols="30" rows="10"></textarea>
51
+ </div>
52
+
53
+ <script src="../dist/sorla.min.js"></script>
54
+
55
+ <script>
56
+ function generateUUID() {
57
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
58
+ var r = Math.random() * 16 | 0,
59
+ v = c == 'x' ? r : (r & 0x3 | 0x8);
60
+ return v.toString(16);
61
+ });
62
+ }
63
+
64
+ addItem = () => {
65
+ const name = document.getElementById('name').value;
66
+ const inscription = document.getElementById('inscription').value;
67
+ const age = document.getElementById('age').value;
68
+ const father = document.getElementById('father').value;
69
+ const mother = document.getElementById('mother').value;
70
+
71
+ s.db.simple.insertOne({
72
+ 'name': name,
73
+ 'inscription': inscription,
74
+ 'age': age,
75
+ 'parents': {
76
+ 'father': father,
77
+ 'mother': mother
78
+ }
79
+ });
80
+
81
+ document.getElementById('total-items').innerText = s.db.simple.count();
82
+ }
83
+
84
+ searchData = () => {
85
+ const searchName = document.getElementById('search-name').value;
86
+ const searchNameType = document.getElementById('search-name-type').value;
87
+
88
+ const result = s.db.simple.findOne({
89
+ [searchNameType]: searchName
90
+ });
91
+
92
+ console.log(result);
93
+
94
+ document.getElementById('search-result').value = JSON.stringify(result, null, 4);
95
+ }
96
+
97
+ document.addEventListener('DOMContentLoaded', () => {
98
+ window.s = new sorla();
99
+ s.useDb('simple_database');
100
+ s.db.createCollection('simple');
101
+ const uuid_fix = generateUUID();
102
+
103
+ //creating data
104
+ s.db.simple.insertMany([
105
+ {
106
+ 'name': 'John Doe',
107
+ 'inscription': 123,
108
+ 'age': 25,
109
+ 'parents': {
110
+ 'father': 'John Doe Sr.',
111
+ 'mother': 'Jane Doe'
112
+ },
113
+ 'uuid': generateUUID()
114
+ },
115
+
116
+ {
117
+ "name": "Elizabeth Davis",
118
+ "inscription": 618,
119
+ "age": 36,
120
+ "parents": {
121
+ "father": "Elizabeth Brown",
122
+ "mother": "Elizabeth Brown"
123
+ },
124
+ 'uuid': generateUUID()
125
+ },
126
+
127
+
128
+ {
129
+ "name": "John Davis",
130
+ "inscription": 817,
131
+ "age": 54,
132
+ "parents": {
133
+ "father": "John Garcia",
134
+ "mother": "Patricia Garcia"
135
+ },
136
+ 'uuid': uuid_fix
137
+ },
138
+
139
+ {
140
+ "name": "Jennifer Miller",
141
+ "inscription": 699,
142
+ "age": 45,
143
+ "parents": {
144
+ "father": "Linda Brown",
145
+ "mother": "Elizabeth Brown"
146
+ },
147
+ 'uuid': generateUUID()
148
+ },
149
+
150
+ {
151
+ "name": "Patricia Johnson",
152
+ "inscription": 906,
153
+ "age": 49,
154
+ "parents": {
155
+ "father": "Robert Johnson",
156
+ "mother": "Elizabeth Johnson"
157
+ },
158
+ 'uuid': generateUUID()
159
+ },
160
+
161
+ {
162
+ "name": "Michael Johnson",
163
+ "inscription": 810,
164
+ "age": 20,
165
+ "parents": {
166
+ "father": "Jennifer Brown",
167
+ "mother": "Jennifer Brown"
168
+ },
169
+ 'uuid': generateUUID()
170
+ }
171
+ ]);
172
+
173
+ document.getElementById('total-items').innerText = s.db.simple.count();
174
+ document.getElementById('add-data').addEventListener('click', addItem);
175
+ document.getElementById('search-by-btn').addEventListener('click', searchData);
176
+
177
+ //operators test
178
+ //testing search and
179
+ /*const result = s.db.simple.find({'$and': [{'name': 'John Doe'}, {'age': 25}]}, {_id: 0}); //should return 1
180
+ console.log('and', result);
181
+
182
+ //testing search or
183
+ const result2 = s.db.simple.find({'$or': [{'name': 'John Doe'}, {'parents.mother': 'Elizabeth Johnson'}]}); //should return 2
184
+ console.log('or', result2);
185
+
186
+ //testing search uuid
187
+ const result3 = s.db.simple.findOne({'uuid': uuid_fix});
188
+ console.log('uuid', uuid_fix, result3);*/
189
+
190
+ //search uuid with not
191
+ const result4 = s.db.simple.find({'uuid': {'$not': uuid_fix}});
192
+ console.log('uuid not', uuid_fix, result4);
193
+ });
194
+ </script>
195
+ </body>
196
+ </html>
package/index.js ADDED
@@ -0,0 +1,62 @@
1
+
2
+ const fs = require('fs-extra');
3
+ const browserify = require('browserify');
4
+ const path = require('path');
5
+ const terser = require('terser');
6
+
7
+ const srcDir = './src';
8
+ const distDir = './dist';
9
+ const outputFile = `${distDir}/sorla.min.js`;
10
+
11
+ function findJsFiles(dir, fileList = [])
12
+ {
13
+ const files = fs.readdirSync(dir);
14
+ files.forEach(file => {
15
+ const filePath = path.join(dir, file);
16
+ const stat = fs.statSync(filePath);
17
+ if (stat.isDirectory())
18
+ {
19
+ findJsFiles(filePath, fileList);
20
+ }
21
+ else if (path.extname(filePath) === '.js')
22
+ {
23
+ fileList.push(filePath);
24
+ }
25
+ });
26
+ return fileList;
27
+ }
28
+
29
+ function buildForBrowser(entryFile, outputFile) {
30
+ const b = browserify();
31
+ b.add(entryFile);
32
+ b.bundle(async (err, buf) => {
33
+ if (err) {
34
+ console.error(err);
35
+ return;
36
+ }
37
+
38
+ const code = buf.toString();
39
+ try {
40
+ const minified = await terser.minify(code, {
41
+ compress: true,
42
+ mangle: {
43
+ keep_classnames: true,
44
+ keep_fnames: true
45
+ }
46
+ });
47
+
48
+ if (minified.error) {
49
+ console.error(minified.error);
50
+ return;
51
+ }
52
+
53
+ fs.outputFileSync(outputFile, code);
54
+ fs.outputFileSync(outputFile, minified.code);
55
+ } catch (minifyErr) {
56
+ console.error(minifyErr);
57
+ }
58
+ });
59
+ }
60
+
61
+ const allJsFiles = findJsFiles(srcDir);
62
+ buildForBrowser(allJsFiles, outputFile);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "sorla-db",
3
+ "version": "1.0.0",
4
+ "description": "A simple and temporary database focused to use in browser environment that will bring capabilities for other tools that will be launched as soon as possible.",
5
+ "main": "dist/sorla.min.js",
6
+ "scripts": {
7
+ "mini": "node index.js",
8
+ "build": "webpack",
9
+ "test": "jest"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/sysborg/sorla-db.git"
14
+ },
15
+ "keywords": [
16
+ "nosql",
17
+ "browser",
18
+ "database",
19
+ "sorla",
20
+ "sysborg",
21
+ "anderson",
22
+ "arruda",
23
+ "andmarruda"
24
+ ],
25
+ "author": "Anderson Arruda < andmarruda@gmail.com >",
26
+ "license": "MIT",
27
+ "bugs": {
28
+ "url": "https://github.com/sysborg/sorla-db/issues"
29
+ },
30
+ "homepage": "https://github.com/sysborg/sorla-db#readme",
31
+ "devDependencies": {
32
+ "browserify": "^17.0.0",
33
+ "chai": "^4.3.8",
34
+ "faker": "^5.5.3",
35
+ "fs-extra": "^11.2.0",
36
+ "jest": "^29.6.4",
37
+ "jsdom": "^22.1.0",
38
+ "jsdom-global": "^3.0.2",
39
+ "mocha": "^10.2.0",
40
+ "terser": "^5.27.0"
41
+ }
42
+ }
@@ -0,0 +1,47 @@
1
+ const query = require('../query_language/query.js');
2
+
3
+ class collection extends query
4
+ {
5
+ /**
6
+ * Constructs class Collection to manage documents
7
+ * @author Anderson Arruda < anderson@sysborg.com.br >
8
+ * @version 1.0.0
9
+ * @param object validationSchema - in construction
10
+ * @return void
11
+ **/
12
+ constructor(validationSchema)
13
+ {
14
+ super(validationSchema);
15
+ this._documents = [];
16
+ this._indexes = [];
17
+ }
18
+
19
+ /**
20
+ * Returns the first document of the collection
21
+ * @return object
22
+ */
23
+ get first()
24
+ {
25
+ return structuredClone(this._documents[0]._data);
26
+ }
27
+
28
+ /**
29
+ * Returns the last document of the collection
30
+ * @return object
31
+ */
32
+ get last()
33
+ {
34
+ return structuredClone(this._documents[this._documents.length - 1]._data);
35
+ }
36
+
37
+ /**
38
+ * Return all the documents of the collection
39
+ * @return array
40
+ */
41
+ get all()
42
+ {
43
+ return this._documents;
44
+ }
45
+ }
46
+
47
+ module.exports = collection;
@@ -0,0 +1,72 @@
1
+ const collection = require('../collections/collection.js');
2
+
3
+ class database
4
+ {
5
+ /**
6
+ * Constructs class Database to manage collections
7
+ * @author Anderson Arruda < anderson@sysborg.com.br >
8
+ * @version 1.0.0
9
+ * @param string name
10
+ * @return void
11
+ **/
12
+ constructor(name)
13
+ {
14
+ this._collections = {};
15
+ this._name = name;
16
+ this._collectionCount = 0;
17
+
18
+ return new Proxy(this, {
19
+ get: (target, prop, receiver) => {
20
+ if(prop in target._collections)
21
+ {
22
+ return target._collections[prop];
23
+ }
24
+
25
+ return target[prop];
26
+ }
27
+ });
28
+ }
29
+
30
+ /**
31
+ * Returns the database name
32
+ * @author Anderson Arruda < anderson@sysborg.com.br >
33
+ * @version 1.0.0
34
+ * @param
35
+ * @return string
36
+ **/
37
+ get name()
38
+ {
39
+ return this._name;
40
+ }
41
+
42
+ /**
43
+ * Sets a new collection in the database
44
+ * @param string name
45
+ * @param object validationSchema - in construction
46
+ * @return void
47
+ */
48
+ createCollection(name, validationSchema)
49
+ {
50
+ if(this._collections.hasOwnProperty(name) || typeof this[name] !== 'undefined')
51
+ {
52
+ throw new Error('Collection already exists');
53
+ }
54
+
55
+ this._collections[name] = new collection(validationSchema);
56
+ this._collectionCount++;
57
+
58
+ //creates _id as a index unique
59
+ }
60
+
61
+ /**
62
+ * Returns the number of collections in the database
63
+ * @param
64
+ * @return int
65
+ */
66
+ countCollections()
67
+ {
68
+ return this._collectionCount;
69
+ }
70
+ }
71
+
72
+ module.exports = database;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @class Cursor
3
+ * @description Cursor class is used to represent the cursor in the document, adding some extra capabilities to object.
4
+ */
5
+
6
+ const documents = require('../documents/document.js');
7
+
8
+ class cursor {
9
+ /**
10
+ * @constructor
11
+ * @param array data
12
+ * @description Create a new cursor instance
13
+ */
14
+ constructor(data, projection) {
15
+ this._data = typeof data === 'undefined' ? [] : data;
16
+ this.currIndex = 0;
17
+ if(typeof projection === 'object')
18
+ this.projection(projection);
19
+ }
20
+
21
+ /**
22
+ * @method hasNext
23
+ * @description Check if the cursor has more elements
24
+ * @return boolean
25
+ */
26
+ hasNext() {
27
+ return this.currIndex < this._data.length;
28
+ }
29
+
30
+ /**
31
+ * @method next
32
+ * @description Get the next element in the cursor
33
+ * @return mixed
34
+ */
35
+ next() {
36
+ if(!this.hasNext())
37
+ throw new Error('No more item to the cursor');
38
+
39
+ return this._data[this.currIndex++];
40
+ }
41
+
42
+ /**
43
+ * @method toArray
44
+ * @description Convert the cursor to an array
45
+ * @return array
46
+ */
47
+ toArray() {
48
+ return structuredClone(this._data);
49
+ }
50
+
51
+ /**
52
+ * @methor reset
53
+ * @description Reset the cursor to the first element
54
+ * @return void
55
+ */
56
+ reset() {
57
+ this.currIndex = 0;
58
+ }
59
+
60
+ /**
61
+ * @method first
62
+ * @description Get the first element in the cursor
63
+ * @return mixed
64
+ */
65
+ first() {
66
+ return this._data[0]._data;
67
+ }
68
+
69
+ /**
70
+ * @method last
71
+ * @description Get the last element in the cursor
72
+ * @return mixed
73
+ */
74
+ last() {
75
+ return this._data[this._data.length - 1];
76
+ }
77
+
78
+ /**
79
+ * @method sort
80
+ * @description Sort the cursor using collection
81
+ * @param json sortQuery
82
+ * @return void
83
+ */
84
+ sort(sortQuery) {
85
+ const queryDoc = new documents(sortQuery);
86
+ this._data.sort((a, b) => {
87
+ for(const key of Object.keys(sortQuery))
88
+ {
89
+ const ascending = queryDoc[key] === 1;
90
+ if(a[key] > b[key])
91
+ return ascending ? 1 : -1;
92
+
93
+ if(a[key] < b[key])
94
+ return ascending ? -1 : 1;
95
+ }
96
+
97
+ return 0;
98
+ });
99
+ }
100
+
101
+ /**
102
+ * @get length
103
+ * @description Get the number of elements in the cursor
104
+ * @return number
105
+ */
106
+ get length() {
107
+ return this._data.length;
108
+ }
109
+
110
+ /**
111
+ * Projection of the cursor
112
+ * @param json projection
113
+ * @return cursor
114
+ */
115
+ projection(projection) {
116
+ if(projection === null || typeof projection !== 'object')
117
+ return;
118
+
119
+ const self = this;
120
+ this._data.forEach(doc => {
121
+ for(const attribute of Object.keys(projection))
122
+ {
123
+ if(projection[attribute] === 0) {
124
+ doc.deleteProp(attribute, self);
125
+ }
126
+ }
127
+ });
128
+ }
129
+
130
+ /**
131
+ * @method push
132
+ * @description Push an element to the cursor
133
+ * @param object element
134
+ * @return void
135
+ */
136
+ push(element) {
137
+ if(typeof element !== 'object')
138
+ throw new Error('The element must be an object');
139
+
140
+ this._data.push(element);
141
+ }
142
+ }
143
+
144
+ module.exports = cursor;
@@ -0,0 +1,88 @@
1
+ const utils = require('../utils');
2
+ const cursor = require('./cursor');
3
+ const manipulation = require('../query_language/manipulation');
4
+
5
+ class documents
6
+ {
7
+ constructor(object)
8
+ {
9
+ this._data = object;
10
+ this._utils = new utils();
11
+ this._cloned = false;
12
+ this._deleteReceiver = null;
13
+
14
+ return new Proxy(this, {
15
+ deleteProperty: (target, prop, receiver) => {
16
+ if(target._cloned && target._deleteReceiver instanceof cursor)
17
+ {
18
+ if(prop in target._data)
19
+ {
20
+ console.log('2', prop);
21
+ delete target._data[prop];
22
+ return true;
23
+ }
24
+
25
+ return false;
26
+ }
27
+ },
28
+
29
+ get: (target, prop) => {
30
+ if(prop.indexOf('.') > -1)
31
+ return target._utils.getDotData(target._data, prop);
32
+
33
+ if(prop in target._data)
34
+ return target._data[prop];
35
+
36
+ return target[prop];
37
+ },
38
+
39
+ set: (target, prop, value, receiver) => {
40
+ if(!(prop in target._data) && !target.hasOwnProperty(prop))
41
+ return false;
42
+
43
+ if(target.hasOwnProperty(prop) && ['_data', '_utils'].indexOf(prop) === -1){
44
+ target[prop] = value;
45
+ return true;
46
+ }
47
+
48
+ if(receiver instanceof manipulation || target._cloned && receiver instanceof cursor) {
49
+ target._data[prop] = value;
50
+ return true;
51
+ }
52
+
53
+ return false;
54
+ }
55
+ });
56
+ }
57
+
58
+ /**
59
+ * @method clone
60
+ * @description Clone the document
61
+ * @return Document
62
+ */
63
+ clone()
64
+ {
65
+ const cloned = new documents(structuredClone(this._data));
66
+ cloned._cloned = true;
67
+ return cloned;
68
+ }
69
+
70
+ /**
71
+ * @method delete prop
72
+ * @description Delete a property from the document
73
+ * @param string prop
74
+ * @param cursor receiver
75
+ * @return boolean
76
+ */
77
+ deleteProp(prop, receiver)
78
+ {
79
+ this._deleteReceiver = receiver;
80
+ if(this._cloned)
81
+ return Reflect.deleteProperty(this, prop);
82
+
83
+ return false;
84
+ }
85
+ }
86
+
87
+
88
+ module.exports = documents;
package/src/helper.js ADDED
@@ -0,0 +1,41 @@
1
+ //this file works only in dev mode, and is used to help with the development of the app
2
+ //and to debug bad behaviors and mistakes
3
+
4
+ const faker = require('faker');
5
+ const sorla = require('./sorla.js');
6
+
7
+ const createFakeCollection = (srla, collectionName, number_objects) => {
8
+ if(!(srla instanceof sorla))
9
+ throw new Error('srla must be an instance of sorla');
10
+
11
+ const objects = [];
12
+
13
+ for(let i=0; i<number_objects; i++)
14
+ {
15
+ const obj = {
16
+ name: faker.random.word(),
17
+ email: faker.internet.email(),
18
+ age: faker.datatype.number(),
19
+ uuid: faker.datatype.uuid()
20
+ };
21
+ srla.db[collectionName].insertOne(structuredClone(obj));
22
+ objects.push(obj);
23
+ }
24
+
25
+ return objects;
26
+ }
27
+
28
+ const getRandomComparisonData = (objects) => {
29
+ const itemIndex1 = Math.floor(Math.random() * objects.length);
30
+ let itemIndex2 = null;
31
+ do {
32
+ itemIndex2 = Math.floor(Math.random() * objects.length);
33
+ } while(itemIndex1 === itemIndex2);
34
+
35
+ return [objects[itemIndex1], objects[itemIndex2]];
36
+ }
37
+
38
+ module.exports = {
39
+ createFakeCollection,
40
+ getRandomComparisonData
41
+ }
File without changes