Skip to content

Commit

Permalink
Merge 1b70a36 into d6af1cc
Browse files Browse the repository at this point in the history
  • Loading branch information
ronag committed Aug 18, 2016
2 parents d6af1cc + 1b70a36 commit 504ca2e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 54 deletions.
6 changes: 5 additions & 1 deletion src/default-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,5 +192,9 @@ module.exports = {
* returned data as the latest revision. This can be overriden on a per record
* basis by setting the `setMergeStrategy`.
*/
mergeStrategy: MERGE_STRATEGIES.REMOTE_WINS
mergeStrategy: MERGE_STRATEGIES.REMOTE_WINS,

recordDeepCopy: true,

recordDeepCompare: true
};
68 changes: 43 additions & 25 deletions src/record/json-path.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ var utils = require( '../utils/utils' ),
SPLIT_REG_EXP = /[\.\[\]]/g,
ASTERISK = '*';

var cache = Object.create( null );

/**
* This class allows to set or get specific
* values within a json data structure using
Expand All @@ -14,10 +16,11 @@ var utils = require( '../utils/utils' ),
*/
var JsonPath = function( record, path ) {
this._record = record;
this._path = String( path );
this._tokens = [];

this._tokenize();
this._tokens = cache[ path ];
if ( !this._tokens ) {
this._tokens = tokenize( path );
cache[ path ] = this._tokens;
}
};

/**
Expand All @@ -27,7 +30,7 @@ var JsonPath = function( record, path ) {
* @public
* @returns {Mixed}
*/
JsonPath.prototype.getValue = function() {
JsonPath.prototype.getValue = function( deepCopy ) {
var node = this._record._$data,
i;

Expand All @@ -39,7 +42,7 @@ JsonPath.prototype.getValue = function() {
}
}

return node;
return deepCopy ? utils.deepCopy( node ) : node;
};

