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.
@@ -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
- * Verify if exists some document that is not object
56
- * @param array documents
57
- * @return boolean
58
- */
59
- _validateDocumentsType(documents)
60
- {
61
- const count = documents.reduce((acc, doc) => {
62
- return typeof doc !== 'object' ? ++acc : acc;
63
- }, 0);
64
-
65
- return count;
66
- }
67
-
68
- /**
69
- * Verify if keys has prohibited characters
70
- * @param object document
71
- * @return boolean
72
- */
73
- _validateKeys(document)
74
- {
75
- const keys = Object.keys(document);
76
- const operators = new operatorsCheck();
77
- for(let key of keys)
78
- {
79
- const hasProhibitedCharacters = this._prohibitedCharacters.reduce((acc, char) => {
80
- return key.indexOf(char) > -1 ? ++acc : acc;
81
- }, 0);
82
-
83
- if(hasProhibitedCharacters > 0 && !operators.isOperator(key))
84
- return false;
85
-
86
- if(typeof document[key] === 'object')
87
- return this._validateKeys(document[key]);
88
-
89
- if(Array.isArray(document[key]))
90
- {
91
- for(let value of document[key])
92
- {
93
- if(typeof value === 'object')
94
- return this._validateKeys(value);
95
- }
96
- }
97
- }
98
-
99
- return true;
100
- }
101
-
102
- /**
103
- * Inserts one document to the collection
104
- * @author Anderson Arruda < anderson@sysborg.com.br >
105
- * @version 1.0.0
106
- * @param object document
107
- * @param function callback - under construction
108
- * @return void
109
- **/
110
- insertOne(document, callback)
111
- {
112
- if(typeof document !== 'object' || Array.isArray(document))
113
- throw new Error('Invalid document type');
114
-
115
- if(!this._validateKeys(document))
116
- throw new Error('Invalid document keys');
117
-
118
- if(typeof document._id === 'undefined')
119
- {
120
- let _idKey = '';
121
- do {
122
- _idKey = this._generateKey();
123
- } while(this._documents.find(doc => doc._id === document._id));
124
-
125
- document._id = _idKey;
126
- }
127
-
128
- if(!this._validate(document))
129
- throw new Error('Invalid document');
130
-
131
- this._documents.push(new documents(document));
132
-
133
- if(typeof callback === 'function')
134
- callback();
135
- }
136
-
137
- /**
138
- * Insert many documents
139
- * @author Anderson Arruda < anderson@sysborg.com.br >
140
- * @version 1.0.0
141
- * @param array documents
142
- * @param function callback
143
- * @return void
144
- */
145
- insertMany(documents, callback) {
146
- console.info(this._validateDocumentsType(documents));
147
- if(!Array.isArray(documents) || this._validateDocumentsType(documents) > 0)
148
- throw new Error('Documents must be an array of objects');
149
-
150
- for(let document of documents)
151
- this.insertOne(document);
152
-
153
- if(typeof callback === 'function')
154
- callback();
155
- }
156
-
157
- //create index
158
- //create indexes
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;