1
0
Fork 0

StagingBucket: Better consideration of nulls for change detection

`null` indicates a truncation.

* src/bucket/StagingBucket.js (_length, _deepEqual): Add methods.
  (_hasChanged): Better consider how nulls affect the bucket.
* test/bucket/StagingBucketTest.js: Modify tests accordingly.
master
Mike Gerwitz 2017-08-11 12:03:34 -04:00
parent 5078c7d8d9
commit 1123bccf71
2 changed files with 109 additions and 8 deletions

View File

@ -204,31 +204,108 @@ module.exports = Class( 'StagingBucket' )
*/
'private _hasChanged': function( data, merge_index )
{
let changed = false;
for ( let name in data )
{
let values = data[ name ];
let cur = this._curdata[ name ] || [];
let values = data[ name ];
let cur = this._curdata[ name ] || [];
let len = this._length( values );
let has_null = ( len !== values.length );
if ( !merge_index && ( values.length !== cur.length ) )
let merge_len_change = (
merge_index && has_null && ( len < cur.length )
);
let replace_len_change = (
!merge_index && ( len !== cur.length )
);
// quick change check (index removal if merge_index, or index
// count change if not merge_index)
if ( merge_len_change || replace_len_change )
{
return true;
changed = true;
continue;
}
for ( let index in values )
for ( let index = 0; index < len; index++ )
{
if ( merge_index && ( values[ index ] === undefined ) )
{
continue;
}
if ( values[ index ] !== cur[ index ] )
if ( !this._deepEqual( values[ index ], cur[ index ] ) )
{
return true;
changed = true;
continue;
}
// unchanged
values[ index ] = undefined;
}
// if nothing is left, remove entirely
if ( !values.some( x => x !== undefined ) )
{
delete data[ name ];
}
}
return false;
return changed;
},
/**
* Get actual length of vector
*
* This considers when the last element of the vector is a null value,
* which is a truncation indicator.
*
* @param {Array} values value vector
*
* @return {number} length of vector considering truncation
*/
'private _length'( values )
{
if ( values[ values.length - 1 ] === null )
{
return values.length - 1;
}
return values.length;
},
/**
* Recursively check for equality of two vavlues
*
* This only recognizes nested arrays (vectors). They are not
* traditionally encountered in the bucket, but may exist.
*
* The final comparison is by string equality, since bucket values are
* traditionally strings.
*
* @param {*} a first vector or scalar
* @param {*} b second vector or scalar
*
* @return {boolean} whether `a` and `b` are equal
*/
'private _deepEqual'( a, b )
{
if ( Array.isArray( a ) )
{
if ( !Array.isArray( b ) || ( a.length !== b.length ) )
{
return false;
}
return a.map( ( item, i ) => this._deepEqual( item, b[ i ] ) )
.every( res => res === true );
}
return ''+a === ''+b;
},

View File

@ -112,6 +112,30 @@ describe( 'StagingBucket', () =>
merge_index: true,
is_change: true,
},
{
initial: { foo: [ 'bar', 'baz' ] },
update: { foo: [ 'bar', 'baz', null ] },
merge_index: true,
is_change: false,
},
{
initial: { foo: [ 'bar', 'baz' ] },
update: { foo: [ 'bar', 'baz', null ] },
merge_index: false,
is_change: false,
},
{
initial: { foo: [ 'bar', 'baz' ] },
update: { foo: [ 'bar', 'baz', 'quux' ] },
merge_index: true,
is_change: true,
},
{
initial: { foo: [ 'bar', 'baz' ] },
update: { foo: [ 'bar', 'baz', 'quux' ] },
merge_index: false,
is_change: true,
},
{
initial: { foo: [ 'bar', 'baz' ] },
update: { foo: [] },