diff --git a/src/bucket/QuoteDataBucket.d.ts b/src/bucket/QuoteDataBucket.d.ts
new file mode 100644
index 0000000..7f1c8e6
--- /dev/null
+++ b/src/bucket/QuoteDataBucket.d.ts
@@ -0,0 +1,123 @@
+/**
+ * Key/value store
+ *
+ * Copyright (C) 2010-2019 R-T Specialty, LLC.
+ *
+ * This file is part of liza.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+import { PositiveInteger } from "../numeric";
+
+
+/**
+ * General key/value store for document
+ *
+ * The term "Quote" here is an artifact from the initial design of the
+ * system used for insurance quoting. It will be renamed.
+ *
+ * @todo Rename to DocumentDataBucket
+ */
+export declare class QuoteDataBucket
+{
+ /**
+ * Triggered when data in the bucket is updated, before it's committed
+ */
+ static readonly EVENT_UPDATE: string;
+
+
+ /**
+ * Explicitly sets the contents of the bucket
+ *
+ * @param data - associative array of the data
+ */
+ setValues( data: Record ): this;
+
+
+ /**
+ * Alias of setValues
+ */
+ setCommittedValues(): this;
+
+
+ /**
+ * Clears all data from the bucket
+ */
+ clear(): this;
+
+
+ /**
+ * Overwrites values in the original bucket
+ *
+ * For this buckeet, overwriteValues() is an alias for setValues() without
+ * index merging. However, other Bucket implementations may handle it
+ * differently.
+ *
+ * @param data - associative array of the data
+ */
+ overwriteValues( data: Record ): this;
+
+
+ /**
+ * Calls a function for each each of the values in the bucket
+ *
+ * Note: This format is intended to be consistent with Array.forEach()
+ *
+ * @param callback - function to call for each value in the bucket
+ */
+ each( callback: ( val: any, key: string) => {} ): this;
+
+
+ /**
+ * Calls a function for each each of the values in the bucket matching the
+ * given predicate
+ *
+ * @param pred - predicate
+ * @param c - function to call for each value in the bucket
+ */
+ filter(
+ pred: ( key: string ) => {},
+ _c: ( val: any, key: string) => {}
+ ): this;
+
+
+ /**
+ * Returns the data for the requested field
+ *
+ * @param name - name of the field (with or without trailing brackets)
+ *
+ * @return data for the field, or empty array if none
+ */
+ getDataByName( name: string ): any;
+
+
+ /**
+ * Returns the data as a JSON string
+ *
+ * @return data represented as JSON
+ */
+ getDataJson(): string;
+
+
+ /**
+ * Return raw bucket data
+ *
+ * TODO: remove; breaks encapsulation
+ *
+ * @return raw bucket data
+ */
+ getData(): Record;
+}
diff --git a/src/bucket/StagingBucket.d.ts b/src/bucket/StagingBucket.d.ts
new file mode 100644
index 0000000..a96341f
--- /dev/null
+++ b/src/bucket/StagingBucket.d.ts
@@ -0,0 +1,206 @@
+/**
+ * StagingBucket class
+ *
+ * Copyright (C) 2010-2019 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { PositiveInteger } from "../numeric";
+
+
+export type StagingBucketConstructor = (
+ bucket: StagingBucket
+) => StagingBucket;
+
+
+/**
+ * Stages and merges values into underlying key/value store
+ */
+export declare class StagingBucket
+{
+ /**
+ * Analgous to setValues(), but immediately commits the changes
+ *
+ * This still calls setValues() to ensure all events are properly kicked
+ * off.
+ *
+ * @param data - data to set and commit
+ */
+ setCommittedValues( data: Record ): this;
+
+
+ /**
+ * Prevent #setCommittedValues from bypassing staging
+ *
+ * When set, #setCommittedValues will act as an alias of #setValues.
+ */
+ forbidBypass(): this;
+
+
+ /**
+ * Explicitly sets the contents of the bucket
+ *
+ * Because JSON serializes all undefined values to `null`, only the
+ * final null in a diff is considered terminating; the rest are
+ * converted into `undefined`. Therefore, it is important that all
+ * truncations include no elements in the vector after the truncating null.
+ *
+ * @param given_data - associative array of the data
+ */
+ setValues( given_data: Record ): this;
+
+
+ /**
+ * Overwrites values in the original bucket
+ *
+ * @param data - associative array of the data
+ */
+ overwriteValues( data: Record ): this;
+
+
+ /**
+ * Returns staged data
+ *
+ * @return staged data
+ */
+ getDiff(): Record;
+
+
+ /**
+ * Returns a field-oriented diff filled with all values rather than a
+ * value-oriented diff
+ *
+ * Only the fields that have changed are returned. Each field contains its
+ * actual value---not the diff representation of what portions of the field
+ * have changed.
+ *
+ * @return filled diff
+ */
+ getFilledDiff(): Record;
+
+
+ /**
+ * Reverts staged changes, preventing them from being committed
+ *
+ * This will also generate a diff and raise the same events that would be
+ * raised by setting values in the conventional manner, allowing reverts to
+ * transparently integrate with the remainder of the system.
+ *
+ * @param evented - whether to emit events as part of the revert
+ */
+ revert( evented?: boolean ): this;
+
+
+ /**
+ * Commits staged changes, merging them with the bucket
+ *
+ * @param store - object to save old staged values to
+ */
+ commit( store?: { old: Record } ): this
+
+
+ /**
+ * Clears all data from the bucket
+ */
+ clear(): this;
+
+
+ /**
+ * Calls a function for each each of the values in the bucket
+ *
+ * @param callback - function to call for each value in the bucket
+ */
+ each( callback: ( value: any, name: string ) => void ): this;
+
+
+ /**
+ * Returns the data for the requested field
+ *
+ * WARNING: This can be a potentially expensive operation if there is a
+ * great deal of staged data. The staged data is merged with the bucket data
+ * on each call. Do not make frequent calls to retrieve the same data. Cache
+ * it instead.
+ *
+ * @param name - field name (with or without trailing brackets)
+ *
+ * @return data for the field, or empty array if none
+ */
+ getDataByName( name: string ): Record;
+
+
+ /**
+ * Returns original bucket data by name, even if there is data staged atop
+ * of it
+ *
+ * There is no additional overhead of this operation versus getDataByName()
+ *
+ * @param name - field name (with or without trailing brackets)
+ *
+ * @return data for the field, or empty array if none
+ */
+ getOriginalDataByName( name: string ): Record;
+
+
+ /**
+ * Returns the data as a JSON string
+ *
+ * @return data represented as JSON
+ */
+ getDataJson(): string;
+
+
+ /**
+ * Return raw bucket data
+ *
+ * todo: remove; breaks encapsulation
+ *
+ * @return raw bucket data
+ */
+ getData(): Record;
+
+
+ /**
+ * Calls a function for each each of the values in the bucket matching the
+ * given predicate
+ *
+ * @param pred - predicate
+ * @param c - function to call for each value in the bucket
+ */
+ filter(
+ pred: ( name: string ) => boolean,
+ c: ( value: any, name: string ) => void
+ ): this;
+
+
+ /**
+ * Returns true if the index for the given key exists
+ *
+ * @param name - the data key
+ * @param i - the index
+ *
+ * @return whether the key exists
+ */
+ hasIndex( name: string, i: PositiveInteger ): boolean;
+
+
+ /**
+ * Returns true if the bucket has been changed and not saved
+ *
+ * @return true if the bucket has been changed and not saved
+ */
+ isDirty(): boolean;
+}
diff --git a/src/bucket/bucket_filter.d.ts b/src/bucket/bucket_filter.d.ts
new file mode 100644
index 0000000..f731956
--- /dev/null
+++ b/src/bucket/bucket_filter.d.ts
@@ -0,0 +1,65 @@
+/**
+ * Filters bucket data
+ *
+ * Copyright (C) 2010-2019 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+export declare module bucket_filter {
+
+ export type filter = {
+ /**
+ * Filters bucket data based on the provided types
+ *
+ * If a type is not provided, the data is considered to be unwanted and is
+ * removed entirely. Otherwise, the filter is applied to every element in the
+ * array.
+ *
+ * The data is modified in place.
+ *
+ * @param data - data to filter
+ * @param key_types - filter types
+ * @param ignore_types - types to ignore
+ * @param permit_null - Allow nulls in results
+ *
+ * @return Object modified data
+ */
+ filter(
+ data: Record,
+ key_types: Record,
+ ignore_types: Record,
+ permit_null: boolean,
+ ): Record
+
+
+ /**
+ * Filter bucket data based on values
+ *
+ * @param values - The values to filter
+ * @param filter - The filter to apply
+ * @param permit_null - Allow nulls in results
+ *
+ * @return the filtered values
+ */
+ filterValues(
+ values: string[],
+ filter: string,
+ permit_null: boolean,
+ ): string[];
+ };
+}
diff --git a/src/program/Program.d.ts b/src/program/Program.d.ts
index de3f45a..ec45efc 100644
--- a/src/program/Program.d.ts
+++ b/src/program/Program.d.ts
@@ -19,9 +19,13 @@
* along with this program. If not, see .
*/
+import { StagingBucket } from "../bucket/StagingBucket";
+
export declare abstract class Program
{
readonly ineligibleLockCount: number;
getId(): string;
+
+ initQuote( bucket: StagingBucket, store_only: boolean ): void
}
diff --git a/src/quote/BaseQuote.d.ts b/src/quote/BaseQuote.d.ts
index 9af47ee..f2271f4 100644
--- a/src/quote/BaseQuote.d.ts
+++ b/src/quote/BaseQuote.d.ts
@@ -23,6 +23,7 @@
import { Program } from "../program/Program";
import { Quote, QuoteId } from "./Quote";
+import { QuoteDataBucket } from "../bucket/QuoteDataBucket";
export declare class BaseQuote implements Quote
@@ -90,4 +91,12 @@ export declare class BaseQuote implements Quote
* @return last calculated time or 0
*/
getLastPremiumDate(): UnixTimestamp;
+
+
+ /**
+ * Returns the bucket used to store the quote form data
+ *
+ * @return the data bucket
+ */
+ getBucket(): QuoteDataBucket
}
diff --git a/src/server/quote/ServerSideQuote.d.ts b/src/server/quote/ServerSideQuote.d.ts
index 98eff98..c8bdf2f 100644
--- a/src/server/quote/ServerSideQuote.d.ts
+++ b/src/server/quote/ServerSideQuote.d.ts
@@ -23,6 +23,7 @@
import { Program } from "../../program/Program";
import { BaseQuote } from "../../quote/BaseQuote";
+import { QuoteDataBucket } from "../../bucket/QuoteDataBucket";
export declare class ServerSideQuote extends BaseQuote
@@ -43,4 +44,28 @@ export declare class ServerSideQuote extends BaseQuote
* @return self
*/
setRatedDate( timestamp: UnixTimestamp ): this;
+
+
+ /**
+ * Set rating bucket
+ *
+ * @param bucket - the data bucket
+ */
+ setRateBucket( bucket: QuoteDataBucket ): this;
+
+
+ /**
+ * Set rating data
+ *
+ * @param data - rating data
+ */
+ setRatingData( data: Record ): this;
+
+
+ /**
+ * Get rating data
+ *
+ * @return rating data
+ */
+ getRatingData(): Record;
}
diff --git a/src/server/quote/ServerSideQuote.js b/src/server/quote/ServerSideQuote.js
index b1040c3..3d5f7c0 100644
--- a/src/server/quote/ServerSideQuote.js
+++ b/src/server/quote/ServerSideQuote.js
@@ -40,7 +40,6 @@ module.exports = Class( 'ServerSideQuote' )
*/
'private _creditScoreRef': 0,
-
/**
* Unix timestamp containing date of first premium calculation
* @type {number}
@@ -53,6 +52,12 @@ module.exports = Class( 'ServerSideQuote' )
*/
'private _metabucket': null,
+ /**
+ * Rating Data Bucket
+ * @type {Bucket}
+ */
+ 'private _rate_bucket': null,
+
'public setProgramVersion': function( version )
{
@@ -148,6 +153,64 @@ module.exports = Class( 'ServerSideQuote' )
this._metabucket.setValues( data );
return this;
- }
+ },
+
+
+ /**
+ * Set rating bucket
+ *
+ * @param {Bucket} bucket the rate bucket to set
+ */
+ 'public setRateBucket': function( bucket )
+ {
+ this._rate_bucket = bucket;
+
+ return this;
+ },
+
+
+ /**
+ * Get rating bucket
+ *
+ * @return {Bucket}
+ */
+ 'public getRateBucket': function()
+ {
+ return this._rate_bucket;
+ },
+
+
+ /**
+ * Set rating data
+ *
+ * @param {Object.} data rating data
+ */
+ 'public setRatingData': function( data )
+ {
+ if ( !this._rate_bucket )
+ {
+ throw Error( "No rating bucket available for #setRatingData" );
+ }
+
+ this._rate_bucket.setValues( data );
+
+ return this;
+ },
+
+
+ /**
+ * Get rating data
+ *
+ * @return {Object.} rating data
+ */
+ 'public getRatingData': function()
+ {
+ if ( !this._rate_bucket )
+ {
+ throw Error( "No rating bucket available for #setRatingData" );
+ }
+
+ return this._rate_bucket.getData();
+ },
} );
diff --git a/src/server/request/DataProcessor.ts b/src/server/request/DataProcessor.ts
index 3d549e0..7483132 100644
--- a/src/server/request/DataProcessor.ts
+++ b/src/server/request/DataProcessor.ts
@@ -18,7 +18,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+import { StagingBucket, StagingBucketConstructor } from "../../bucket/StagingBucket";
import { PositiveInteger } from "../../numeric";
+import { bucket_filter } from "../../bucket/bucket_filter";
import { UserRequest } from "./UserRequest";
/**
@@ -41,10 +43,10 @@ export class DataProcessor
* @param staging_ctor - staging bucket constructor
*/
constructor(
- private readonly _filter: any,
+ private readonly _filter: bucket_filter.filter,
private readonly _dapif: any,
private readonly _meta_source: any,
- private readonly _stagingCtor: any,
+ private readonly _stagingCtor: StagingBucketConstructor,
) {}
@@ -169,7 +171,7 @@ export class DataProcessor
dapi_manager: any,
program: any,
data: Record,
- bucket: any,
+ bucket: StagingBucket,
): [ any, Record ]
{
const {
@@ -292,7 +294,7 @@ export class DataProcessor
*/
private _mapDapiData(
dapi: any,
- bucket: any,
+ bucket: StagingBucket,
index: PositiveInteger,
diff_data: Record,
): Record
diff --git a/test/server/quote/ServerSideQuoteTest.js b/test/server/quote/ServerSideQuoteTest.js
index aea8cc8..8e92a67 100644
--- a/test/server/quote/ServerSideQuoteTest.js
+++ b/test/server/quote/ServerSideQuoteTest.js
@@ -21,8 +21,14 @@
'use strict';
-const { expect } = require( 'chai' );
-const Sut = require( '../../..' ).server.quote.ServerSideQuote;
+const root = require( '../../..' );
+const Sut = require( '../../..' ).server.quote.ServerSideQuote;
+const expect = require( 'chai' ).expect;
+const sinon = require( 'sinon' );
+
+const {
+ QuoteDataBucket,
+} = root.bucket;
describe( 'ServerSideQuote', () =>
{
@@ -31,80 +37,85 @@ describe( 'ServerSideQuote', () =>
[
{
property: 'startDate',
- default: 0,
- value: 946684800
+ default: 0,
+ value: 946684800
},
{
property: 'initialRatedDate',
- default: 0,
- value: 946684800
+ default: 0,
+ value: 946684800
},
{
property: 'agentId',
- default: 0,
- value: 12345678
+ default: 0,
+ value: 12345678
},
{
property: 'agentEntityId',
- default: 0,
- value: 12345678
+ default: 0,
+ value: 12345678
},
{
property: 'agentName',
- default: '',
- value: 'name'
+ default: '',
+ value: 'name'
},
{
property: 'imported',
- default: false,
- value: true,
+ default: false,
+ value: true,
accessor: 'is'
},
{
property: 'bound',
- default: false,
- value: true,
+ default: false,
+ value: true,
accessor: 'is'
},
{
property: 'currentStepId',
- default: 1,
- value: 2
+ default: 1,
+ value: 2
},
{
property: 'topVisitedStepId',
- default: 1,
- value: 2
+ default: 1,
+ value: 2
},
{
property: 'topSavedStepId',
- value: 1
+ value: 1
},
{
property: 'error',
- default: '',
- value: 'ERROR'
+ default: '',
+ value: 'ERROR'
},
{
property: 'programVersion',
- default: '',
- value: '1.0.0'
+ default: '',
+ value: '1.0.0'
},
{
property: 'creditScoreRef',
- default: 0,
- value: 800
+ default: 0,
+ value: 800
},
{
property: 'lastPremiumDate',
- default: 0,
- value: 946684800
+ default: 0,
+ value: 946684800
},
{
property: 'ratedDate',
- default: 0,
- value: 946684800
- }
+ default: 0,
+ value: 946684800
+ },
+ {
+ property: 'rateBucket',
+ default: null,
+ value: QuoteDataBucket()
+ },
].forEach( testCase =>
{
@@ -122,4 +133,44 @@ describe( 'ServerSideQuote', () =>
} );
} );
} );
-} );
\ No newline at end of file
+
+ describe( 'rating data', () =>
+ {
+ it( `#setRatingData throws an error if no bucket is set`, () =>
+ {
+ const data = { foo: 'bar' };
+ const sut = Sut();
+
+ expect( function() { sut.setRatingData( data ); } )
+ .to.throw( Error );
+ } );
+
+ it( `Bucket values setters/getters work correctly`, () =>
+ {
+ const data = { foo: 'bar' };
+ let bucket_data = null;
+ const sut = Sut();
+ var called = false;
+
+ const bucket = {
+ setValues( gdata )
+ {
+ expect( gdata ).to.deep.equal( data );
+
+ bucket_data = gdata;
+ called = true;
+ },
+
+ getData()
+ {
+ return bucket_data;
+ },
+ };
+
+ sut.setRateBucket( bucket );
+ sut.setRatingData( data );
+
+ expect( called ).to.equal( true );
+ } );
+ } );
+} );
diff --git a/test/server/request/DataProcessorTest.ts b/test/server/request/DataProcessorTest.ts
index faf69bf..361d99a 100644
--- a/test/server/request/DataProcessorTest.ts
+++ b/test/server/request/DataProcessorTest.ts
@@ -25,6 +25,7 @@ import { DocumentId } from "../../../src/document/Document";
import { PositiveInteger } from "../../../src/numeric";
import { UserRequest } from "../../../src/server/request/UserRequest";
import { ServerSideQuote } from "../../../src/server/quote/ServerSideQuote";
+import { QuoteDataBucket } from "../../../src/bucket/QuoteDataBucket";
chai_use( require( 'chai-as-promised' ) );
@@ -711,7 +712,7 @@ function createStubQuote()
getBucket()
{
- return;
+ return new QuoteDataBucket();
}
};
}
diff --git a/test/server/service/RatingServiceTest.ts b/test/server/service/RatingServiceTest.ts
index 1b7f7d7..3bc72c0 100644
--- a/test/server/service/RatingServiceTest.ts
+++ b/test/server/service/RatingServiceTest.ts
@@ -35,6 +35,7 @@ import { ServerSideQuote } from "../../../src/server/quote/ServerSideQuote";
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 {
ServerDao,
@@ -140,7 +141,7 @@ describe( 'RatingService', () =>
.then( () => expect( sent ).to.be.true );
} );
- it( "saves rate data to own field", () =>
+ it( "saves rate data to it's own field", () =>
{
const {
logger,
@@ -510,6 +511,10 @@ function getStubs()
getLastPremiumDate: () => 0,
getCurrentStepId: () => 0,
setExplicitLock: () => quote,
+ setRateBucket: () => quote,
+ setRatingData: () => quote,
+ getRatingData: () => stub_rate_data,
+ getBucket: () => new QuoteDataBucket(),
};
return {