Skip to content

Commit

Permalink
Merge pull request #5 from hoxton-one/feature/list-entries-by-index
Browse files Browse the repository at this point in the history
Adding index to addEntry/removeEntry in list
  • Loading branch information
yasserf committed May 28, 2015
2 parents 42932c3 + 02845b3 commit 385a777
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 40 deletions.
60 changes: 48 additions & 12 deletions dist/deepstream.js
Expand Up @@ -7749,7 +7749,7 @@ module.exports = JsonPath;
var EventEmitter = _dereq_( 'component-emitter' ),
Record = _dereq_( './record' ),
C = _dereq_( '../constants/constants' );

/**
* A List is a specialised Record that contains
* an Array of recordNames and provides a number
Expand All @@ -7764,7 +7764,7 @@ var List = function( recordHandler, name, options ) {
this._recordHandler = recordHandler;
this._record = this._recordHandler.getRecord( name, options );
this._record._applyUpdate = this._applyUpdate.bind( this );

this._record.on( 'delete', this.emit.bind( this, 'delete' ) );
this._record.on( 'discard', this.emit.bind( this, 'discard' ) );
this._record.on( 'ready', this._onReady.bind( this ) );
Expand Down Expand Up @@ -7826,7 +7826,7 @@ List.prototype.setEntries = function( entries ) {
throw new Error( errorMsg );
}
}

if( this._record.isReady === false ) {
this._queuedMethods.push( this.setEntries.bind( this, entries ) );
} else {
Expand All @@ -7838,23 +7838,25 @@ List.prototype.setEntries = function( entries ) {
* Removes an entry from the list
*
* @param {String} entry
* @param {Number} [index]
*
* @public
* @returns {void}
*/
List.prototype.removeEntry = function( entry ) {
List.prototype.removeEntry = function( entry, index ) {
if( this._record.isReady === false ) {
this._queuedMethods.push( this.removeEntry.bind( this, entry ) );
return;
}

var currentEntries = this._record.get(),
hasIndex = this._hasIndex( index ),
entries = [],
i;

for( i = 0; i < currentEntries.length; i++ ) {
if( currentEntries[ i ] !== entry ) {
entries.push( currentEntries[ i ] );
if( currentEntries[i] !== entry || ( hasIndex && index !== i ) ) {
entries.push( currentEntries[i] );
}
}

Expand All @@ -7865,22 +7867,28 @@ List.prototype.removeEntry = function( entry ) {
* Adds an entry to the list
*
* @param {String} entry
* @param {Number} [index]
*
* @public
* @returns {void}
*/
List.prototype.addEntry = function( entry ) {
List.prototype.addEntry = function( entry, index ) {
if( typeof entry !== 'string' ) {
throw new Error( 'Entry must be a recordName' );
}

if( this._record.isReady === false ) {
this._queuedMethods.push( this.addEntry.bind( this, entry ) );
return;
}

var hasIndex = this._hasIndex( index );
var entries = this.getEntries();
entries.push( entry );
if( hasIndex ) {
entries.splice( index, 0, entry );
} else {
entries.push( entry );
}
this._record.set( entries );
};

Expand Down Expand Up @@ -7927,11 +7935,11 @@ List.prototype.unsubscribe = function() {
*/
List.prototype._onReady = function() {
this.isReady = true;

for( var i = 0; i < this._queuedMethods.length; i++ ) {
this._queuedMethods[ i ]();
}

this.emit( 'ready' );
};

Expand All @@ -7957,7 +7965,31 @@ List.prototype._applyUpdate = function( message ) {
Record.prototype._applyUpdate.call( this._record, message );
};

/**
* Validates that the index provided is within the current set of entries.
*
* @param {Number} index
*
* @private
* @returns {Number}
*/
List.prototype._hasIndex = function( index ) {
var hasIndex = false;
var entries = this.getEntries();
if( index !== undefined ) {
if( isNaN( index ) ) {
throw new Error( 'Index must be a number' );
}
if( index >= entries.length || index < 0 ) {
throw new Error( 'Index must be within current entries' );
}
hasIndex = true;
}
return hasIndex;
};

module.exports = List;

},{"../constants/constants":42,"./record":53,"component-emitter":12}],51:[function(_dereq_,module,exports){
var C = _dereq_( '../constants/constants' );

Expand Down Expand Up @@ -8256,6 +8288,10 @@ Record.prototype.get = function( path ) {
* @returns {void}
*/
Record.prototype.set = function( pathOrData, data ) {
if( arguments.length === 1 && typeof pathOrData !== 'object' ) {
throw new Error( 'Invalid record data ' + pathOrData + ': Record data must be an object' );
}

if( this._checkDestroyed( 'set' ) ) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions dist/deepstream.min.js

Large diffs are not rendered by default.

57 changes: 44 additions & 13 deletions src/record/list.js
@@ -1,7 +1,7 @@
var EventEmitter = require( 'component-emitter' ),
Record = require( './record' ),
C = require( '../constants/constants' );

/**
* A List is a specialised Record that contains
* an Array of recordNames and provides a number
Expand All @@ -16,7 +16,7 @@ var List = function( recordHandler, name, options ) {
this._recordHandler = recordHandler;
this._record = this._recordHandler.getRecord( name, options );
this._record._applyUpdate = this._applyUpdate.bind( this );

this._record.on( 'delete', this.emit.bind( this, 'delete' ) );
this._record.on( 'discard', this.emit.bind( this, 'discard' ) );
this._record.on( 'ready', this._onReady.bind( this ) );
Expand Down Expand Up @@ -78,7 +78,7 @@ List.prototype.setEntries = function( entries ) {
throw new Error( errorMsg );
}
}

if( this._record.isReady === false ) {
this._queuedMethods.push( this.setEntries.bind( this, entries ) );
} else {
Expand All @@ -90,23 +90,25 @@ List.prototype.setEntries = function( entries ) {
* Removes an entry from the list
*
* @param {String} entry
* @param {Number} [index]
*
* @public
* @returns {void}
*/
List.prototype.removeEntry = function( entry ) {
List.prototype.removeEntry = function( entry, index ) {
if( this._record.isReady === false ) {
this._queuedMethods.push( this.removeEntry.bind( this, entry ) );
return;
}

var currentEntries = this._record.get(),
hasIndex = this._hasIndex( index ),
entries = [],
i;

for( i = 0; i < currentEntries.length; i++ ) {
if( currentEntries[ i ] !== entry ) {
entries.push( currentEntries[ i ] );
if( currentEntries[i] !== entry || ( hasIndex && index !== i ) ) {
entries.push( currentEntries[i] );
}
}

Expand All @@ -117,22 +119,28 @@ List.prototype.removeEntry = function( entry ) {
* Adds an entry to the list
*
* @param {String} entry
* @param {Number} [index]
*
* @public
* @returns {void}
*/
List.prototype.addEntry = function( entry ) {
List.prototype.addEntry = function( entry, index ) {
if( typeof entry !== 'string' ) {
throw new Error( 'Entry must be a recordName' );
}

if( this._record.isReady === false ) {
this._queuedMethods.push( this.addEntry.bind( this, entry ) );
return;
}

var hasIndex = this._hasIndex( index );
var entries = this.getEntries();
entries.push( entry );
if( hasIndex ) {
entries.splice( index, 0, entry );
} else {
entries.push( entry );
}
this._record.set( entries );
};

Expand Down Expand Up @@ -179,11 +187,11 @@ List.prototype.unsubscribe = function() {
*/
List.prototype._onReady = function() {
this.isReady = true;

for( var i = 0; i < this._queuedMethods.length; i++ ) {
this._queuedMethods[ i ]();
}

this.emit( 'ready' );
};

Expand All @@ -209,4 +217,27 @@ List.prototype._applyUpdate = function( message ) {
Record.prototype._applyUpdate.call( this._record, message );
};

module.exports = List;
/**
* Validates that the index provided is within the current set of entries.
*
* @param {Number} index
*
* @private
* @returns {Number}
*/
List.prototype._hasIndex = function( index ) {
var hasIndex = false;
var entries = this.getEntries();
if( index !== undefined ) {
if( isNaN( index ) ) {
throw new Error( 'Index must be a number' );
}
if( index >= entries.length || index < 0 ) {
throw new Error( 'Index must be within current entries' );
}
hasIndex = true;
}
return hasIndex;
};

module.exports = List;
40 changes: 27 additions & 13 deletions test-unit/unit/record/list-spec.js
Expand Up @@ -11,7 +11,7 @@ describe( 'lists contain arrays of record names', function(){
recordHandler = new RecordHandler( options, new ConnectionMock(), new ClientMock() ),
readyCallback = jasmine.createSpy( 'ready' ),
changeCallback = jasmine.createSpy( 'change' );

it( 'creates the list', function(){
list = new List( recordHandler, 'someList', {} );
list.subscribe( changeCallback );
Expand All @@ -21,12 +21,12 @@ describe( 'lists contain arrays of record names', function(){
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|CR|someList+' ) );
expect( readyCallback ).not.toHaveBeenCalled();
});

it( 'starts with an empty array', function(){
expect( list.getEntries() ).toEqual( [] );
expect( list.isEmpty() ).toBe( true );
});

it( 'receives a response from the server', function() {
recordHandler._$handle({
topic: 'R',
Expand All @@ -38,28 +38,42 @@ describe( 'lists contain arrays of record names', function(){
expect( readyCallback ).toHaveBeenCalled();
expect( list.isEmpty() ).toBe( false );
});
it( 'adds an entry to the list', function(){

it( 'adds an entry to the end of list', function(){
list.addEntry( 'entryC' );
expect( list.getEntries() ).toEqual(['entryA', 'entryB', 'entryC' ]);
expect( changeCallback ).toHaveBeenCalledWith(['entryA', 'entryB', 'entryC' ]);
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|2|["entryA","entryB","entryC"]+' ) );
});

it( 'removes an entry from the list', function(){
list.removeEntry( 'entryB' );
expect( list.getEntries() ).toEqual(['entryA', 'entryC' ]);
expect( changeCallback ).toHaveBeenCalledWith(['entryA', 'entryC' ]);
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|3|["entryA","entryC"]+' ) );
});


it( 'adds an entry to the list at a explicit index', function(){
list.addEntry( 'entryD', 1 );
expect( list.getEntries() ).toEqual(['entryA', 'entryD', 'entryC' ]);
expect( changeCallback ).toHaveBeenCalledWith(['entryA', 'entryD', 'entryC' ]);
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|4|["entryA","entryD","entryC"]+' ) );
});

it( 'removes an entry to the list at a explicit index', function(){
list.removeEntry( 'entryD', 1 );
expect( list.getEntries() ).toEqual(['entryA', 'entryC' ]);
expect( changeCallback ).toHaveBeenCalledWith(['entryA', 'entryC' ]);
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|5|["entryA","entryC"]+' ) );
});

it( 'sets the entire list', function(){
list.setEntries([ 'u','v' ]);
expect( list.getEntries() ).toEqual([ 'u','v' ]);
expect( changeCallback ).toHaveBeenCalledWith([ 'u','v' ]);
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|4|["u","v"]+' ) );
expect( recordHandler._connection.lastSendMessage ).toBe( msg( 'R|U|someList|6|["u","v"]+' ) );
});

it( 'handles server updates', function(){
recordHandler._$handle({
topic: 'R',
Expand All @@ -69,11 +83,11 @@ describe( 'lists contain arrays of record names', function(){
expect( list.getEntries() ).toEqual([ 'x','y' ]);
expect( changeCallback ).toHaveBeenCalledWith([ 'x','y' ]);
});

it( 'unsubscribes', function(){
expect( changeCallback.calls.length ).toBe( 5 );
expect( changeCallback.calls.length ).toBe( 7 );
list.unsubscribe( changeCallback );
list.setEntries([ 'q' ]);
expect( changeCallback.calls.length ).toBe( 5 );
expect( changeCallback.calls.length ).toBe( 7 );
});
});
});

0 comments on commit 385a777

Please sign in to comment.