define([
], function (
) {
'use strict';
/**
* Represents and wraps single data record.
*
* You will often use this object instead of a plain JS map object when using
* the ABCS {@link api/js/Pages Navigation API} or communicating with ABCS
* {@link viewmodel/js/api/Archetype Archetypes}.
*
* In contrast to a plain JS object this provides a set of helper methods
* when accessing wrapped data and mainly allows you to access (and update)
* values of archetype's observables and record model from your code (see the
* example below).
*
* @AbcsAPI stable
* @version 16.3.5
*
* @exports viewmodel/js/api/Record
* @constructor
* @private
*
* @example <caption>Custom code accessing a form archetype, getting one of
* record model values and updating the value</caption>
*
* // get the current live archetype's instance of a Record
* var customerRecord = customerEditArchetype.getRecord();
*
* // get number of orders the customer has made so far
* var numberOfOrders = customerRecord.getValue('numberOfOrders');
*
* // check if number of orders is more than five in which case promote the
* // customer to a Premium state
* if (numberOfOrders > 5) {
* customerRecord.setValue('state', 'Premium');
* }
*
* @example <caption>Custom code fetching customer data and immediately
* opening the customer's detail page</caption>
*
* require([
* 'operation/js/api/Conditions',
* 'operation/js/api/Operator',
* 'viewmodel/js/api/ContextualData',
* 'viewmodel/js/api/Record'
* ], function (Conditions, Operator, ContextualData, Record) {
* // construct read condition for customer with customerId=100
* var customer = Abcs.Entities().findById('my.custom.bop.Customer');
* var customerId = customer.getProperty('customerId');
* var condition = Conditions.SIMPLE(customerId, Operator.EQUALS, 100);
* // get read operation for the constructed condition
* var operation = Abcs.Operations().read({
* entity: customer,
* condition: condition
* });
*
* // fetch customer data
* operation.perform().then(function(operationResult) {
*
* // when data are fetched prepare the record to pass to a detail page
* var customerRecord = Record.createFromJSON(operationResult.getData());
*
* // open a detail page with id 'customerDetail' and pass the record
* // wrapped in the contextual data so the page can show its details
* // in the UI
* var customerToEdit = ContextualData.createRecordToEditContext({
* entityId: 'customer',
* // pass the record instance here
* data: customerRecord
* });
* return Abcs.Pages().navigateToPage('customerDetail', customerToEdit);
* });
* });
*
* @see {@link viewmodel/js/api/Archetype Archetype API}
* @see {@link viewmodel/js/api/DetailArchetype Detail/Form Archetype API} which represents
* record of one businness object
* @see {@link module:api/js/Pages Navigation API} which uses the Record object for sharing data
* between pages
*/
var Record = function(data, originalOperationResult) {
this.data = data || {};
this.__originalResult = originalOperationResult;
this._lastSyncTime = 0;
if (!originalOperationResult && this.data.__originalResult) {
this.__originalResult = this.data.__originalResult;
delete this.data.__originalResult;
}
};
Record._ERROR_CREATE_NO_OBJECT_LITERAL = function (contructor) {
return 'Record must be based on a valid JSON object. You seem to be passing an object of type ' + contructor.name;
};
/**
* Creates simple record backed by plain JSON object literal.
*
* @AbcsAPI stable
* @version 16.3.5
*
* @param {Object} data JSON with initial values
* @returns {viewmodel/js/api/Record} created record instance
*
* @example <caption>Clone the Record object using Record's createFromJSON() and getDefinition() methods</caption>
* // creates data for this sample
* var data = {
* prop1: 'value1',
* prop2: 'value2
* }
* // creates the Record objects
* var record = Record.createFromJSON(data);
* // clones the Record
* var clone = Record.createFromJSON(record.getDefinition());
*/
Record.createFromJSON = function (data) {
AbcsLib.checkParameterCount(arguments, 1);
AbcsLib.checkDefined(data, 'data');
AbcsLib.checkDataType(data, AbcsLib.Type.OBJECT);
if (typeof data.constructor === 'function' && data.constructor !== Object && !data.hasOwnProperty('constructor')) {
throw new Error(Record._ERROR_CREATE_NO_OBJECT_LITERAL(data.constructor));
}
return new Record(AbcsLib.clone(data));
};
/**
* Creates simple record backed by plain JSON object literal.
*
* <p>This duplicates the method {@link viewmodel/js/api/Record.createFromJSON Record.createFromJSON}
* due to compatibility reasons. This method is spread over custom code in existing applications.</p>
*
* @param {Object} data JSON with initial values
* @returns {viewmodel/js/api/Record} created record instance
*/
Record.createSimpleRecord = function (data) {
return Record.createFromJSON(data);
};
/**
* Create simple record backed by plain JSON object literal, with the result
* from the operations layer that retrieved it.
*
* @param {Object} data JSON with initial values
* @param {String} operationResult the operationResult that was was the data
* response for this record when retrieved from the server.
* @returns {Record}
*/
Record.createSimpleRecordWithResult = function(data, operationResult) {
return new Record(data, operationResult);
};
Record.createSimpleRecordForRVM = function(rvm) {
return new Record.RVMRecord(rvm);
};
Record.prototype.getOriginalResult = function() {
return this.__originalResult;
};
Record.prototype.setOriginalResult = function(operationResult) {
return this.__originalResult = operationResult;
};
/**
* Returns array of record's property names.
*
* @AbcsAPI stable
* @version 16.3.5
*
* @returns {String[]} list of all property names
*/
Record.prototype.getProperties = function() {
AbcsLib.checkParameterCount(arguments, 0);
return Object.keys(this.data);
};
/**
* Get value of a single property.
*
* @AbcsAPI stable
* @version 16.3.5
* @param {String} property property ID
*
* @returns {*} property value, may be <code>undefined</code> if the property doesn't exist
*/
Record.prototype.getValue = function(property) {
AbcsLib.checkParameterCount(arguments, 1);
AbcsLib.checkDefined(property, 'property');
return this.data[property];
};
/**
* Set value of a single property.
*
* In case the record is based on {@link viewmodel/js/api/DetailArchetype detail
* archetype's} data this writes through the archetype's model and allows you
* to communicate with other components bound to the same property.
*
* @AbcsAPI stable
* @version 16.3.5
*
* @param {String} property property ID
* @param {Object} value value to set
*/
Record.prototype.setValue = function(property, value) {
AbcsLib.checkParameterCount(arguments, 2);
AbcsLib.checkDefined(property, 'property');
AbcsLib.checkDataType(property, AbcsLib.Type.STRING);
this.data[property] = value;
};
/**
* Erase value of single proeprty.
*
* @AbcsAPI unstable
* @param {String} property property ID
* @returns {Record} this
*/
Record.prototype.removeValue = function(property) {
delete this.data[property];
return this;
};
/**
* Gets the map where key is PropertyID and value is the corresponding record value.
*
* @returns {Object[]}
*/
Record.prototype.getData = function() {
return this.data;
};
/**
* Return record data as plain JSON object.
*
* This is useful when you want to pass the record data to a remote REST endpoint
* via the {@link module:api/js/Operations Operations API}.
*
* @AbcsAPI stable
* @version 16.3.5
*
* @returns {Object}
*
* @example <caption>Clone the Record object using Record's createFromJSON() and getDefinition() methods</caption>
* // creates data for this sample
* var data = {
* prop1: 'value1',
* prop2: 'value2
* }
* // creates the Record objects
* var record = Record.createFromJSON(data);
* // clones the Record
* var clone = Record.createFromJSON(record.getDefinition());
*/
Record.prototype.getDefinition = function() {
return this.toJSON();
};
Record.prototype.toJSON = function() {
var clone = AbcsLib.clone(this.data);
var originalResult = this.getOriginalResult();
if (clone && !clone.__originalResult && originalResult) {
clone.__originalResult = originalResult;
}
return clone;
};
/**
* Get timestamp of the last sync with backend
* @returns {Number} timestamp - in milliseconds - of the last sync.
*/
Record.prototype.getLastSyncTime = function () {
return this._lastSyncTime;
};
/**
* Set timestamp of the last sync with backend
* @param {Number} timestamp timestamp - in milliseconds - of the last sync.
*/
Record.prototype.setLastSyncTime = function (timestamp) {
this._lastSyncTime = timestamp;
};
/**
*
* @param {RecordViewModel} rvm
*/
Record.RVMRecord = function(rvm) {
this.recordViewModel = rvm;
};
AbcsLib.extend(Record.RVMRecord, Record);
Record.RVMRecord.prototype.getProperties = function() {
AbcsLib.checkParameterCount(arguments, 0);
return Object.keys(this.recordViewModel.getData());
};
Record.RVMRecord.prototype.getOriginalResult = function() {
return this.recordViewModel.getOriginalResult();
};
Record.RVMRecord.prototype.setOriginalResult = function(operationResult) {
return this.recordViewModel.setOriginalResult(operationResult);
};
Record.RVMRecord.prototype.getValue = function(property) {
AbcsLib.checkParameterCount(arguments, 1);
AbcsLib.checkDefined(property, 'property');
return this.recordViewModel.getValue(property);
};
Record.RVMRecord.prototype.getData = function() {
return this.recordViewModel.getData();
};
Record.RVMRecord.prototype.setValue = function(property, value) {
AbcsLib.checkParameterCount(arguments, 2);
AbcsLib.checkDefined(property, 'property');
AbcsLib.checkDataType(property, AbcsLib.Type.STRING);
this.recordViewModel.setValue(property, value);
return this;
};
Record.RVMRecord.prototype.removeValue = function(/*property*/) {
// XXX: I do not think this is currently supported
return this;
};
Record.RVMRecord.prototype.getDefinition = function() {
return this.toJSON();
};
Record.RVMRecord.prototype.toJSON = function() {
return this.recordViewModel.getData();
};
Record.RVMRecord.prototype.getLastSyncTime = function () {
return this.recordViewModel.getLastSyncTime();
};
Record.RVMRecord.prototype.setLastSyncTime = function (timestamp) {
this.recordViewModel.setLastSyncTime(timestamp);
};
return Record;
});