DataValidator, ValidStateMonitor: Add #clearFailures argument
This allows clearing only the specified failures. * src/validate/ValidStateMonitor.js (clearFailures): Add `fields' argument. Make method more concise. (_fixFailure): Handle clearing `_failures' record. * src/validate/DataValidator.js (clearFailures): Add `fields' argument. * test/validate/ValidStateMonitorTest.js: Add test. * test/validate/DataValidatorTest.js: Add test.master
parent
e7700e8b69
commit
ed21707920
|
@ -159,13 +159,21 @@ module.exports = Class( 'DataValidator',
|
|||
|
||||
|
||||
/**
|
||||
* Clear all recorded failures
|
||||
* Clear specified failures, or otherwise all recorded failures
|
||||
*
|
||||
* `fields` must be a key-value map with the field name as the key and
|
||||
* an array of indexes as the value. Any field in `fields` that has no
|
||||
* failure is ignored.
|
||||
*
|
||||
* See `ValidStateMonitor#clearFailures` for more information.
|
||||
*
|
||||
* @param {Object} fields key-value names of fields/indexes to clear
|
||||
*
|
||||
* @return {DataValidator} self
|
||||
*/
|
||||
'public clearFailures'()
|
||||
'public clearFailures'( failures )
|
||||
{
|
||||
this._field_monitor.clearFailures();
|
||||
this._field_monitor.clearFailures( failures );
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
|
@ -263,7 +263,6 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
// looks like it has been resolved
|
||||
this._fixFailure( fixed, name, fail_i, result );
|
||||
|
||||
delete past_fail[ fail_i ];
|
||||
return true;
|
||||
} );
|
||||
} ) ).then( fixes => fixes.some( fix => fix === true ) );
|
||||
|
@ -328,48 +327,58 @@ module.exports = Class( 'ValidStateMonitor' )
|
|||
'private _fixFailure'( fixed, name, index, value )
|
||||
{
|
||||
( fixed[ name ] = fixed[ name ] || [] )[ index ] = value;
|
||||
|
||||
// caller is expected to have ensured that this exists
|
||||
delete this._failures[ name ][ index ];
|
||||
|
||||
return fixed;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Clear all recorded failures
|
||||
* Clear specified failures, or otherwise all recorded failures
|
||||
*
|
||||
* For each recorded failure, a `fix` even is emitted. All failure
|
||||
* records are then cleared.
|
||||
* `fields` must be a key-value map with the field name as the key and
|
||||
* an array of indexes as the value. Any field in `fields` that has no
|
||||
* failure is ignored.
|
||||
*
|
||||
* For each specified failure, a `fix` event is emitted. If no failures
|
||||
* are specified by `fields`, all recorded failures are marked as
|
||||
* fixed. If a field in `fields` is not known, it is ignored.
|
||||
*
|
||||
* Normally the resulting fix object contains the values that triggered
|
||||
* the fix. Instead, each fixed index will contain `undefined`.
|
||||
* the fix. Instead, each fixed index will contain `null`.
|
||||
*
|
||||
* This process is synchronous, and only a single `fix` event is emitted
|
||||
* after all failures have been cleared.
|
||||
*
|
||||
* @param {Object} fields key-value names of fields/indexes to clear
|
||||
*
|
||||
* @return {ValidStateMonitor} self
|
||||
*/
|
||||
'public clearFailures'()
|
||||
'public clearFailures'( fields )
|
||||
{
|
||||
const failures = this._failures;
|
||||
|
||||
let fixed = {};
|
||||
|
||||
for ( let name in this._failures )
|
||||
{
|
||||
const failure = this._failures[ name ];
|
||||
const isRequestedIndex = ( fields )
|
||||
? field => ( fields[ field.getName() ] || [] ).indexOf(
|
||||
field.getIndex()
|
||||
) !== -1
|
||||
: () => true;
|
||||
|
||||
for ( let cause_i in failure )
|
||||
{
|
||||
const cause = failure[ cause_i ];
|
||||
|
||||
for ( let cause_i in cause )
|
||||
{
|
||||
let fail_i = cause.getField().getIndex();
|
||||
|
||||
this._fixFailure( fixed, name, fail_i, undefined );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear _before_ emitting the fixes (listeners might trigger
|
||||
// additional failures, for example, or call `#hasFailures`)
|
||||
this._failures = {};
|
||||
Object.keys( failures )
|
||||
.reduce(
|
||||
( all_fields, name ) => all_fields.concat(
|
||||
failures[ name ].map( cause => cause.getField() )
|
||||
),
|
||||
[]
|
||||
)
|
||||
.filter( isRequestedIndex )
|
||||
.forEach( field => this._fixFailure(
|
||||
fixed, field.getName(), field.getIndex(), null
|
||||
) );
|
||||
|
||||
this.emit( 'fix', fixed );
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ describe( 'DataValidator', () =>
|
|||
|
||||
describe( '#clearFailures', () =>
|
||||
{
|
||||
it( 'marks all failures as fixed', () =>
|
||||
it( 'proxies to validator', () =>
|
||||
{
|
||||
const bvalidator = createMockBucketValidator();
|
||||
const vmonitor = ValidStateMonitor();
|
||||
|
@ -229,9 +229,14 @@ describe( 'DataValidator', () =>
|
|||
bvalidator, vmonitor, dep_factory, createStubStore()
|
||||
);
|
||||
|
||||
mock_vmonitor.expects( 'clearFailures' ).once();
|
||||
const failures = [ 'foo', 'bar' ];
|
||||
|
||||
expect( sut.clearFailures() )
|
||||
mock_vmonitor
|
||||
.expects( 'clearFailures' )
|
||||
.once()
|
||||
.withExactArgs( failures );
|
||||
|
||||
expect( sut.clearFailures( failures ) )
|
||||
.to.equal( sut );
|
||||
|
||||
mock_vmonitor.verify();
|
||||
|
|
|
@ -596,7 +596,7 @@ describe( 'ValidStateMonitor', function()
|
|||
|
||||
describe( '#clearFailures', () =>
|
||||
{
|
||||
it( 'clears all failures', () =>
|
||||
it( 'clears all failures when provided no arguments', () =>
|
||||
{
|
||||
return new Promise( ( accept, reject ) =>
|
||||
{
|
||||
|
@ -608,7 +608,7 @@ describe( 'ValidStateMonitor', function()
|
|||
.on( 'fix', fixed =>
|
||||
{
|
||||
expect( fixed )
|
||||
.to.deep.equal( { foo: [ undefined ] } );
|
||||
.to.deep.equal( { foo: [ null ] } );
|
||||
|
||||
expect( sut.hasFailures() ).to.be.false;
|
||||
|
||||
|
@ -620,6 +620,52 @@ describe( 'ValidStateMonitor', function()
|
|||
.catch( e => reject( e ) );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
it( 'clears only provided failures when provided array argument', () =>
|
||||
{
|
||||
return new Promise( ( accept, reject ) =>
|
||||
{
|
||||
mkstore( {} ).then( empty =>
|
||||
{
|
||||
const sut = Sut();
|
||||
|
||||
return sut
|
||||
.on( 'fix', fixed =>
|
||||
{
|
||||
debugger;
|
||||
// `bar' not cleared
|
||||
expect( fixed )
|
||||
.to.deep.equal( {
|
||||
foo: [ null ],
|
||||
baz: [ , null ],
|
||||
} );
|
||||
|
||||
// still has `bar'
|
||||
expect( sut.hasFailures() ).to.be.true;
|
||||
|
||||
accept( true );
|
||||
} )
|
||||
.update( empty, {
|
||||
foo: mkfail( 'foo', [ 'bar1', 'bar2' ] ),
|
||||
bar: mkfail( 'bar', [ 'baz' ] ),
|
||||
baz: mkfail( 'baz', [ 'quux', 'quuux' ] ),
|
||||
} )
|
||||
.then( sut => sut.clearFailures( {
|
||||
foo: [ 0 ],
|
||||
baz: [ 1 ],
|
||||
} ) );
|
||||
} )
|
||||
.catch( e => reject( e ) );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
it( 'does not error on non-existent failure', () =>
|
||||
{
|
||||
expect( () => Sut().clearFailures( [ 'foo', 'baz' ] ) )
|
||||
.to.not.throw( Error );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
|
Loading…
Reference in New Issue