diff --git a/src/bucket/delta.ts b/src/bucket/delta.ts index 429873d..58c75ec 100644 --- a/src/bucket/delta.ts +++ b/src/bucket/delta.ts @@ -161,9 +161,8 @@ function _deepEqual( a: any, b: any ): boolean return false; } - return a.map( ( item, i ) => _deepEqual( item, b[ i ] ) ) - .every( res => res === true ); + return a.every( ( item, i ) => _deepEqual( item, b[ i ] ) ); } - return ''+a === ''+b; + return a === b; } diff --git a/src/server/Server.js b/src/server/Server.js index 8cbdcf7..3993640 100644 --- a/src/server/Server.js +++ b/src/server/Server.js @@ -1144,14 +1144,28 @@ module.exports = Class( 'Server' ) { try { + var rdelta_data; var parsed_data = JSON.parse( post_data.data ); var bucket = quote.getBucket(); - const { filtered, dapis, meta_clear } = + const { filtered, dapis, meta_clear, rdiff } = server._dataProcessor.processDiff( parsed_data, request, program, bucket, quote ); + // Leave rdelta_data undefined if rdiff is an empty object + if ( Object.keys( rdiff ).length > 0 ) + { + rdelta_data = { + "rdelta.data": { + data: rdiff, + timestamp: Math.round( + new Date().getTime() / 1000 + ), + } + }; + } + server._monitorMetadataPromise( quote, dapis, meta_clear ); } catch ( err ) @@ -1173,7 +1187,7 @@ module.exports = Class( 'Server' ) } // save the quote - server._doQuoteSave( step_id, request, quote, program ); + server._doQuoteSave( step_id, request, quote, program, rdelta_data); }); return this; @@ -1205,7 +1219,14 @@ module.exports = Class( 'Server' ) }, - 'private _doQuoteSave': function( step_id, request, quote, program, c ) + 'private _doQuoteSave': function( + step_id, + request, + quote, + program, + rdelta_data, + c + ) { var server = this; @@ -1258,7 +1279,9 @@ module.exports = Class( 'Server' ) ); c && c( false ); - } + }, + undefined, + rdelta_data ); } ); }, diff --git a/src/server/daemon/controller.js b/src/server/daemon/controller.js index 501618d..06b7a5e 100644 --- a/src/server/daemon/controller.js +++ b/src/server/daemon/controller.js @@ -43,6 +43,7 @@ var rating_service = null; const { bucket: { QuoteDataBucket, + delta }, dapi: { @@ -141,7 +142,7 @@ exports.init = function( logger, enc_service, conf ) rating_service = easejs( RatingService ).use( RatingServicePublish( amqplib, exports.post_rate_publish, logger ) )( - logger, dao, server, exports.rater + logger, dao, server, exports.rater, delta.createDelta ); // TODO: exports.init needs to support callbacks; this will work, but diff --git a/src/server/service/RatingService.ts b/src/server/service/RatingService.ts index df81c18..ea4667e 100644 --- a/src/server/service/RatingService.ts +++ b/src/server/service/RatingService.ts @@ -31,6 +31,7 @@ import { ServerDao } from "../db/ServerDao"; import { ServerSideQuote } from "../quote/ServerSideQuote"; import { UserRequest } from "../request/UserRequest"; import { UserResponse } from "../request/UserResponse"; +import { DeltaConstructor } from "../../bucket/delta"; type RequestCallback = () => void; @@ -59,12 +60,14 @@ export class RatingService * @param _dao - database connection * @param _server - server actions * @param _rater_manager - rating manager + * @param _createDelta - delta constructor */ constructor( private readonly _logger: PriorityLog, private readonly _dao: ServerDao, private readonly _server: Server, private readonly _rater_manager: ProcessManager, + private readonly _createDelta: DeltaConstructor, ) {} @@ -271,12 +274,19 @@ export class RatingService quote.setLastPremiumDate( cur_date ); quote.setRatedDate( cur_date ); + const quote_data = quote.getRatingData(); + const save_data = { ratedata: data }; + const rdelta_data = { + "rdelta.ratedata": { + data: this._createDelta( data, quote_data ), + timestamp: cur_date + }, + }; + // save the last prem status (we pass an empty object as the save // data argument to ensure that we do not save the actual bucket // data, which may cause a race condition with the below merge call) - this._dao.saveQuote( quote, c, c, { - ratedata: data, - }, {} ); + this._dao.saveQuote( quote, c, c, save_data, rdelta_data ); } else { diff --git a/test/server/service/RatingServiceTest.ts b/test/server/service/RatingServiceTest.ts index 5dd821f..8896c49 100644 --- a/test/server/service/RatingServiceTest.ts +++ b/test/server/service/RatingServiceTest.ts @@ -36,6 +36,7 @@ import { UserRequest } from "../../../src/server/request/UserRequest"; import { UserResponse } from "../../../src/server/request/UserResponse"; import { UserSession } from "../../../src/server/request/UserSession"; import { QuoteDataBucket } from "../../../src/bucket/QuoteDataBucket"; +import { Kv } from "../../../src/bucket/delta"; import { ServerDao, @@ -59,9 +60,10 @@ describe( 'RatingService', () => response, quote, stub_rate_data, + createDelta, } = getStubs(); - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta); const expected = { data: stub_rate_data, @@ -85,9 +87,10 @@ describe( 'RatingService', () => response, quote, stub_rate_data, + createDelta, } = getStubs(); - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); let last_prem_called = false; let rated_date_called = false; @@ -152,6 +155,7 @@ describe( 'RatingService', () => response, quote, stub_rate_data, + createDelta, } = getStubs(); let saved_rates = false; @@ -172,7 +176,7 @@ describe( 'RatingService', () => return dao; }; - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); return sut.request( request, response, quote, "" ) .then( () => @@ -182,6 +186,55 @@ describe( 'RatingService', () => } ); + it( "saves delta to it's own field", () => + { + const { + logger, + server, + raters, + dao, + request, + response, + quote, + stub_rate_delta, + createDelta, + } = getStubs(); + + let saved_quote = false; + + let timestamp = 0; + + quote.setLastPremiumDate = ( ts: UnixTimestamp ) => + { + timestamp = ts; + return quote; + }; + + dao.saveQuote = ( + quote: ServerSideQuote, + success: ServerDaoCallback, + _failure: ServerDaoCallback, + _save_data: Record, + push_data: Record, + ) => + { + stub_rate_delta[ "rdelta.ratedata" ].timestamp = timestamp; + saved_quote = true; + + expect( push_data ).to.deep.equal( stub_rate_delta ); + success( quote ); + + return dao; + }; + + const sut = new Sut( logger, dao, server, raters, createDelta ); + + return sut.request( request, response, quote, "" ) + .then( () => { expect( saved_quote ).to.be.true; } ); + } ); + + + it( "rejects and responds with error", () => { const { @@ -194,13 +247,14 @@ describe( 'RatingService', () => request, response, server, + createDelta, } = getStubs(); const expected_error = new Error( "expected error" ); rater.rate = () => { throw expected_error; }; - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); let logged = false; @@ -242,11 +296,12 @@ describe( 'RatingService', () => request, response, server, + createDelta, } = getStubs(); const expected_message = 'expected foo'; - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); rater.rate = ( _quote: ServerSideQuote, @@ -279,6 +334,7 @@ describe( 'RatingService', () => response, server, stub_rate_data, + createDelta, } = getStubs(); let sent = false; @@ -304,7 +360,7 @@ describe( 'RatingService', () => return server; }; - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); return sut.request( request, response, quote, "" ) .then( () => expect( sent ).to.be.true ); @@ -325,6 +381,7 @@ describe( 'RatingService', () => request, response, quote, + createDelta, } = getStubs(); dao.mergeBucket = () => @@ -341,7 +398,7 @@ describe( 'RatingService', () => { processed = true; } - }( logger, dao, server, raters ); + }( logger, dao, server, raters, createDelta ); sut.request( request, response, quote, 'something' ); } ); @@ -361,6 +418,7 @@ describe( 'RatingService', () => request, response, quote, + createDelta, } = getStubs(); quote.getLastPremiumDate = () => @@ -371,7 +429,7 @@ describe( 'RatingService', () => quote.getRatedDate = () => initial_date; - const sut = new Sut( logger, dao, server, raters ); + const sut = new Sut( logger, dao, server, raters, createDelta ); server.sendResponse = ( _request: any, _quote: any, resp: any, _actions: any ) => { @@ -404,6 +462,19 @@ function getStubs() _unavailable_all: '0', }; + const stub_rate_delta: any = { + "rdelta.ratedata": { + data: { + _unavailable_all: [ undefined ] + }, + timestamp: 123 + } + }; + + const createDelta = ( _src: Kv, _dest: Kv ) => { + return stub_rate_delta[ "rdelta.ratedata" ][ "data" ]; + }; + const rater = new class implements Rater { rate( @@ -518,16 +589,18 @@ function getStubs() }; return { - program: program, - stub_rate_data: stub_rate_data, - rater: rater, - raters: raters, - logger: logger, - server: server, - dao: dao, - session: session, - request: request, - response: response, - quote: quote, + program: program, + stub_rate_data: stub_rate_data, + stub_rate_delta: stub_rate_delta, + createDelta: createDelta, + rater: rater, + raters: raters, + logger: logger, + server: server, + dao: dao, + session: session, + request: request, + response: response, + quote: quote, }; };