@@ -85,6 +85,7 @@ export class Collection extends LokiEventEmitter {
85
85
* @param {boolean } [options.adaptiveBinaryIndices=true] - collection indices will be actively rebuilt rather than lazily
86
86
* @param {boolean } [options.asyncListeners=false] - whether listeners are invoked asynchronously
87
87
* @param {boolean } [options.disableChangesApi=true] - set to false to enable Changes API
88
+ * @param {boolean } [options.disableDeltaChangesApi=true] - set to false to enable Delta Changes API (requires Changes API, forces cloning)
88
89
* @param {boolean } [options.autoupdate=false] - use Object.observe to update objects automatically
89
90
* @param {boolean } [options.clone=false] - specify whether inserts and queries clone to/from user
90
91
* @param {boolean } [options.serializableIndices =true[]] - converts date values on binary indexed property values are serializable
@@ -171,6 +172,12 @@ export class Collection extends LokiEventEmitter {
171
172
// disable track changes
172
173
this . disableChangesApi = options . disableChangesApi !== undefined ? options . disableChangesApi : true ;
173
174
175
+ // disable delta update object style on changes
176
+ this . disableDeltaChangesApi = options . disableDeltaChangesApi !== undefined ? options . disableDeltaChangesApi : true ;
177
+ if ( this . disableChangesApi ) {
178
+ this . disableDeltaChangesApi = true ;
179
+ }
180
+
174
181
// option to observe objects and update them automatically, ignored if Object.observe is not supported
175
182
this . autoupdate = options . autoupdate !== undefined ? options . autoupdate : false ;
176
183
@@ -258,14 +265,54 @@ export class Collection extends LokiEventEmitter {
258
265
* This method creates a clone of the current status of an object and associates operation and collection name,
259
266
* so the parent db can aggregate and generate a changes object for the entire db
260
267
*/
261
- function createChange ( name , op , obj ) {
268
+ function createChange ( name , op , obj , old ) {
262
269
self . changes . push ( {
263
270
name,
264
271
operation : op ,
265
- obj : JSON . parse ( JSON . stringify ( obj ) )
272
+ obj : op === "U" && ! self . disableDeltaChangesApi ? getChangeDelta ( obj , old ) : JSON . parse ( JSON . stringify ( obj ) )
266
273
} ) ;
267
274
}
268
275
276
+ //Compare changed object (which is a forced clone) with existing object and return the delta
277
+ function getChangeDelta ( obj , old ) {
278
+ if ( old ) {
279
+ return getObjectDelta ( old , obj ) ;
280
+ }
281
+ else {
282
+ return JSON . parse ( JSON . stringify ( obj ) ) ;
283
+ }
284
+ }
285
+
286
+ this . getChangeDelta = getChangeDelta ;
287
+
288
+ function getObjectDelta ( oldObject , newObject ) {
289
+ const propertyNames = newObject !== null && typeof newObject === "object" ? Object . keys ( newObject ) : null ;
290
+ if ( propertyNames && propertyNames . length && [ "string" , "boolean" , "number" ] . indexOf ( typeof ( newObject ) ) < 0 ) {
291
+ const delta = { } ;
292
+ for ( let i = 0 ; i < propertyNames . length ; i ++ ) {
293
+ const propertyName = propertyNames [ i ] ;
294
+ if ( newObject . hasOwnProperty ( propertyName ) ) {
295
+ if ( ! oldObject . hasOwnProperty ( propertyName ) || self . uniqueNames . indexOf ( propertyName ) >= 0 || propertyName === "$loki" || propertyName === "meta" ) {
296
+ delta [ propertyName ] = newObject [ propertyName ] ;
297
+ }
298
+ else {
299
+ const propertyDelta = getObjectDelta ( oldObject [ propertyName ] , newObject [ propertyName ] ) ;
300
+ if ( typeof propertyDelta !== "undefined" && propertyDelta !== { } ) {
301
+ delta [ propertyName ] = propertyDelta ;
302
+ }
303
+ }
304
+ }
305
+ }
306
+ return Object . keys ( delta ) . length === 0 ? undefined : delta ;
307
+ }
308
+ else {
309
+ return oldObject === newObject ? undefined : newObject ;
310
+ }
311
+ }
312
+
313
+ this . getObjectDelta = getObjectDelta ;
314
+
315
+
269
316
// clear all the changes
270
317
function flushChanges ( ) {
271
318
self . changes = [ ] ;
@@ -323,18 +370,18 @@ export class Collection extends LokiEventEmitter {
323
370
createChange ( self . name , "I" , obj ) ;
324
371
}
325
372
326
- function createUpdateChange ( obj ) {
327
- createChange ( self . name , "U" , obj ) ;
373
+ function createUpdateChange ( obj , old ) {
374
+ createChange ( self . name , "U" , obj , old ) ;
328
375
}
329
376
330
377
function insertMetaWithChange ( obj ) {
331
378
insertMeta ( obj ) ;
332
379
createInsertChange ( obj ) ;
333
380
}
334
381
335
- function updateMetaWithChange ( obj ) {
382
+ function updateMetaWithChange ( obj , old ) {
336
383
updateMeta ( obj ) ;
337
- createUpdateChange ( obj ) ;
384
+ createUpdateChange ( obj , old ) ;
338
385
}
339
386
340
387
@@ -352,6 +399,9 @@ export class Collection extends LokiEventEmitter {
352
399
353
400
this . setChangesApi = ( enabled ) => {
354
401
this . disableChangesApi = ! enabled ;
402
+ if ( ! enabled ) {
403
+ self . disableDeltaChangesApi = false ;
404
+ }
355
405
setHandlers ( ) ;
356
406
} ;
357
407
/**
@@ -361,8 +411,8 @@ export class Collection extends LokiEventEmitter {
361
411
insertHandler ( obj ) ;
362
412
} ) ;
363
413
364
- this . on ( "update" , ( obj ) => {
365
- updateHandler ( obj ) ;
414
+ this . on ( "update" , ( obj , old ) => {
415
+ updateHandler ( obj , old ) ;
366
416
} ) ;
367
417
368
418
this . on ( "delete" , ( obj ) => {
@@ -418,7 +468,10 @@ export class Collection extends LokiEventEmitter {
418
468
}
419
469
420
470
static fromJSONObject ( obj , options , forceRebuild ) {
421
- let coll = new Collection ( obj . name , { disableChangesApi : obj . disableChangesApi } ) ;
471
+ let coll = new Collection ( obj . name , {
472
+ disableChangesApi : obj . disableChangesApi ,
473
+ disableDeltaChangesApi : obj . disableDeltaChangesApi
474
+ } ) ;
422
475
423
476
coll . adaptiveBinaryIndices = obj . adaptiveBinaryIndices !== undefined ? ( obj . adaptiveBinaryIndices === true ) : false ;
424
477
coll . transactional = obj . transactional ;
@@ -1016,7 +1069,7 @@ export class Collection extends LokiEventEmitter {
1016
1069
position = arr [ 1 ] ; // position in data array
1017
1070
1018
1071
// if configured to clone, do so now... otherwise just use same obj reference
1019
- newInternal = this . cloneObjects ? clone ( doc , this . cloneMethod ) : doc ;
1072
+ newInternal = this . cloneObjects || ! this . disableDeltaChangesApi ? clone ( doc , this . cloneMethod ) : doc ;
1020
1073
1021
1074
this . emit ( "pre-update" , doc ) ;
1022
1075
@@ -1059,7 +1112,7 @@ export class Collection extends LokiEventEmitter {
1059
1112
this . commit ( ) ;
1060
1113
this . dirty = true ; // for autosave scenarios
1061
1114
1062
- this . emit ( "update" , doc , this . cloneObjects ? clone ( oldInternal , this . cloneMethod ) : null ) ;
1115
+ this . emit ( "update" , doc , this . cloneObjects || ! this . disableDeltaChangesApi ? clone ( oldInternal , this . cloneMethod ) : null ) ;
1063
1116
return doc ;
1064
1117
} catch ( err ) {
1065
1118
this . rollback ( ) ;
0 commit comments