UNPKG

react-sync-state

Version:

A client side implementation for synchronizing states with server

245 lines (209 loc) 8.09 kB
'use strict'; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var _Record = require('../_Record'); var _Record2 = _interopRequireDefault(_Record); var _RecordSet = require('../_RecordSet'); var _RecordSet2 = _interopRequireDefault(_RecordSet); var _State = require('../State'); var _State2 = _interopRequireDefault(_State); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * The state initialization method, that takes in the state of the system in JSON in the following format * <code> * { * "oracle":[ * { * "type":"Unit", * "structure":[ * { * "name":"id", * "type":"Long" * }, * { * "name":"name", * "type":"String" * } * ], * "data": { * "1":[1,Celcius] * } * }, * { * "type":"Station", * "structure":[ * { * "name":"id", * "type":"Long" * }, * { * "name":"name", * "type":"String" * }, * { * "name":"parameters", * "type":"Parameter[]" * } * ], * "data":{ * "1":[1,Kathmandu,[1]] * } * } * ] * }, * "state":[ * { * "name":"stations", * "type":"Station", * "items":[1] * } * ], * </code> * * and creates a new state based on that * */ var JavaSyncStateLoader = (function () { function JavaSyncStateLoader() { _classCallCheck(this, JavaSyncStateLoader); // Initialize this.shadows = []; } /** * The method to create a state from the given data * * @param {JSON} data The JSON data in the above format * @return {State} The newly created State for use in the Application */ _createClass(JavaSyncStateLoader, [{ key: 'load', value: function load(data) { var state = new _State2.default(); // Lock the state, we don't want any event to be thrown during the loading // stage state.lock(); // First define all the data types for (var i in data.oracle) { var type = data.oracle[i]; // for each different record type, register two different data types // one for the Record.Type itself and another for RecordSet.Type var recordType = new _Record2.default.Type(type.type); state.registerDataType(type.type, recordType); state.registerDataType(type.type + "[]", new _RecordSet2.default.Type(recordType)); } // Next convert all the data to a Record type for (var j in data.oracle) { var type = data.oracle[j]; var recordType = state.getDataType(type.type); // first set the structure for the recordType that was created on the loop before recordType._structure = this.createStructure(state, type.structure); for (var id in type.data) { var record = this.createRecord(state, recordType, type.structure, type.data[id]); recordType._own(id, record); } } // Reconile the shadow instances while (this.shadows.length) { var shadow = this.shadows.pop(); // A shadow consists of 4 indices which are // 0 - The source which needs to be updated which is either Record or RecordSet // 1 - The reference on the source which is either fieldname (for Record) or index (for RecordSet) // 2 - The record type // 3 - The record id shadow[0].update([shadow[1]], shadow[2].get([shadow[3]])); } // Load all the states for (var s in data.state) { var item = data.state[s]; var list = new _RecordSet2.default(state); state._seeds[item.name] = list; var recordType = state.getDataType(item.type); for (var i in item.items) { list.add(recordType.get(item.items[i])); } } // release the lock without dispatching events state.reset(); return state; } /** * The structure defined in the source data is an array of a key value * pair. Convert that key value pair array into a object. */ }, { key: 'createStructure', value: function createStructure(state, array) { var structure = {}; for (var i in array) { var typeName = array[i].type; var type = state.getDataType(typeName); if (type == null) { console.error("Unknown data type " + typeName); } structure[array[i].name] = state.getDataType(array[i].type); } return structure; } /** * Convert the given record array into a Record object. The record object * requires, the structure type as registered in the state, that is why * the typeName is provided, whereas to decode the data, the structureArray * is needed */ }, { key: 'createRecord', value: function createRecord(state, recordType, structureArray, recordArray) { var record = new _Record2.default(state, recordType); for (var i in recordArray) { var field = structureArray[i].name; var fieldType = recordType.getFieldType(field); var value = recordArray[i]; // The value has to be interpreted depending on the field Type if (fieldType instanceof _Record2.default.Type) { // We expect a number that points to another record here if (fieldType.has(value)) { record[field] = fieldType.get(value); } else { // The referenced record has not been loaded here, so we will just // put up a shadow here, which need to be reconciled later record[field] = this.createShadow(record, field, fieldType, value); } } else if (fieldType instanceof _RecordSet2.default.Type) { var refType = fieldType.getRecordType(); var set = new _RecordSet2.default(state); // We expect a list of numbers for (var idx in value) { var v = value[idx]; if (refType.has(v)) { set.add(refType.get(v)); } else { set.add(this.createShadow(set, idx, refType, v)); } } record[field] = set; } else { // A primitive value is directly adapted console.log(fieldType); record[field] = fieldType.adapt(value); } } return record; } /** * Create a shadow instance for a record which has not yet been initialized * but is tried to be referenced. The shadow keeps information of all these * yet to be created record, and at the end of the initialization process * replaces these shadows with a Record instance during reconcilation */ }, { key: 'createShadow', value: function createShadow(owner, ownerRef, recordType, recordId) { this.shadows.push([owner, ownerRef, recordType, recordId]); } }]); return JavaSyncStateLoader; })(); exports.default = JavaSyncStateLoader;