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,289 +1,243 @@
|
|
|
1
|
-
class operators {
|
|
2
|
-
/**
|
|
3
|
-
* Constructs the class
|
|
4
|
-
*/
|
|
5
|
-
constructor() {
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
* @
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
* @
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
* @param
|
|
41
|
-
* @
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
*
|
|
172
|
-
* @
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
*
|
|
196
|
-
* @
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*
|
|
208
|
-
* @
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
*
|
|
220
|
-
* @
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*
|
|
232
|
-
* @
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
* @param mixed query
|
|
244
|
-
* @return boolean
|
|
245
|
-
*/
|
|
246
|
-
get $ne() {
|
|
247
|
-
return (doc_value, query) => {
|
|
248
|
-
return !Array.isArray(query) ? doc_value !== query : false;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* equal
|
|
254
|
-
* @param mixed doc_value
|
|
255
|
-
* @param mixed query
|
|
256
|
-
* @return boolean
|
|
257
|
-
*/
|
|
258
|
-
get $eq() {
|
|
259
|
-
return (doc_value, query) => {
|
|
260
|
-
return !Array.isArray(query) ? doc_value === query : false;
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Handling with comparison of columns
|
|
266
|
-
* @param string field
|
|
267
|
-
* @param mixed query
|
|
268
|
-
* @param object doc
|
|
269
|
-
* @return boolean
|
|
270
|
-
*/
|
|
271
|
-
handleComparison(field, query, doc) {
|
|
272
|
-
if(typeof doc[field] === 'undefined' && typeof doc[this._currentField] === 'undefined')
|
|
273
|
-
return false;
|
|
274
|
-
|
|
275
|
-
if(this.isOperator(field))
|
|
276
|
-
return this[field](doc[this._currentField], query);
|
|
277
|
-
|
|
278
|
-
if(typeof query === 'object')
|
|
279
|
-
{
|
|
280
|
-
const operator = Object.keys(query)[0];
|
|
281
|
-
field = typeof field === 'undefined' ? this._currentField : field;
|
|
282
|
-
return this[operator](doc[field], query[operator]);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return this.$eq(doc[field], query);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
1
|
+
class operators {
|
|
2
|
+
/**
|
|
3
|
+
* Constructs the class with the list of supported operators
|
|
4
|
+
*/
|
|
5
|
+
constructor() {
|
|
6
|
+
this._logicalOperators = ['$or', '$and', '$not', '$nor'];
|
|
7
|
+
this._comparisonOperators = ['$lt', '$lte', '$gt', '$gte', '$eq', '$ne', '$in', '$nin'];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if is any operator
|
|
12
|
+
* @param string operator
|
|
13
|
+
* @return boolean
|
|
14
|
+
*/
|
|
15
|
+
isAnyOperator(operator) {
|
|
16
|
+
return this.isLogicalOperator(operator) || this.isOperator(operator);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* check if is logical operator
|
|
21
|
+
* @param string operator
|
|
22
|
+
* @return boolean
|
|
23
|
+
*/
|
|
24
|
+
isLogicalOperator(operator) {
|
|
25
|
+
return this._logicalOperators.indexOf(operator) > -1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Is operators
|
|
30
|
+
* @param string operator
|
|
31
|
+
* @return boolean
|
|
32
|
+
*/
|
|
33
|
+
isOperator(operator) {
|
|
34
|
+
return this._comparisonOperators.indexOf(operator) > -1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Checks if a document matches a query. Logical operators can be nested at any depth:
|
|
39
|
+
* {$and: [{age: {$gte: 30}}, {$or: [{name: 'X'}, {city: {$in: ['A', 'B']}}]}]}
|
|
40
|
+
* @param object doc
|
|
41
|
+
* @param object query
|
|
42
|
+
* @return boolean
|
|
43
|
+
*/
|
|
44
|
+
matches(doc, query) {
|
|
45
|
+
if(query === null || typeof query !== 'object' || Array.isArray(query))
|
|
46
|
+
throw new Error('The query must be an object');
|
|
47
|
+
|
|
48
|
+
for(const key of Object.keys(query)) {
|
|
49
|
+
if(this.isLogicalOperator(key)) {
|
|
50
|
+
if(!this.matchesLogical(key, query[key], doc))
|
|
51
|
+
return false;
|
|
52
|
+
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if(!this.matchesCondition(doc[key], query[key]))
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Logical operators: every query of $and, at least one of $or, none of $nor
|
|
65
|
+
* @param string operator
|
|
66
|
+
* @param array queries
|
|
67
|
+
* @param object doc
|
|
68
|
+
* @return boolean
|
|
69
|
+
*/
|
|
70
|
+
matchesLogical(operator, queries, doc) {
|
|
71
|
+
if(operator === '$not')
|
|
72
|
+
throw new Error('The $not operator must be used inside a field condition, like {age: {$not: {$gt: 30}}}');
|
|
73
|
+
|
|
74
|
+
if(!Array.isArray(queries))
|
|
75
|
+
throw new Error(`The ${operator} operator must be an array`);
|
|
76
|
+
|
|
77
|
+
switch(operator) {
|
|
78
|
+
case '$and':
|
|
79
|
+
return queries.every(query => this.matches(doc, query));
|
|
80
|
+
case '$or':
|
|
81
|
+
return queries.some(query => this.matches(doc, query));
|
|
82
|
+
case '$nor':
|
|
83
|
+
return !queries.some(query => this.matches(doc, query));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Checks a field value against a condition: a plain value means equality, an object of operators
|
|
91
|
+
* must satisfy every operator ({$gte: 1, $lte: 5}), and $not inverts a condition
|
|
92
|
+
* @param mixed value
|
|
93
|
+
* @param mixed condition
|
|
94
|
+
* @return boolean
|
|
95
|
+
*/
|
|
96
|
+
matchesCondition(value, condition) {
|
|
97
|
+
if(!this.isOperatorObject(condition))
|
|
98
|
+
return this.$eq(value, condition);
|
|
99
|
+
|
|
100
|
+
for(const operator of Object.keys(condition)) {
|
|
101
|
+
if(operator === '$not') {
|
|
102
|
+
if(this.matchesCondition(value, condition[operator]))
|
|
103
|
+
return false;
|
|
104
|
+
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if(!this.isOperator(operator))
|
|
109
|
+
throw new Error(`Unknown operator ${operator}`);
|
|
110
|
+
|
|
111
|
+
if(!this[operator](value, condition[operator]))
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Whether a condition is an object made of operators, like {$gt: 5}
|
|
120
|
+
* @param mixed condition
|
|
121
|
+
* @return boolean
|
|
122
|
+
*/
|
|
123
|
+
isOperatorObject(condition) {
|
|
124
|
+
if(condition === null || typeof condition !== 'object' || Array.isArray(condition))
|
|
125
|
+
return false;
|
|
126
|
+
|
|
127
|
+
const keys = Object.keys(condition);
|
|
128
|
+
return keys.length > 0 && keys.every(key => key.startsWith('$'));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Not in operator
|
|
133
|
+
* @param mixed doc_value
|
|
134
|
+
* @param array queries
|
|
135
|
+
* @return boolean
|
|
136
|
+
*/
|
|
137
|
+
get $nin() {
|
|
138
|
+
return (doc_value, queries) => {
|
|
139
|
+
if(!Array.isArray(queries))
|
|
140
|
+
throw new Error('The $nin operator must be an array');
|
|
141
|
+
|
|
142
|
+
return !this.$in(doc_value, queries);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* In operator
|
|
148
|
+
* @param mixed doc_value
|
|
149
|
+
* @param array queries
|
|
150
|
+
* @return boolean
|
|
151
|
+
*/
|
|
152
|
+
get $in() {
|
|
153
|
+
return (doc_value, queries) => {
|
|
154
|
+
if(!Array.isArray(queries))
|
|
155
|
+
throw new Error('The $in operator must be an array');
|
|
156
|
+
|
|
157
|
+
if(Array.isArray(doc_value))
|
|
158
|
+
{
|
|
159
|
+
for(const value of queries)
|
|
160
|
+
{
|
|
161
|
+
if(doc_value.indexOf(value) > -1)
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return queries.indexOf(doc_value) > -1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* less than
|
|
172
|
+
* @param mixed doc_value
|
|
173
|
+
* @param mixed query
|
|
174
|
+
* @return boolean
|
|
175
|
+
*/
|
|
176
|
+
get $lt() {
|
|
177
|
+
return (doc_value, query) => {
|
|
178
|
+
return !Array.isArray(query) ? doc_value < query : false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* less than or equal
|
|
184
|
+
* @param mixed doc_value
|
|
185
|
+
* @param mixed query
|
|
186
|
+
* @return boolean
|
|
187
|
+
*/
|
|
188
|
+
get $lte() {
|
|
189
|
+
return (doc_value, query) => {
|
|
190
|
+
return !Array.isArray(query) ? doc_value <= query : false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* greater than
|
|
196
|
+
* @param mixed doc_value
|
|
197
|
+
* @param mixed query
|
|
198
|
+
* @return boolean
|
|
199
|
+
*/
|
|
200
|
+
get $gt() {
|
|
201
|
+
return (doc_value, query) => {
|
|
202
|
+
return !Array.isArray(query) ? doc_value > query : false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* greater than or equal
|
|
208
|
+
* @param mixed doc_value
|
|
209
|
+
* @param mixed query
|
|
210
|
+
* @return boolean
|
|
211
|
+
*/
|
|
212
|
+
get $gte() {
|
|
213
|
+
return (doc_value, query) => {
|
|
214
|
+
return !Array.isArray(query) ? doc_value >= query : false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* not equal
|
|
220
|
+
* @param mixed doc_value
|
|
221
|
+
* @param mixed query
|
|
222
|
+
* @return boolean
|
|
223
|
+
*/
|
|
224
|
+
get $ne() {
|
|
225
|
+
return (doc_value, query) => {
|
|
226
|
+
return !Array.isArray(query) ? doc_value !== query : false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* equal
|
|
232
|
+
* @param mixed doc_value
|
|
233
|
+
* @param mixed query
|
|
234
|
+
* @return boolean
|
|
235
|
+
*/
|
|
236
|
+
get $eq() {
|
|
237
|
+
return (doc_value, query) => {
|
|
238
|
+
return !Array.isArray(query) ? doc_value === query : false;
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
289
243
|
module.exports = operators;
|