viewdb 0.5.12 → 0.7.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/.prettierrc +1 -0
- package/README.md +416 -1
- package/jest.config.js +11 -0
- package/lib/cursor.js +13 -9
- package/lib/index.js +1 -1
- package/lib/inmemory/collection.js +8 -10
- package/lib/inmemory/store.js +12 -12
- package/lib/merger.js +55 -56
- package/lib/observe.js +41 -41
- package/lib/plugins/viewdb_timestamp_plugin.js +2 -2
- package/lib/plugins/viewdb_versioning_plugin.js +7 -9
- package/lib/viewdb.js +12 -14
- package/package.json +12 -11
- package/test/cursor.js +50 -35
- package/test/merger.js +193 -160
- package/test/observe.js +63 -25
- package/test/plugins/viewdb_timestamp_plugin.js +39 -35
- package/test/plugins/viewdb_versioning_plugin.js +28 -28
- package/test/viewdb.js +88 -77
package/.prettierrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"prettier-config-surikaterna"
|
package/README.md
CHANGED
|
@@ -1 +1,416 @@
|
|
|
1
|
-
|
|
1
|
+
ViewDB
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
[ViewDB](https://github.com/surikaterna/viewdb) is an database facade for JavaScript. It can be configured with a custom
|
|
5
|
+
Store in order to provide support for different persistence sources, such as MongoDB or IndexedDB, but comes with
|
|
6
|
+
a default in-memory Store for easy testing.
|
|
7
|
+
|
|
8
|
+
* [Purpose](#purpose)
|
|
9
|
+
* [Installation](#installation)
|
|
10
|
+
* [Usage](#usage-example)
|
|
11
|
+
* [Components](#components)
|
|
12
|
+
* [ViewDB](#viewdb-1)
|
|
13
|
+
* [Methods](#methods)
|
|
14
|
+
* [open](#open)
|
|
15
|
+
* [collection](#collection)
|
|
16
|
+
* [Plugins](#plugins)
|
|
17
|
+
* [TimeStampPlugin](#timestampplugin)
|
|
18
|
+
* [VersioningPlugin](#versioningplugin)
|
|
19
|
+
* [Store](#store)
|
|
20
|
+
* [Methods](#methods-1)
|
|
21
|
+
* [open](#open-1)
|
|
22
|
+
* [collection](#collection-1)
|
|
23
|
+
* [InMemoryStore](#inmemorystore)
|
|
24
|
+
* [Collection](#collection-2)
|
|
25
|
+
* [Methods](#methods-2)
|
|
26
|
+
* [count](#count)
|
|
27
|
+
* [createIndex](#createindex)
|
|
28
|
+
* [drop](#drop)
|
|
29
|
+
* [ensureIndex](#ensureindex)
|
|
30
|
+
* [find](#find)
|
|
31
|
+
* [findAndModify](#findandmodify)
|
|
32
|
+
* [insert](#insert)
|
|
33
|
+
* [remove](#remove)
|
|
34
|
+
* [save](#save)
|
|
35
|
+
* [InMemoryCollection](#inmemorycollection)
|
|
36
|
+
* [Cursor](#cursor)
|
|
37
|
+
* [Methods](#methods-3)
|
|
38
|
+
* [count](#count-1)
|
|
39
|
+
* [forEach](#foreach)
|
|
40
|
+
* [limit](#limit)
|
|
41
|
+
* [observe](#observe)
|
|
42
|
+
* [skip](#skip)
|
|
43
|
+
* [sort](#sort)
|
|
44
|
+
* [toArray](#toarray)
|
|
45
|
+
* [Observer](#observer)
|
|
46
|
+
* [Methods](#methods-4)
|
|
47
|
+
* [stop](#stop)
|
|
48
|
+
* [Merger](#merger)
|
|
49
|
+
|
|
50
|
+
## Purpose
|
|
51
|
+
|
|
52
|
+
Provide a MongoDB like syntax for managing documents while providing customization for where to store the data.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```shell
|
|
57
|
+
npm install viewdb
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Usage Example
|
|
61
|
+
|
|
62
|
+
### In-Memory Database
|
|
63
|
+
|
|
64
|
+
Create a ViewDB instance keeping data in memory.
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
import ViewDB from 'viewdb';
|
|
68
|
+
import { processUsers, User, usersData } from './users';
|
|
69
|
+
|
|
70
|
+
const viewDB = new ViewDB();
|
|
71
|
+
const userCollection = viewDB.collection('user');
|
|
72
|
+
userCollection.insert(usersData, () => {
|
|
73
|
+
userCollection.find({ name: 'Jeff' }, (err, users) => {
|
|
74
|
+
if (err ?? users.length === 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
processUsers(users);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Components
|
|
84
|
+
|
|
85
|
+
### ViewDB
|
|
86
|
+
|
|
87
|
+
The database facade that manages a persistence [Store](#store). Manages [Collections](#collection-1) through the Store.
|
|
88
|
+
|
|
89
|
+
#### Methods
|
|
90
|
+
|
|
91
|
+
##### open
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
// Use a MongoDB Store for persistence
|
|
95
|
+
const viewDB = new ViewDB(mongoDBStore);
|
|
96
|
+
// Make sure the Store is open and ready to use
|
|
97
|
+
await viewDB.open();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
##### collection
|
|
101
|
+
|
|
102
|
+
Get a [Collection](#collection-1) from the provided [Store](#store). Will create and return a new Collection if one
|
|
103
|
+
doesn't already exist.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const userCollection = viewDB.collection('user');
|
|
107
|
+
userCollection.find({ name: 'Jeff' }, (err, users) => {
|
|
108
|
+
if (err ?? users.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
processUsers(users);
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Plugins
|
|
117
|
+
|
|
118
|
+
ViewDB can be extended by plugins to intercept data manipulation. Two plugins are included in this repository:
|
|
119
|
+
|
|
120
|
+
* [TimeStampPlugin](#timestampplugin)
|
|
121
|
+
* [VersioningPlugin](#versioningplugin)
|
|
122
|
+
|
|
123
|
+
##### TimeStampPlugin
|
|
124
|
+
|
|
125
|
+
Intercepts the `save`, `insert` & `findAndModify` _Collection_ methods with timestamps for creation and latest update.
|
|
126
|
+
The time inserted is a unix timestamp in milliseconds. It provides the following changes.
|
|
127
|
+
|
|
128
|
+
When _inserting_ documents without providing a `skipTimestamp` option, the inserted documents will get
|
|
129
|
+
a `createDateTime` and a `changeDateTime` property will be added to the documents.
|
|
130
|
+
|
|
131
|
+
When _saving_ documents without providing a `skipTimestamp` option, the inserted documents will get an
|
|
132
|
+
updated `changeDateTime` and a `changeDateTime` value. If there is no `createDateTime` property on the document, it will
|
|
133
|
+
be added as well.
|
|
134
|
+
|
|
135
|
+
When _finding and modifying_ an existing document, the `changeDateTime` value will be update to the current time.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const viewDB = new ViewDB();
|
|
139
|
+
|
|
140
|
+
// Apply the plugin to the ViewDB Store
|
|
141
|
+
new TimeStampPlugin(viewDB);
|
|
142
|
+
|
|
143
|
+
const collection = viewDB.collection('user');
|
|
144
|
+
|
|
145
|
+
// User data for Jeff will get `createDateTime` and `changeDateTime` properties
|
|
146
|
+
await collection.insert({ name: 'Jeff' });
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
##### VersioningPlugin
|
|
150
|
+
|
|
151
|
+
Intercepts the `save`, `insert` & `findAndModify` _Collection_ methods with an incremented version, unless
|
|
152
|
+
the `skipVersioning` option is passed and set to `true`.
|
|
153
|
+
|
|
154
|
+
Note that when _finding and modifying_ existing documents, if `version` is explicitly set in the `update` query, that
|
|
155
|
+
value will be replaced with the incremented version.
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const viewDB = new ViewDB();
|
|
159
|
+
|
|
160
|
+
// Apply the plugin to the ViewDB Store
|
|
161
|
+
new VersioningPlugin(viewDB);
|
|
162
|
+
|
|
163
|
+
const collection = viewDB.collection('user');
|
|
164
|
+
|
|
165
|
+
// User data for Jeff will get a `version` property
|
|
166
|
+
await collection.insert({ name: 'Jeff' });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Store
|
|
170
|
+
|
|
171
|
+
Responsible for retrieving a [Collection](#collection-2) of documents. If the store needs some setup to be ready, it
|
|
172
|
+
shall provide an `open` method for that.
|
|
173
|
+
|
|
174
|
+
Used through the [ViewDB](#viewdb-1) methods.
|
|
175
|
+
|
|
176
|
+
#### Methods
|
|
177
|
+
|
|
178
|
+
##### open
|
|
179
|
+
|
|
180
|
+
Optional method on the Store, to prepare the Store for usage.
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
await store.open();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
##### collection
|
|
187
|
+
|
|
188
|
+
Returns a named [Collection](#collection-2), kept in the Store for multiple retrievals.
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
const userCollection = store.collection('user');
|
|
192
|
+
|
|
193
|
+
// Same instance of the collection retrieved above
|
|
194
|
+
const userCollectionRetrievedLater = store.collection('user');
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### InMemoryStore
|
|
198
|
+
|
|
199
|
+
A basic implementation of a Store, which keeps a record of the [in memory collections](#InMemoryCollection) by name in
|
|
200
|
+
memory. Used if no Store is provided as an argument to the ViewDB constructor.
|
|
201
|
+
|
|
202
|
+
### Collection
|
|
203
|
+
|
|
204
|
+
Responsible for managing the data.
|
|
205
|
+
|
|
206
|
+
#### Methods
|
|
207
|
+
|
|
208
|
+
##### count
|
|
209
|
+
|
|
210
|
+
Retrieve the current amount of documents in the collection.
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
collection.count((err, count) => {
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
##### createIndex
|
|
218
|
+
|
|
219
|
+
Creates an `index` to be used when looking up data.
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
collection.createIndex({ 'contactMeans.identifier': 1 }, null, (err, result) => {
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
##### drop
|
|
227
|
+
|
|
228
|
+
Clear all data in the collection.
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
// Whether the collection was successfully dropped
|
|
232
|
+
const isSuccess = collection.drop();
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
##### ensureIndex
|
|
236
|
+
|
|
237
|
+
Creates an `index` for the collection unless it already exists.
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
collection.ensureIndex({ 'contactMeans.identifier': 1 }, null, (err, result) => {
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
##### find
|
|
245
|
+
|
|
246
|
+
Returns a [Cursor](#cursor) for the list of documents from the collection matching the query.
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
await cursor = collection.find({});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
##### findAndModify
|
|
253
|
+
|
|
254
|
+
Retrieve a list of documents from the collection matching the query, and update the resulting documents based on the
|
|
255
|
+
update query.
|
|
256
|
+
|
|
257
|
+
```js
|
|
258
|
+
collection.findAndModify(query, null, update, options, (err, res) => {
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
##### insert
|
|
263
|
+
|
|
264
|
+
Insert new documents into the collection.
|
|
265
|
+
|
|
266
|
+
```js
|
|
267
|
+
collection.insert(newDocs, (err, insertedDocs) => {
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
##### remove
|
|
272
|
+
|
|
273
|
+
Remove documents matching the query from the collection.
|
|
274
|
+
|
|
275
|
+
```js
|
|
276
|
+
collection.remove({ name: 'Jeff' }, null, (err, result) => {
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
##### save
|
|
281
|
+
|
|
282
|
+
Replace the documents in the collection matching the provided documents by `_id`.
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
collection.save(updatedDocs, (err, savedDocs) => {
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### InMemoryCollection
|
|
290
|
+
|
|
291
|
+
A basic implementation of a [Collection](#collection-2) managing the data in memory.
|
|
292
|
+
|
|
293
|
+
### Cursor
|
|
294
|
+
|
|
295
|
+
A result set of the queried [Collection](#collection-2). Contains methods to operate on the result set.
|
|
296
|
+
|
|
297
|
+
Used through the [Collection.find](#find) method, but a Cursor can be constructed manually.
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
const collection = viewDB.collection('user');
|
|
301
|
+
const queryObj = { query: {} };
|
|
302
|
+
const cursorOptions = null;
|
|
303
|
+
const getDocuments = (query, callback) => {
|
|
304
|
+
// Logic for retreving documents based on query and passing them to the callback
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const cursor = new Cursor(collection, queryObj, cursorOptions, getDocuments);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### Methods
|
|
311
|
+
|
|
312
|
+
##### count
|
|
313
|
+
|
|
314
|
+
Get the amount of matches for the [Cursor](#cursor).
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
cursor.count((err, count) => {
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
##### forEach
|
|
322
|
+
|
|
323
|
+
Iterate through the matched documents and run the callback for each document.
|
|
324
|
+
|
|
325
|
+
```js
|
|
326
|
+
cursor.forEach((doc) => {
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
##### limit
|
|
331
|
+
|
|
332
|
+
Limit the amount of documents to be retrieved.
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
// Get maximum 5 documents
|
|
336
|
+
cursor.limit(5).toArray((err, docs) => {
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
##### observe
|
|
341
|
+
|
|
342
|
+
Retrieves an [Observer](#observer) listening for changes for the documents matched in the [Cursor](#cursor).
|
|
343
|
+
|
|
344
|
+
```js
|
|
345
|
+
const observeOptions = {
|
|
346
|
+
added: (user, index) => {
|
|
347
|
+
// Called when a user matching the cursor has been inserted to the collection
|
|
348
|
+
},
|
|
349
|
+
changed: (currentUser, newUser, index) => {
|
|
350
|
+
// Called when a user matching the cursor has been updated in the collection
|
|
351
|
+
},
|
|
352
|
+
moved: (user, oldIndex, newIndex) => {
|
|
353
|
+
// Called when a user matching the cursor has been moved to another position
|
|
354
|
+
},
|
|
355
|
+
removed: (user, index) => {
|
|
356
|
+
// Called when a user matching the cursor has been removed from the collection
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const observer = cursor.observe(observeOptions);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
##### skip
|
|
364
|
+
|
|
365
|
+
Amounts of documents in the [Cursor](#cursor) that should be skipped.
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
// Get documents starting from the 6th match
|
|
369
|
+
cursor.skip(5).toArray((err, docs) => {
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
##### sort
|
|
374
|
+
|
|
375
|
+
Sort the resulting documents based on a query.
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
// Get documents sorted by creation time in descending order
|
|
379
|
+
cursor.sort({ createDateTime: -1 }).toArray((err, docs) => {
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
##### toArray
|
|
384
|
+
|
|
385
|
+
Retrieve the list of documents matching the query.
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
cursor.toArray((err, docs) => {
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Observer
|
|
393
|
+
|
|
394
|
+
Observe changes to documents for a [Cursor](#cursor). With provide information about initial data, added, changed,
|
|
395
|
+
moved & removed data.
|
|
396
|
+
|
|
397
|
+
Used through the [Collection.observe](#observe) method, but an Observer can be constructed manually.
|
|
398
|
+
|
|
399
|
+
```js
|
|
400
|
+
const observer = new Observe(query, cursorOptions, collection, observerOptions);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### Methods
|
|
404
|
+
|
|
405
|
+
##### stop
|
|
406
|
+
|
|
407
|
+
Stop listening to changes matching the query.
|
|
408
|
+
|
|
409
|
+
```js
|
|
410
|
+
const observer = collection.find({}).observe(observeOptions);
|
|
411
|
+
observer.stop();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Merger
|
|
415
|
+
|
|
416
|
+
Check the provided data and provide information about how the values have changed.
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
roots: ['<rootDir>/lib', '<rootDir>/test'],
|
|
4
|
+
transform: {
|
|
5
|
+
'^.+\\.js$': ['es-jest']
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
testRegex: '(/test/.*|(\\.|/)(test|spec))\\.js$',
|
|
9
|
+
moduleDirectories: ['node_modules', 'lib'],
|
|
10
|
+
moduleFileExtensions: ['js', 'json', 'node']
|
|
11
|
+
};
|
package/lib/cursor.js
CHANGED
|
@@ -7,18 +7,18 @@ var Cursor = function (collection, query, options, getDocuments) {
|
|
|
7
7
|
this._options = options;
|
|
8
8
|
this._getDocuments = getDocuments;
|
|
9
9
|
this._isObserving = false;
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
11
|
|
|
12
|
-
Cursor.prototype.forEach = function (callback
|
|
13
|
-
|
|
14
|
-
_.forEach(result, function (
|
|
15
|
-
callback(result)
|
|
12
|
+
Cursor.prototype.forEach = function (callback) {
|
|
13
|
+
this._getDocuments(this._query, function (err, result) {
|
|
14
|
+
_.forEach(result, function () {
|
|
15
|
+
callback(result);
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
Cursor.prototype.toArray = function (callback) {
|
|
21
|
-
|
|
21
|
+
this._getDocuments(this._query, callback);
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
Cursor.prototype.observe = function (options) {
|
|
@@ -26,6 +26,11 @@ Cursor.prototype.observe = function (options) {
|
|
|
26
26
|
return new Observe(this._query, this._options, this._collection, options);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
Cursor.prototype.updateQuery = function (query) {
|
|
30
|
+
this._query.query = query;
|
|
31
|
+
this._refresh();
|
|
32
|
+
};
|
|
33
|
+
|
|
29
34
|
Cursor.prototype.skip = function (skip) {
|
|
30
35
|
this._query.skip = skip;
|
|
31
36
|
if (this._isObserving) {
|
|
@@ -74,8 +79,7 @@ Cursor.prototype.count = function (applySkipLimit, callback) {
|
|
|
74
79
|
}
|
|
75
80
|
this._getDocuments(query, function (err, res) {
|
|
76
81
|
callback(err, res && res.length);
|
|
77
|
-
})
|
|
82
|
+
});
|
|
78
83
|
};
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
module.exports = Cursor;
|
|
85
|
+
module.exports = Cursor;
|
package/lib/index.js
CHANGED
|
@@ -3,4 +3,4 @@ module.exports = require('./viewdb');
|
|
|
3
3
|
module.exports.Cursor = require('./cursor');
|
|
4
4
|
module.exports.Observer = require('./observe');
|
|
5
5
|
module.exports.merge = require('./merger');
|
|
6
|
-
module.exports.plugins = require('./plugins');
|
|
6
|
+
module.exports.plugins = require('./plugins');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var _ = require('lodash');
|
|
2
|
-
var uuid = require('
|
|
2
|
+
var { v4: uuid } = require('uuid');
|
|
3
3
|
|
|
4
4
|
var EventEmitter = require('events').EventEmitter;
|
|
5
5
|
var util = require('util');
|
|
@@ -17,15 +17,13 @@ var Collection = function (collectionName) {
|
|
|
17
17
|
|
|
18
18
|
util.inherits(Collection, EventEmitter);
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
Collection.prototype.count = function (callback) {
|
|
22
21
|
callback(null, this._documents.length);
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
Collection.prototype._write = function (op, documents, options, callback) {
|
|
26
|
-
if(_.isFunction(options)) {
|
|
25
|
+
if (_.isFunction(options)) {
|
|
27
26
|
callback = options;
|
|
28
|
-
options = undefined;
|
|
29
27
|
}
|
|
30
28
|
if (!_.isArray(documents)) {
|
|
31
29
|
documents = [documents];
|
|
@@ -50,11 +48,11 @@ Collection.prototype._write = function (op, documents, options, callback) {
|
|
|
50
48
|
this._documents[idx] = document;
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
|
-
this.emit(
|
|
51
|
+
this.emit('change', documents);
|
|
54
52
|
if (callback) {
|
|
55
53
|
callback(null, documents);
|
|
56
54
|
}
|
|
57
|
-
}
|
|
55
|
+
};
|
|
58
56
|
|
|
59
57
|
Collection.prototype.insert = function (documents, options, callback) {
|
|
60
58
|
return this._write('insert', documents, options, callback);
|
|
@@ -85,11 +83,11 @@ Collection.prototype.remove = function (query, options, callback) {
|
|
|
85
83
|
callback(null);
|
|
86
84
|
});
|
|
87
85
|
};
|
|
88
|
-
Collection.prototype.ensureIndex = function(
|
|
89
|
-
throw new Error('ensureIndex not supported!')
|
|
86
|
+
Collection.prototype.ensureIndex = function () {
|
|
87
|
+
throw new Error('ensureIndex not supported!');
|
|
90
88
|
};
|
|
91
|
-
Collection.prototype.createIndex = function(
|
|
92
|
-
throw new Error('createIndex not supported!')
|
|
89
|
+
Collection.prototype.createIndex = function () {
|
|
90
|
+
throw new Error('createIndex not supported!');
|
|
93
91
|
};
|
|
94
92
|
|
|
95
93
|
Collection.prototype._getDocuments = function (queryObject, callback) {
|
package/lib/inmemory/store.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
var Collection = require('./collection');
|
|
2
2
|
|
|
3
|
-
var Store = function() {
|
|
4
|
-
|
|
3
|
+
var Store = function () {
|
|
4
|
+
this._collections = {};
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
Store.prototype.collection = function(collectionName, callback) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
Store.prototype.collection = function (collectionName, callback) {
|
|
8
|
+
var coll = this._collections[collectionName];
|
|
9
|
+
if (coll === undefined) {
|
|
10
|
+
coll = new Collection(collectionName);
|
|
11
|
+
this._collections[collectionName] = coll;
|
|
12
|
+
}
|
|
13
|
+
if (callback) {
|
|
14
|
+
callback(coll);
|
|
15
|
+
}
|
|
16
|
+
return coll;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
module.exports = Store;
|
package/lib/merger.js
CHANGED
|
@@ -1,63 +1,62 @@
|
|
|
1
1
|
var _ = require('lodash');
|
|
2
2
|
|
|
3
3
|
function contains(list, element, comparator) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
for (var i in list) {
|
|
5
|
+
var n = list[i];
|
|
6
|
+
if (comparator(element, n)) {
|
|
7
|
+
return n;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return undefined;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function merge(asis, tobe, options) {
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//list = _.exclude()v
|
|
14
|
+
options = options || {};
|
|
15
|
+
var comparator = options.comparator || _.isEqual;
|
|
16
|
+
var comparatorId = options.comparatorId || comparator;
|
|
17
|
+
var list = _.slice(asis);
|
|
18
|
+
//check removed
|
|
19
|
+
_.forEach(asis, function (e) {
|
|
20
|
+
var found = contains(tobe, e, comparatorId);
|
|
21
|
+
if (found === undefined) {
|
|
22
|
+
var index = list.indexOf(e);
|
|
23
|
+
list.splice(index, 1);
|
|
24
|
+
if (options.removed) {
|
|
25
|
+
options.removed(e, index);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
var indexInNew = -1;
|
|
30
|
+
_.forEach(tobe, function (e) {
|
|
31
|
+
indexInNew++;
|
|
32
|
+
var found = contains(list, e, comparatorId);
|
|
33
|
+
//added
|
|
34
|
+
if (found === undefined) {
|
|
35
|
+
list.splice(indexInNew, 0, e);
|
|
36
|
+
if (options.added) {
|
|
37
|
+
options.added(e, indexInNew);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
//existed before
|
|
41
|
+
var indexInOld = list.indexOf(found);
|
|
42
|
+
if (indexInOld !== indexInNew) {
|
|
43
|
+
//remove
|
|
44
|
+
list.splice(indexInOld, 1);
|
|
45
|
+
//add
|
|
46
|
+
list.splice(indexInNew, 0, e);
|
|
47
|
+
if (options.moved) {
|
|
48
|
+
options.moved(e, indexInOld, indexInNew);
|
|
49
|
+
}
|
|
50
|
+
} //else not moved
|
|
51
|
+
if (!comparator(found, e)) {
|
|
52
|
+
list[indexInNew] = e;
|
|
53
|
+
if (options.changed) {
|
|
54
|
+
options.changed(found, e, indexInNew);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return list;
|
|
60
|
+
//list = _.exclude()v
|
|
62
61
|
}
|
|
63
|
-
module.exports=merge;
|
|
62
|
+
module.exports = merge;
|