sorla-db 1.0.0 → 1.2.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/LICENSE +21 -21
- package/README.md +274 -31
- package/dist/sorla.min.js +1 -1
- package/index.d.ts +89 -0
- package/index.mjs +5 -0
- package/package.json +66 -42
- package/src/collections/collection.js +46 -46
- package/src/dbs/database.js +71 -71
- package/src/documents/cursor.js +207 -143
- package/src/documents/document.js +83 -87
- package/src/query_language/manipulation.js +197 -160
- package/src/query_language/operators.js +242 -288
- package/src/query_language/query.js +73 -103
- package/src/sorla.js +122 -122
- package/src/utils.js +41 -40
- 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 -73
- package/test/feature_collection_queries.test.js +0 -269
- package/test/unit_database.test.js +0 -36
- package/test/unit_document_test.js +0 -39
- package/test/unit_sorla.test.js +0 -42
- package/test/unit_test.test.js +0 -25
- package/webpack.config.js +0 -11
|
@@ -1,161 +1,198 @@
|
|
|
1
|
-
const documents = require('../documents/document.js');
|
|
2
|
-
const operatorsCheck = require('./operators.js');
|
|
3
|
-
|
|
4
|
-
class manipulation {
|
|
5
|
-
constructor(validationSchema = null) {
|
|
6
|
-
this.validationSchema = validationSchema;
|
|
7
|
-
this._index = {};
|
|
8
|
-
this._prohibitedCharacters = ['$', '.'];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generates a unique key as a uuid
|
|
13
|
-
* @return string
|
|
14
|
-
*/
|
|
15
|
-
_generateKey() {
|
|
16
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
17
|
-
var r = Math.random() * 16 | 0,
|
|
18
|
-
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
19
|
-
return v.toString(16)
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Valid and set validation schema for collection
|
|
25
|
-
* @author Anderson Arruda < anderson@sysborg.com.br >
|
|
26
|
-
* @version 1.0.0
|
|
27
|
-
* @param validationSchema
|
|
28
|
-
* @return void
|
|
29
|
-
**/
|
|
30
|
-
set validationSchema(validationSchema)
|
|
31
|
-
{
|
|
32
|
-
if(typeof schemaValidation === 'undefined' || schemaValidation === null)
|
|
33
|
-
return;
|
|
34
|
-
|
|
35
|
-
if(['object', 'function'].indexOf(typeof schemaValidation) == -1)
|
|
36
|
-
{
|
|
37
|
-
throw new Error('Invalid schema validation');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
this._validationSchema = validationSchema;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Validate data
|
|
45
|
-
* @param object data
|
|
46
|
-
* @return boolean
|
|
47
|
-
*/
|
|
48
|
-
_validate(data)
|
|
49
|
-
{
|
|
50
|
-
//under construction
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @param
|
|
57
|
-
* @return boolean
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
106
|
-
* @param object document
|
|
107
|
-
* @
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if(!this.
|
|
129
|
-
throw new Error('Invalid document');
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
1
|
+
const documents = require('../documents/document.js');
|
|
2
|
+
const operatorsCheck = require('./operators.js');
|
|
3
|
+
|
|
4
|
+
class manipulation {
|
|
5
|
+
constructor(validationSchema = null) {
|
|
6
|
+
this.validationSchema = validationSchema;
|
|
7
|
+
this._index = {};
|
|
8
|
+
this._prohibitedCharacters = ['$', '.'];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generates a unique key as a uuid
|
|
13
|
+
* @return string
|
|
14
|
+
*/
|
|
15
|
+
_generateKey() {
|
|
16
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
17
|
+
var r = Math.random() * 16 | 0,
|
|
18
|
+
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
19
|
+
return v.toString(16)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Valid and set validation schema for collection
|
|
25
|
+
* @author Anderson Arruda < anderson@sysborg.com.br >
|
|
26
|
+
* @version 1.0.0
|
|
27
|
+
* @param validationSchema
|
|
28
|
+
* @return void
|
|
29
|
+
**/
|
|
30
|
+
set validationSchema(validationSchema)
|
|
31
|
+
{
|
|
32
|
+
if(typeof schemaValidation === 'undefined' || schemaValidation === null)
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
if(['object', 'function'].indexOf(typeof schemaValidation) == -1)
|
|
36
|
+
{
|
|
37
|
+
throw new Error('Invalid schema validation');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this._validationSchema = validationSchema;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validate data
|
|
45
|
+
* @param object data
|
|
46
|
+
* @return boolean
|
|
47
|
+
*/
|
|
48
|
+
_validate(data)
|
|
49
|
+
{
|
|
50
|
+
//under construction
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Whether a value is a document: an object that is not null nor an array
|
|
56
|
+
* @param mixed value
|
|
57
|
+
* @return boolean
|
|
58
|
+
*/
|
|
59
|
+
_isDocument(value)
|
|
60
|
+
{
|
|
61
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Verify that no key, at any depth, has prohibited characters
|
|
66
|
+
* @param object document
|
|
67
|
+
* @return boolean
|
|
68
|
+
*/
|
|
69
|
+
_validateKeys(document)
|
|
70
|
+
{
|
|
71
|
+
const operators = new operatorsCheck();
|
|
72
|
+
for(const key of Object.keys(document))
|
|
73
|
+
{
|
|
74
|
+
const hasProhibitedCharacters = this._prohibitedCharacters.some(char => key.indexOf(char) > -1);
|
|
75
|
+
if(hasProhibitedCharacters && !operators.isOperator(key))
|
|
76
|
+
return false;
|
|
77
|
+
|
|
78
|
+
const value = document[key];
|
|
79
|
+
const nested = Array.isArray(value) ? value : [value];
|
|
80
|
+
for(const item of nested)
|
|
81
|
+
{
|
|
82
|
+
// null is a valid value, only objects have keys to check
|
|
83
|
+
if(item !== null && typeof item === 'object' && !this._validateKeys(item))
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Set of the _id values of the collection. It is rebuilt when its size no longer matches the
|
|
93
|
+
* documents, so removals done directly on the documents array are handled too.
|
|
94
|
+
* @return Set
|
|
95
|
+
*/
|
|
96
|
+
_ids()
|
|
97
|
+
{
|
|
98
|
+
if(!this._idSet || this._idSet.size !== this._documents.length)
|
|
99
|
+
this._idSet = new Set(this._documents.map(doc => doc._data._id));
|
|
100
|
+
|
|
101
|
+
return this._idSet;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Copies a document, so the object given by the caller is never changed
|
|
106
|
+
* @param object document
|
|
107
|
+
* @return object
|
|
108
|
+
*/
|
|
109
|
+
_copy(document)
|
|
110
|
+
{
|
|
111
|
+
try {
|
|
112
|
+
return structuredClone(document);
|
|
113
|
+
} catch(error) {
|
|
114
|
+
throw new Error('Documents can only contain cloneable values (no functions or DOM nodes)');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Inserts one document to the collection
|
|
120
|
+
* @author Anderson Arruda < anderson@sysborg.com.br >
|
|
121
|
+
* @version 1.2.0
|
|
122
|
+
* @param object document
|
|
123
|
+
* @param function callback - receives the inserted _id
|
|
124
|
+
* @return mixed the _id of the inserted document
|
|
125
|
+
**/
|
|
126
|
+
insertOne(document, callback)
|
|
127
|
+
{
|
|
128
|
+
if(!this._isDocument(document))
|
|
129
|
+
throw new Error('Invalid document type');
|
|
130
|
+
|
|
131
|
+
if(!this._validateKeys(document))
|
|
132
|
+
throw new Error('Invalid document keys');
|
|
133
|
+
|
|
134
|
+
const data = this._copy(document);
|
|
135
|
+
if(typeof data._id === 'undefined')
|
|
136
|
+
{
|
|
137
|
+
do {
|
|
138
|
+
data._id = this._generateKey();
|
|
139
|
+
} while(this._ids().has(data._id));
|
|
140
|
+
}
|
|
141
|
+
else if(this._ids().has(data._id))
|
|
142
|
+
{
|
|
143
|
+
throw new Error(`Duplicate _id "${data._id}"`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if(!this._validate(data))
|
|
147
|
+
throw new Error('Invalid document');
|
|
148
|
+
|
|
149
|
+
this._documents.push(new documents(data));
|
|
150
|
+
this._ids().add(data._id);
|
|
151
|
+
|
|
152
|
+
if(typeof callback === 'function')
|
|
153
|
+
callback(data._id);
|
|
154
|
+
|
|
155
|
+
return data._id;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Insert many documents. Every document is validated before the first one is inserted,
|
|
160
|
+
* so an invalid document never leaves the collection with only part of the batch.
|
|
161
|
+
* @author Anderson Arruda < anderson@sysborg.com.br >
|
|
162
|
+
* @version 1.2.0
|
|
163
|
+
* @param array documents
|
|
164
|
+
* @param function callback - receives the inserted ids
|
|
165
|
+
* @return array the _id of each inserted document
|
|
166
|
+
*/
|
|
167
|
+
insertMany(documents, callback) {
|
|
168
|
+
if(!Array.isArray(documents) || !documents.every(document => this._isDocument(document)))
|
|
169
|
+
throw new Error('Documents must be an array of objects');
|
|
170
|
+
|
|
171
|
+
const given = new Set();
|
|
172
|
+
for(const document of documents)
|
|
173
|
+
{
|
|
174
|
+
if(!this._validateKeys(document))
|
|
175
|
+
throw new Error('Invalid document keys');
|
|
176
|
+
|
|
177
|
+
if(typeof document._id === 'undefined')
|
|
178
|
+
continue;
|
|
179
|
+
|
|
180
|
+
if(given.has(document._id) || this._ids().has(document._id))
|
|
181
|
+
throw new Error(`Duplicate _id "${document._id}"`);
|
|
182
|
+
|
|
183
|
+
given.add(document._id);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const ids = documents.map(document => this.insertOne(document));
|
|
187
|
+
|
|
188
|
+
if(typeof callback === 'function')
|
|
189
|
+
callback(ids);
|
|
190
|
+
|
|
191
|
+
return ids;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
//create index
|
|
195
|
+
//create indexes
|
|
196
|
+
}
|
|
197
|
+
|
|
161
198
|
module.exports = manipulation;
|