/**
Expand All @@ -51,34 +54,47 @@ JsonPath.prototype.getValue = function() {
* @public
* @returns {void}
*/
JsonPath.prototype.setValue = function( value ) {
JsonPath.prototype.setValue = function( value, deepCopy ) {
var node = this._record._$data,
i;

for( i = 0; i < this._tokens.length - 1; i++ ) {
if( node[ this._tokens[ i ] ] !== undefined ) {
node = node[ this._tokens[ i ] ];
}
else if( this._tokens[ i + 1 ] && !isNaN( this._tokens[ i + 1 ] ) ){
node = node[ this._tokens[ i ] ] = [];
}
else {
node = node[ this._tokens[ i ] ] = {};
if ( deepCopy ) {
value = utils.deepCopy( value );
}

if ( this._tokens.length > 0 ) {
node = utils.deepCopy( node );

for( i = 0; i < this._tokens.length - 1; i++ ) {
if( node[ this._tokens[ i ] ] !== undefined ) {
node = node[ this._tokens[ i ] ];
}
else if( this._tokens[ i + 1 ] && !isNaN( this._tokens[ i + 1 ] ) ){
node = node[ this._tokens[ i ] ] = [];
}
else {
node = node[ this._tokens[ i ] ] = {};
}
}

node[ this._tokens[ i ] ] = value;
}
else {
node = value;
}

node[ this._tokens[ i ] ] = value;
this._record._$data = node;
};

/**
* Parses the path. Splits it into
* keys for objects and indices for arrays.
*
* @private
* @returns {void}
* @returns Array of tokens
*/
JsonPath.prototype._tokenize = function() {
var parts = this._path.split( SPLIT_REG_EXP ),
function tokenize( path ) {
var parts = path ? path.split( SPLIT_REG_EXP ) : [],
tokens = [],
part,
i;

Expand All @@ -90,17 +106,19 @@ JsonPath.prototype._tokenize = function() {
}

if( !isNaN( part ) ) {
this._tokens.push( parseInt( part, 10 ) );
tokens.push( parseInt( part, 10 ) );
continue;
}

if( part === ASTERISK ) {
this._tokens.push( true );
tokens.push( true );
continue;
}

this._tokens.push( part );
tokens.push( part );
}

return tokens;
};

module.exports = JsonPath;
module.exports = JsonPath;
46 changes: 18 additions & 28 deletions src/record/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ var Record = function( name, recordOptions, connection, options, client ) {
this._options = options;
this.isReady = false;
this.isDestroyed = false;
this._$data = {};
this._$data = Object.create( null );
this.version = null;
this._paths = {};
this._paths = Object.create( null );
this._oldValue = null;
this._oldPathValues = null;
this._eventEmitter = new EventEmitter();
Expand Down Expand Up @@ -87,15 +87,7 @@ Record.prototype.setMergeStrategy = function( mergeStrategy ) {
* @returns {Mixed} value
*/
Record.prototype.get = function( path ) {
var value;

if( path ) {
value = this._getPath( path ).getValue();
} else {
value = this._$data;
}

return utils.deepCopy( value );
return this._getPath( path ).getValue(this._options.recordDeepCopy);
};

/**
Expand Down Expand Up @@ -125,25 +117,27 @@ Record.prototype.set = function( pathOrData, data ) {
return this;
}

if( arguments.length === 2 && utils.deepEquals( this._getPath( pathOrData ).getValue(), data ) ) {
return this;
}
else if( arguments.length === 1 && utils.deepEquals( this._$data, pathOrData ) ) {
return this;
if (this._options.recordDeepCompare) {
if( arguments.length === 1 && utils.deepEquals( this._getPath().getValue(), pathOrData ) ) {
return this;
}
else if( arguments.length === 2 && utils.deepEquals( this._getPath( pathOrData ).getValue(), data ) ) {
return this;
}
}

this._beginChange();
this.version++;

if( arguments.length === 1 ) {
this._$data = ( typeof pathOrData == 'object' ) ? utils.deepCopy( pathOrData ) : pathOrData;
this._getPath().setValue( pathOrData, this._options.recordDeepCopy );
this._connection.sendMsg( C.TOPIC.RECORD, C.ACTIONS.UPDATE, [
this.name,
this.version,
this._$data
pathOrData
]);
} else {
this._getPath( pathOrData ).setValue( ( typeof data == 'object' ) ? utils.deepCopy( data ): data );
this._getPath( pathOrData ).setValue( data, this._options.recordDeepCopy );
this._connection.sendMsg( C.TOPIC.RECORD, C.ACTIONS.PATCH, [
this.name,
this.version,
Expand Down Expand Up @@ -185,11 +179,7 @@ Record.prototype.subscribe = function( path, callback, triggerNow ) {
if( args.triggerNow ) {
this.whenReady(function () {
this._eventEmitter.on( args.path || ALL_EVENT, args.callback );
if( args.path ) {
args.callback( this._getPath( args.path ).getValue() );
} else {
args.callback( this.get() );
}
args.callback( this.get( args.path ) );
}.bind(this));
} else {
this._eventEmitter.on( args.path || ALL_EVENT, args.callback );
Expand Down Expand Up @@ -421,7 +411,7 @@ Record.prototype._applyUpdate = function( message ) {
if( message.action === C.ACTIONS.PATCH ) {
this._getPath( message.data[ 2 ] ).setValue( data );
} else {
this._$data = data;
this._getPath().setValue( data );
}

this._completeChange();
Expand Down Expand Up @@ -502,10 +492,10 @@ Record.prototype._beginChange = function() {
var paths = Object.keys( this._eventEmitter._callbacks ),
i;

this._oldPathValues = {};
this._oldPathValues = Object.create( null );

if( this._eventEmitter.hasListeners( ALL_EVENT ) ) {
this._oldValue = this.get();
this._oldValue = this._getPath().getValue();
}

for( i = 0; i < paths.length; i++ ) {
Expand All @@ -524,7 +514,7 @@ Record.prototype._beginChange = function() {
* @returns {void}
*/
Record.prototype._completeChange = function() {
if( this._eventEmitter.hasListeners( ALL_EVENT ) && !utils.deepEquals( this._oldValue, this._$data ) ) {
if( this._eventEmitter.hasListeners( ALL_EVENT ) && (!this._options.recordDeepCompare || utils.deepEquals( this._getPath().getValue(), this._oldValue ) )) {
this._eventEmitter.emit( ALL_EVENT, this.get() );
}

Expand Down

0 comments on commit 504ca2e

Please sign in to comment.