sorla-db 1.1.0 → 1.3.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/README.md +152 -9
- package/dist/sorla.min.js +1 -1
- package/index.d.ts +157 -0
- package/index.mjs +5 -0
- package/package.json +27 -3
- package/src/dbs/database.js +48 -0
- package/src/documents/cursor.js +141 -25
- package/src/documents/document.js +26 -30
- package/src/events.js +69 -0
- package/src/query_language/manipulation.js +321 -50
- package/src/query_language/operators.js +66 -1
- package/src/query_language/query.js +6 -2
- package/src/query_language/update.js +167 -0
- package/src/sorla.js +27 -0
- package/src/utils.js +9 -8
- package/Brainstorming.md +0 -22
- package/debug-not.js +0 -24
- package/example/simple_data_example.html +0 -196
- package/index.js +0 -62
- package/src/helper.js +0 -41
- package/test/feature_collection.test.js +0 -75
- package/test/feature_collection_queries.test.js +0 -224
- package/test/feature_cursor.test.js +0 -84
- package/test/feature_database.test.js +0 -62
- package/test/feature_insert.test.js +0 -116
- package/test/feature_nested_queries.test.js +0 -94
- package/test/feature_query_equivalence.test.js +0 -165
- package/test/unit_database.test.js +0 -36
- package/test/unit_document.test.js +0 -39
- package/test/unit_operators.test.js +0 -78
- package/test/unit_sorla.test.js +0 -42
- package/test/unit_test.test.js +0 -25
- package/webpack.config.js +0 -11
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update operators: $set, $unset, $inc, $push and $pull, with "a.b" paths.
|
|
3
|
+
* Updates are applied to a copy of the document, so a failing operator never leaves it half updated.
|
|
4
|
+
*/
|
|
5
|
+
const UPDATE_OPERATORS = ['$set', '$unset', '$inc', '$push', '$pull'];
|
|
6
|
+
|
|
7
|
+
const isPlainObject = value => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
8
|
+
&& Object.prototype.toString.call(value) === '[object Object]';
|
|
9
|
+
|
|
10
|
+
function splitPath(path)
|
|
11
|
+
{
|
|
12
|
+
if(typeof path !== 'string' || path === '' || path.split('.').some(part => part === ''))
|
|
13
|
+
throw new Error(`Invalid field path "${path}"`);
|
|
14
|
+
|
|
15
|
+
if(path === '_id' || path.startsWith('_id.'))
|
|
16
|
+
throw new Error('The _id field cannot be updated');
|
|
17
|
+
|
|
18
|
+
return path.split('.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getPath(data, parts)
|
|
22
|
+
{
|
|
23
|
+
let value = data;
|
|
24
|
+
for(const part of parts)
|
|
25
|
+
{
|
|
26
|
+
if(value === null || typeof value !== 'object' || !(part in value))
|
|
27
|
+
return undefined;
|
|
28
|
+
|
|
29
|
+
value = value[part];
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parent object of a path, creating missing objects on the way
|
|
36
|
+
*/
|
|
37
|
+
function parentOf(data, parts, create)
|
|
38
|
+
{
|
|
39
|
+
let target = data;
|
|
40
|
+
for(const part of parts.slice(0, -1))
|
|
41
|
+
{
|
|
42
|
+
if(!(part in target))
|
|
43
|
+
{
|
|
44
|
+
if(!create) return null;
|
|
45
|
+
target[part] = {};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if(target[part] === null || typeof target[part] !== 'object')
|
|
49
|
+
throw new Error(`Cannot create the field "${parts.join('.')}": "${part}" is not an object`);
|
|
50
|
+
|
|
51
|
+
target = target[part];
|
|
52
|
+
}
|
|
53
|
+
return target;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Validates an update document
|
|
58
|
+
* @param object update
|
|
59
|
+
* @return void
|
|
60
|
+
*/
|
|
61
|
+
function validateUpdate(update)
|
|
62
|
+
{
|
|
63
|
+
if(!isPlainObject(update))
|
|
64
|
+
throw new Error('The update must be an object like {$set: {field: value}}');
|
|
65
|
+
|
|
66
|
+
const keys = Object.keys(update);
|
|
67
|
+
if(!keys.length)
|
|
68
|
+
throw new Error('The update must contain at least one operator');
|
|
69
|
+
|
|
70
|
+
for(const key of keys)
|
|
71
|
+
{
|
|
72
|
+
if(!key.startsWith('$'))
|
|
73
|
+
throw new Error(`The update can only contain operators, use replaceOne() to replace a document (found "${key}")`);
|
|
74
|
+
|
|
75
|
+
if(!UPDATE_OPERATORS.includes(key))
|
|
76
|
+
throw new Error(`Unknown update operator ${key}`);
|
|
77
|
+
|
|
78
|
+
if(!isPlainObject(update[key]))
|
|
79
|
+
throw new Error(`The ${key} operator must be an object like {${key}: {field: value}}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Applies an update to a copy of the data
|
|
85
|
+
* @param object data stored document data
|
|
86
|
+
* @param object update
|
|
87
|
+
* @param object helpers {copy(value), validateKeys(object), operators}
|
|
88
|
+
* @return object the updated copy
|
|
89
|
+
*/
|
|
90
|
+
function applyUpdate(data, update, helpers)
|
|
91
|
+
{
|
|
92
|
+
validateUpdate(update);
|
|
93
|
+
const result = helpers.copy(data);
|
|
94
|
+
|
|
95
|
+
for(const [path, value] of Object.entries(update.$set ?? {}))
|
|
96
|
+
{
|
|
97
|
+
const parts = splitPath(path);
|
|
98
|
+
if(value !== null && typeof value === 'object' && !helpers.validateKeys(Array.isArray(value) ? { value } : value))
|
|
99
|
+
throw new Error('Invalid document keys');
|
|
100
|
+
|
|
101
|
+
parentOf(result, parts, true)[parts.at(-1)] = helpers.copy(value);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for(const path of Object.keys(update.$unset ?? {}))
|
|
105
|
+
{
|
|
106
|
+
const parts = splitPath(path);
|
|
107
|
+
const parent = parentOf(result, parts, false);
|
|
108
|
+
if(parent && !Array.isArray(parent))
|
|
109
|
+
delete parent[parts.at(-1)];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for(const [path, amount] of Object.entries(update.$inc ?? {}))
|
|
113
|
+
{
|
|
114
|
+
const parts = splitPath(path);
|
|
115
|
+
if(typeof amount !== 'number' || !Number.isFinite(amount))
|
|
116
|
+
throw new Error(`$inc needs a number for "${path}"`);
|
|
117
|
+
|
|
118
|
+
const current = getPath(result, parts);
|
|
119
|
+
if(current !== undefined && typeof current !== 'number')
|
|
120
|
+
throw new Error(`Cannot $inc "${path}": it is not a number`);
|
|
121
|
+
|
|
122
|
+
parentOf(result, parts, true)[parts.at(-1)] = (current ?? 0) + amount;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for(const [path, value] of Object.entries(update.$push ?? {}))
|
|
126
|
+
{
|
|
127
|
+
const parts = splitPath(path);
|
|
128
|
+
const current = getPath(result, parts);
|
|
129
|
+
if(current !== undefined && !Array.isArray(current))
|
|
130
|
+
throw new Error(`Cannot $push to "${path}": it is not an array`);
|
|
131
|
+
|
|
132
|
+
const items = isPlainObject(value) && Array.isArray(value.$each) ? value.$each : [value];
|
|
133
|
+
for(const item of items)
|
|
134
|
+
{
|
|
135
|
+
if(item !== null && typeof item === 'object' && !helpers.validateKeys(Array.isArray(item) ? { item } : item))
|
|
136
|
+
throw new Error('Invalid document keys');
|
|
137
|
+
}
|
|
138
|
+
parentOf(result, parts, true)[parts.at(-1)] = [...(current ?? []), ...items.map(helpers.copy)];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for(const [path, condition] of Object.entries(update.$pull ?? {}))
|
|
142
|
+
{
|
|
143
|
+
const parts = splitPath(path);
|
|
144
|
+
const current = getPath(result, parts);
|
|
145
|
+
if(current === undefined)
|
|
146
|
+
continue;
|
|
147
|
+
|
|
148
|
+
if(!Array.isArray(current))
|
|
149
|
+
throw new Error(`Cannot $pull from "${path}": it is not an array`);
|
|
150
|
+
|
|
151
|
+
const { operators } = helpers;
|
|
152
|
+
const matches = item => {
|
|
153
|
+
if(operators.isRegExp(condition) || operators.isOperatorObject(condition))
|
|
154
|
+
return operators.matchesCondition(item, condition);
|
|
155
|
+
|
|
156
|
+
if(isPlainObject(condition))
|
|
157
|
+
return isPlainObject(item) && operators.matches(item, condition);
|
|
158
|
+
|
|
159
|
+
return item === condition;
|
|
160
|
+
};
|
|
161
|
+
parentOf(result, parts, false)[parts.at(-1)] = current.filter(item => !matches(item));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { applyUpdate, validateUpdate, UPDATE_OPERATORS };
|
package/src/sorla.js
CHANGED
|
@@ -103,6 +103,33 @@ class sorla{
|
|
|
103
103
|
return this._dbs.length;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Names of the databases, in creation order
|
|
108
|
+
* @return array
|
|
109
|
+
*/
|
|
110
|
+
listDatabases()
|
|
111
|
+
{
|
|
112
|
+
return this._dbs.map(db => db.name);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Removes a database and its collections; when it was selected, no database stays selected
|
|
117
|
+
* @param string name
|
|
118
|
+
* @return boolean false when it did not exist
|
|
119
|
+
*/
|
|
120
|
+
dropDb(name)
|
|
121
|
+
{
|
|
122
|
+
const pos = this._findDbIndex(name);
|
|
123
|
+
if(pos === -1)
|
|
124
|
+
return false;
|
|
125
|
+
|
|
126
|
+
if(this._selectedDb === this._dbs[pos])
|
|
127
|
+
this._selectedDb = null;
|
|
128
|
+
|
|
129
|
+
this._dbs.splice(pos, 1);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
106
133
|
/**
|
|
107
134
|
* Return selected db
|
|
108
135
|
* @author Anderson Arruda < anderson@sysborg.com.br >
|
package/src/utils.js
CHANGED
|
@@ -25,16 +25,17 @@ class utils
|
|
|
25
25
|
*/
|
|
26
26
|
getDotData(data, field)
|
|
27
27
|
{
|
|
28
|
-
let
|
|
28
|
+
let value = data;
|
|
29
|
+
for(const part of field.split('.'))
|
|
30
|
+
{
|
|
31
|
+
// a missing step means the field does not exist (it used to return the parent object)
|
|
32
|
+
if(value === null || typeof value !== 'object' || !(part in value))
|
|
33
|
+
return undefined;
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
data = data[field];
|
|
34
|
-
}
|
|
35
|
-
});
|
|
35
|
+
value = value[part];
|
|
36
|
+
}
|
|
36
37
|
|
|
37
|
-
return
|
|
38
|
+
return value;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
package/Brainstorming.md
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
For the first query version needs only to see if has some non logical operator or non logical comparison to resend to find as a recursive method.
|
|
2
|
-
|
|
3
|
-
- Preparing sort of data using new capabilities
|
|
4
|
-
- improving find behavior
|
|
5
|
-
|
|
6
|
-
For comparison operators and deny operator like not
|
|
7
|
-
adding nor https://www.mongodb.com/docs/manual/reference/operator/query/nor/
|
|
8
|
-
|
|
9
|
-
https://www.mongodb.com/docs/manual/reference/operator/query-comparison/
|
|
10
|
-
https://www.mongodb.com/docs/manual/reference/operator/query/expr/
|
|
11
|
-
https://www.mongodb.com/docs/manual/reference/operator/query/regex/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Preparing a bunch of misc tests to search data, add sort data and create test sortable data.
|
|
15
|
-
|
|
16
|
-
//erros and improvements
|
|
17
|
-
Bugs appears after resolving not, need to check and test why
|
|
18
|
-
npm run test
|
|
19
|
-
|
|
20
|
-
needs to improve projection to use cursor
|
|
21
|
-
|
|
22
|
-
fix new bugs in test
|
package/debug-not.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const sorla = require('./src/sorla.js');
|
|
2
|
-
const helper = require('./src/helper.js');
|
|
3
|
-
|
|
4
|
-
const numberOfObjects = 20;
|
|
5
|
-
const sdb = new sorla();
|
|
6
|
-
sdb.createDb('test');
|
|
7
|
-
sdb.useDb('test');
|
|
8
|
-
|
|
9
|
-
sdb.db.createCollection('collection_test');
|
|
10
|
-
|
|
11
|
-
const objects = helper.createFakeCollection(sdb, 'collection_test', numberOfObjects);
|
|
12
|
-
const [itemIndex1, ] = helper.getRandomComparisonData(objects);
|
|
13
|
-
|
|
14
|
-
const finded = sdb.db.collection_test.find({
|
|
15
|
-
uuid: {
|
|
16
|
-
$not: {
|
|
17
|
-
$eq: itemIndex1.uuid
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
console.log(finded.length, numberOfObjects);
|
|
23
|
-
|
|
24
|
-
//console.log(finded);
|
|
@@ -1,196 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
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/src/helper.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
const chai = require('chai')
|
|
2
|
-
const expect = chai.expect
|
|
3
|
-
const faker = require('faker')
|
|
4
|
-
const sorla = require('../src/sorla.js')
|
|
5
|
-
|
|
6
|
-
describe('SORLA Collection Feature Test', () => {
|
|
7
|
-
beforeAll(() => {
|
|
8
|
-
this.srla = new sorla();
|
|
9
|
-
this.dbname = faker.random.word();
|
|
10
|
-
this.srla.createDb(this.dbname);
|
|
11
|
-
this.srla.useDb(this.dbname);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
let sequence = 0;
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
// random words repeat or clash with database properties ("name"), so make them unique
|
|
17
|
-
this.collectionName = `collection_${++sequence}`;
|
|
18
|
-
this.srla.db.createCollection(this.collectionName);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('Create a single document inside of a collection and check by length', () => {
|
|
22
|
-
this.srla.db[this.collectionName].insertOne({name: 'Anderson'});
|
|
23
|
-
expect(this.srla.db[this.collectionName].count()).to.equal(1);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('create multiple documents and check by length', () => {
|
|
27
|
-
this.srla.db[this.collectionName].insertMany([
|
|
28
|
-
{name: 'Anderson'},
|
|
29
|
-
{name: 'Arruda'},
|
|
30
|
-
{name: 'Sorla'}
|
|
31
|
-
]);
|
|
32
|
-
expect(this.srla.db[this.collectionName].count()).to.equal(3);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('create a document with prohibited character $', () => {
|
|
36
|
-
expect(() => this.srla.db[this.collectionName].insertOne({name: 'Anderson', $test: '123'})).to.throw();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('create a document with prohibited character .', () => {
|
|
40
|
-
expect(() => this.srla.db[this.collectionName].insertOne({"name.name": 'Anderson', test: {test: '123'}})).to.throw();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('create a document with prohibited character . inside of an array', () => {
|
|
44
|
-
expect(() => this.srla.db[this.collectionName].insertOne({name: 'Anderson', test: [{"test.number": '123'}, {"test.number": '123'}]})).to.throw();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('create a document with prohibited character . inside of an object', () => {
|
|
48
|
-
expect(() => this.srla.db[this.collectionName].insertOne({name: 'Anderson', test: {"test.number": '123'}})).to.throw();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
/*it('get a document by his subfield using test.inscription', () => {
|
|
52
|
-
this.srla.db[this.collectionName].insertMany([
|
|
53
|
-
{name: 'Anderson', test: {inscription: 123}},
|
|
54
|
-
{name: 'Arruda', test: {inscription: 321}},
|
|
55
|
-
{name: 'Sorla', test: {inscription: 213}}
|
|
56
|
-
]);
|
|
57
|
-
expect(this.srla.db[this.collectionName].findOne({'test.inscription': 123}).length).to.equal(1);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('Try to create a document without beeing a valid object', () => {
|
|
61
|
-
expect(() => this.srla.db[this.collectionName].insertOne('Anderson')).to.throw();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('Try to create a document with array', () => {
|
|
65
|
-
expect(() => this.srla.db[this.collectionName].insertOne(['Anderson'])).to.throw();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('Try to create many documents without beeing a valid array', () => {
|
|
69
|
-
expect(() => this.srla.db[this.collectionName].insertMany('Anderson')).to.throw();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('Try to create many documents without having valid object', () => {
|
|
73
|
-
expect(() => this.srla.db[this.collectionName].insertMany([{test: '123', }, 'anderson'])).to.throw();
|
|
74
|
-
});*/
|
|
75
|
-
});
|