diff --git a/data/service/data-service-reference.js b/data/service/data-service-reference.js new file mode 100644 index 0000000000..d697655c8d --- /dev/null +++ b/data/service/data-service-reference.js @@ -0,0 +1,118 @@ +var Montage = require("core/core").Montage, + ModuleReference = require("core/module-reference").ModuleReference; + +/** + * @class DataServiceReference + * @extends external:Montage + */ +exports.DataServiceReference = Montage.specialize(/** @lends DataServiceReference.prototype */ { + + + + initWithIdTypesAndRequire: { + value: function (id, types, require) { + if (!id || !require) { + throw new Error("Module ID and require required"); + } + this.module = new ModuleReference().initWithIdAndRequire(id, require); + this.types = types; + + return this; + } + }, + + /** + * The identifier is the name of the service and is used to make the + * serialization of models more readable. + * @type {string} + * @default this.name + */ + identifier: { + get: function () { + return [ + "dataService", + (this.serviceName || this.prototypeName || "unnamed").toLowerCase(), + "reference" + ].join("_"); + } + }, + + initWithModuleAndTypes: { + value: function (serviceModule, types) { + if (!serviceModule) { + throw new Error("Module is required"); + } + this.module = serviceModule; + this.types = types; + + return this; + } + }, + + + deserializeSelf: { + value: function (deserializer) { + this.super(deserializer); + var value; + + value = deserializer.getProperty("module"); + this.module = value; + + value = deserializer.getProperty("serviceName"); + this.serviceName = value; + + value = deserializer.getProperty("prototypeName"); + this.prototypeName = value; + + value = deserializer.getProperty("types") || []; + this.types = value; + } + }, + + serializeSelf: { + value: function (serializer) { + this.super(serializer); + } + }, + + promise: { + get: function () { + var prototypeName; + if (!this._promise) { + prototypeName = this.prototypeName; + this._promise = this.module ? this.module.exports.then(function (exports) { + var service = exports.montageObject; + if (!service && prototypeName) { + service = new exports[prototypeName]; + //TODO Add Types To Service + } + return service; + }) : Promise.resolve(null); + } + return this._promise; + } + }, + + module: { + value: undefined + }, + + moduleId: { + get: function () { + return this.module && this.module.id || undefined; + } + }, + + prototypeName: { + value: undefined + }, + + serviceName: { + value: undefined + }, + + types: { + value: undefined + } + +}); \ No newline at end of file diff --git a/data/service/data-service.js b/data/service/data-service.js index 61a2137b57..077320814e 100644 --- a/data/service/data-service.js +++ b/data/service/data-service.js @@ -82,10 +82,20 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { Array.prototype.push.apply(this._childServiceMappings, value); } + this.registerSelf(); + value = deserializer.getProperty("delegate"); if (value) { this.delegate = value; } + + if (this._childServiceRegistrationPromise) { + this._childServiceRegistrationPromise = this._childServiceRegistrationPromise.then(function () { + return self.registerSelf(); + }); + } else { + this._childServiceRegistrationPromise = this.registerSelf(); + } return result; } @@ -281,6 +291,15 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { // types or to the "all types" service array identified by the // `null` type, and add each of the new child's types to the array // of child types if they're not already there. + this._cacheServiceWithTypes(child, types); + // Set the new child service's parent. + child._parentService = this; + } + }, + + _cacheServiceWithTypes: { + value: function (child, types) { + var children, type, i, n, nIfEmpty = 1; for (i = 0, n = types && types.length || nIfEmpty; i < n; i += 1) { type = types && types.length && types[i] || null; @@ -293,8 +312,6 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { } } } - // Set the new child service's parent. - child._parentService = this; } }, @@ -397,6 +414,48 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { } }, + registerSelf: { + value: function () { + var self = this, + mappings = this.mappings || [], + types; + + // possible types + // -- types is passed in as an array or a single type. + // -- a model is set on the child. + // -- types is set on the child. + // any type can be asychronous or synchronous. + types = types && Array.isArray(types) && types || + types && [types] || + this.model && this.model.objectDescriptors || + this.types && Array.isArray(this.types) && this.types || + this.types && [this.types] || + []; + + return this._registerOwnTypesAndMappings(types, mappings).then(function () { + self._cacheServiceWithTypes(self, types); + return self; + }); + } + }, + + _registerOwnTypesAndMappings: { + value: function (types, mappings) { + var self = this, + objectDescriptors; + return this._resolveAsynchronousTypes(types).then(function (descriptors) { + objectDescriptors = descriptors; + self._registerTypesByModuleId(objectDescriptors); + return self._registerChildServiceMappings(self, mappings); + }).then(function () { + return self._makePrototypesForTypes(self, objectDescriptors); + }).then(function () { + // self.addChildService(child, types); + return null; + }); + } + }, + _resolveAsynchronousTypes: { value: function (types) { var self = this; @@ -1747,7 +1806,8 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { //have to go up to answer that question. The difference between //.TYPE and Objectdescriptor still creeps-in when it comes to //the service to answer that to itself - if (self.parentService && self.parentService.childServiceForType(query.type) === self && typeof self.fetchRawData === "function") { + service = self.parentService ? self.parentService.childServiceForType(query.type) : self.childServiceForType(query.type); + if (service === self && typeof self.fetchRawData === "function") { service = self; service._fetchRawData(stream); } else { @@ -1760,6 +1820,7 @@ exports.DataService = Montage.specialize(/** @lends DataService.prototype */ { stream = service.fetchData(query, stream) || stream; self._dataServiceByDataStream.set(stream, service); } else { + debugger; throw new Error("Can't fetch data of unknown type - " + (query.type.typeName || query.type.name) + "/" + query.type.uuid); } } catch (e) { diff --git a/data/service/raw-data-operation.js b/data/service/raw-data-operation.js new file mode 100644 index 0000000000..52d6b11288 --- /dev/null +++ b/data/service/raw-data-operation.js @@ -0,0 +1,45 @@ +var Montage = require("core/core").Montage; + +/** + * Represents + * + * @class + * @extends external:Montage + */ +exports.RawDataOperation = Montage.specialize(/** @lends DataOperation.prototype */ { + + /*************************************************************************** + * Constructor + */ + + constructor: { + value: function RawDataOperation() { + this.time = Date.now(); + this._index = exports.RawDataOperation.prototype._currentIndex + 1 || 0; + exports.RawDataOperation.prototype._currentIndex = this._index; + } + }, + + data: { + value: undefined, + serializable: "value" + }, + + objectDescriptorModule: { + value: undefined, + serializable: "value" + }, + + serviceModule: { + value: undefined, + serializable: "value" + }, + + type: { + value: undefined, + serializable: "value" + } + + +}); + diff --git a/data/service/raw-data-service.js b/data/service/raw-data-service.js index 14df6020dd..92b3b1bd0a 100644 --- a/data/service/raw-data-service.js +++ b/data/service/raw-data-service.js @@ -202,7 +202,7 @@ exports.RawDataService = DataService.specialize(/** @lends RawDataService.protot // if (childService && childService.identifier.indexOf("offline-service") === -1) { // childService._fetchRawData(stream); // } else - if (childService) { + if (childService && childService !== this) { childService._fetchRawData(stream); } else if (query.authorization) { stream.query = self.mapSelectorToRawDataQuery(query); diff --git a/data/service/raw-data-worker.js b/data/service/raw-data-worker.js new file mode 100644 index 0000000000..ee96d3d3fc --- /dev/null +++ b/data/service/raw-data-worker.js @@ -0,0 +1,309 @@ +var Montage = require("montage").Montage, + Criteria = require("core/criteria").Criteria, + DataQuery = require("data/model/data-query").DataQuery, + Map = require("collections/map"), + ObjectDescriptor = require("core/meta/object-descriptor").ObjectDescriptor, + OperationType = require("data/service/data-operation").DataOperation.Type, + Promise = require("core/promise").Promise; + + +exports.RawDataWorker = Montage.specialize({ + + + + /*************************************************************************** + * Serialization + */ + + // serializeSelf: { + // value: function (serializer) { + // } + // }, + + deserializeSelf: { + value: function (deserializer) { + var references = deserializer.getProperty("childServices") || []; + + console.log("RawDataWorker.deserializeSelf", references); + this.registerServiceReferences(references); + } + }, + + + /*************************************************************************** + * Service Tree + */ + + + _serviceReferenceRegistrationPromise: { + get: function () { + if (!this.__serviceReferenceRegistrationPromise) { + this.__serviceReferenceRegistrationPromise = Promise.resolve(null); + } + return this.__serviceReferenceRegistrationPromise; + } + }, + + serviceReferences: { + get: function() { + if (!this._serviceReferences) { + this._serviceReferences = new Set(); + } + return this._serviceReferences; + } + }, + + serviceReferenceByObjectDescriptor: { + get: function () { + if (!this._serviceReferenceByObjectDescriptor) { + this._serviceReferenceByObjectDescriptor = new Map(); + } + return this._serviceReferenceByObjectDescriptor; + } + }, + + serviceReferenceForObjectDescriptor: { + value: function (type) { + var services; + type = type instanceof ObjectDescriptor ? type : this._objectDescriptorForType(type); + services = this._serviceReferenceByObjectDescriptor.get(type) || this._serviceReferenceByObjectDescriptor.get(null); + return services && services[0] || null; + } + }, + + registerServiceReferences: { + value: function (serviceReferences) { + var self; + if (!this.__serviceReferenceRegistrationPromise) { + self = this; + this.__serviceReferenceRegistrationPromise = Promise.all(serviceReferences.map(function (service) { + return self.registerServiceReference(service); + })); + } + } + }, + + registerServiceReference: { + value: function (service, types) { + var self = this; + // possible types + // -- types is passed in as an array or a single type. + // -- a model is set on the service. + // -- types is set on the service. + // any type can be asychronous or synchronous. + types = types && Array.isArray(types) && types || + types && [types] || + service.model && service.model.objectDescriptors || + service.types && Array.isArray(service.types) && service.types || + service.types && [service.types] || + []; + + return this._registerServiceReferenceObjectDescriptors(service, types); + } + }, + + _registerServiceReferenceObjectDescriptors: { + value: function (service, types) { + this._addServiceReference(service, types); + this._registerObjectDescriptorsByModuleId(types); + return this.nullPromise; + } + }, + + _addServiceReference: { + value: function (service, types) { + var serviceReference, type, i, n, nIfEmpty = 1; + types = types || service.model && service.model.objectDescriptors || service.types; + + // Add the new service to this service's serviceren set. + this.serviceReferences.add(service); + + // Add the new service service to the services array of each of its + // types or to the "all types" service array identified by the + // `null` type, and add each of the new service's types to the array + // of service types if they're not already there. + for (i = 0, n = types && types.length || nIfEmpty; i < n; i += 1) { + type = types && types.length && types[i] || null; + serviceReference = this.serviceReferenceByObjectDescriptor.get(type) || []; + serviceReference.push(service); + if (serviceReference.length === 1) { + this.serviceReferenceByObjectDescriptor.set(type, serviceReference); + } + } + } + }, + + _registerObjectDescriptorsByModuleId: { + value: function (types) { + var self = this; + types.forEach(function (objectDescriptor) { + var module = objectDescriptor.module, + moduleId = [module.id, objectDescriptor.exportName].join("/"); + self.objectDescriptorsByModuleID.set(moduleId, objectDescriptor); + }); + } + }, + + nullPromise: { + get: function () { + if (!exports.RawDataWorker._nullPromise) { + exports.RawDataWorker._nullPromise = Promise.resolve(null); + } + return exports.RawDataWorker._nullPromise; + } + }, + + /*************************************************************************** + * Operation Handlers + */ + + handleOperation: { + value: function (rawOperation) { + var self = this, + objectDescriptor, service; + + return this._serviceReferenceRegistrationPromise.then(function () { + return self._objectDescriptorForOperation(rawOperation); + }).then(function (descriptor) { + objectDescriptor = descriptor; + return self._serviceForObjectDescriptor(descriptor); + }).then(function (service) { + var handlerName = self._handlerNameForOperationType(rawOperation.type); + if (!service) { + console.log(rawOperation, self, objectDescriptor); + debugger; + throw new Error("No service available to handle operation with type (" + (objectDescriptor && objectDescriptor.name) + ")"); + } + return self[handlerName](rawOperation, service, objectDescriptor); + }); + } + }, + + _handlerNameForOperationType: { + value: function (operationType) { + var name = "_perform"; + name += this._operationTypeNameByOperationType(operationType); + return name + "Operation"; + } + }, + + _operationTypeNameByOperationType: { + value: function (operationType) { + return operationType.isCreate ? "Create" : + operationType.isRead ? "Read" : + operationType.isUpdate ? "Update" : + operationType.isDelete ? "Delete" : + null; + } + }, + + _performCreateOperation: { + value: function (rawOperation, service, objectDescriptor) { + return service.saveRawData(rawOperation.data); + } + }, + + _performDeleteOperation: { + value: function (rawOperation, service, objectDescriptor) { + return service.deleteRawData(rawOperation.data); + } + }, + + _performReadOperation: { + value: function (rawOperation, service, objectDescriptor) { + var criteria = rawOperation.criteria || rawOperation.data, + query, parameters, expression; + + if (!(criteria instanceof Criteria)) { + parameters = criteria ? criteria.parameters : {}; + expression = criteria ? criteria.expression : ""; + criteria = new Criteria().initWithExpression(expression, parameters); + } + query = DataQuery.withTypeAndCriteria(objectDescriptor, criteria); + + return service.fetchData(query); + } + }, + + _performUpdateOperation: { + value: function (rawOperation, service, objectDescriptor) { + return service.saveRawData(rawOperation.data); + } + }, + + /*************************************************************************** + * Service & ObjectDescriptor Creation + */ + + objectDescriptorForType: { + value: function () { + + } + }, + + _serviceReferenceForObjectDescriptor: { + value: function (objectDescriptor) { + var services = this.serviceReferenceByObjectDescriptor.get(objectDescriptor); + services = services || this.serviceReferenceByObjectDescriptor.get(null); + return services && services[0] || null; + } + }, + + _serviceForObjectDescriptor: { + value: function (objectDescriptor) { + var self = this, + serviceReference = this._serviceReferenceForObjectDescriptor(objectDescriptor), + service = serviceReference && this.servicesByModuleID.get(serviceReference.moduleId); + + + + return !serviceReference ? Promise.resolve(null) : + service ? Promise.resolve(service) : + serviceReference.promise.then(function (service) { + self._servicesByModuleID.set(serviceReference.moduleId, service); + return service; + }); + } + }, + + _objectDescriptorForOperation: { + value: function (rawOperation) { + var self = this, + module = rawOperation.objectDescriptorModule, + descriptor = this.objectDescriptorsByModuleID.get(module.id); + + + return descriptor ? Promise.resolve(descriptor) : + module.exports.then(function (exports) { + var instance = exports.montageObject, + moduleId = [module.id, instance.exportName].join("/"); + self.objectDescriptorsByModuleID.set(module.id, instance); + self.objectDescriptorsByModuleID.set(moduleId, instance); + return instance; + }); + } + }, + + /*************************************************************************** + * Service/Type Caching + */ + + servicesByModuleID: { + get: function () { + if (!this._servicesByModuleID) { + this._servicesByModuleID = new Map(); + } + return this._servicesByModuleID; + } + }, + + objectDescriptorsByModuleID: { + get: function () { + if (!this._objectDescriptorsByModuleID) { + this._objectDescriptorsByModuleID = new Map(); + } + return this._objectDescriptorsByModuleID; + } + } + +}); \ No newline at end of file diff --git a/package.json b/package.json index 705a8dfb36..39bfb86074 100644 --- a/package.json +++ b/package.json @@ -52,14 +52,14 @@ "collections": "~5.0.x", "frb": "~4.0.x", "htmlparser2": "~3.0.5", - "q-io": "^1.13.3", - "mr": "^17.0.11", - "weak-map": "^1.0.5", - "lodash.kebabcase": "^4.1.1", "lodash.camelcase": "^4.3.0", - "lodash.trim": "^4.5.1", + "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", - "proxy-polyfill": "~0.1.7" + "lodash.trim": "^4.5.1", + "mr": "montagejs/mr#features/dirIndex", + "proxy-polyfill": "~0.1.7", + "q-io": "^1.13.3", + "weak-map": "^1.0.5" }, "devDependencies": { "concurrently": "^3.4.0", diff --git a/test/all.js b/test/all.js index 37607e0bd9..ce75f71b38 100644 --- a/test/all.js +++ b/test/all.js @@ -112,11 +112,11 @@ module.exports = require("montage-testing").run(require, [ {name: "spec/core/localizer-spec", node: false, karma: false}, {name: "spec/core/localizer/serialization-spec", node: false, karma: false}, // Data - {name: "spec/data/data-query"}, {name: "spec/data/data-mapping"}, {name: "spec/data/data-object-descriptor"}, {name: "spec/data/data-property-descriptor"}, {name: "spec/data/data-provider"}, + {name: "spec/data/data-query"}, {name: "spec/data/data-service"}, {name: "spec/data/data-stream"}, {name: "spec/data/expression-data-mapping"}, @@ -126,6 +126,7 @@ module.exports = require("montage-testing").run(require, [ {name: "spec/data/property-descriptor"}, {name: "spec/data/raw-data-service"}, {name: "spec/data/raw-data-type-mapping-spec"}, + {name: "spec/data/raw-data-worker"}, {name: "spec/data/integration", node: false}, // Meta diff --git a/test/raw-data-worker.js b/test/raw-data-worker.js new file mode 100644 index 0000000000..366e87bf57 --- /dev/null +++ b/test/raw-data-worker.js @@ -0,0 +1,11 @@ +console.log('montage-testing', 'Start'); + +module.exports = require("montage-testing").run(require, [ + + {name: "spec/data/raw-data-worker"} +]).then(function () { + console.log('montage-testing', 'End'); +}, function (err) { + console.log('montage-testing', 'Fail', err, err.stack); + throw err; +}); diff --git a/test/run.html b/test/run.html index 6ba084031c..f2c7fc4ca3 100644 --- a/test/run.html +++ b/test/run.html @@ -9,6 +9,7 @@ - + + diff --git a/test/spec/data/logic/service/category-service-reference.mjson b/test/spec/data/logic/service/category-service-reference.mjson new file mode 100644 index 0000000000..e16aa6e340 --- /dev/null +++ b/test/spec/data/logic/service/category-service-reference.mjson @@ -0,0 +1,17 @@ +{ + "root": { + "prototype": "montage/data/service/data-service-reference", + "properties": { + "module": {"%": "spec/data/logic/service/category-service.mjson"}, + "serviceName": "CategoryService", + "prototypeName": "CategoryService", + "types": [ + {"@": "CategoryDescriptor"} + ] + } + }, + + "CategoryDescriptor": { + "object": "spec/data/logic/model/category.mjson" + } +} \ No newline at end of file diff --git a/test/spec/data/logic/service/category-service.js b/test/spec/data/logic/service/category-service.js index 5dcaf9dc4e..dcdd495eba 100644 --- a/test/spec/data/logic/service/category-service.js +++ b/test/spec/data/logic/service/category-service.js @@ -13,6 +13,28 @@ exports.CategoryService = RawDataService.specialize(/** @lends CategoryService.p }]); this.rawDataDone(stream); } + }, + + saveRawData: { + value: function (rawData, object) { + if (rawData.categoryID) { + CategoryNames[rawData.categoryID] = rawData.name; + } else { + CategoryNames.push(rawData.name); + } + + return Promise.resolve(CategoryNames); + } + }, + + deleteRawData: { + value: function (rawData, object) { + if (rawData.categoryID && CategoryNames[rawData.categoryID]) { + CategoryNames.splice(rawData.categoryID, 1); + } + return Promise.resolve(CategoryNames); + } } + }); diff --git a/test/spec/data/logic/service/movie-service-reference.mjson b/test/spec/data/logic/service/movie-service-reference.mjson new file mode 100644 index 0000000000..cd5d2a5f8f --- /dev/null +++ b/test/spec/data/logic/service/movie-service-reference.mjson @@ -0,0 +1,17 @@ +{ + "root": { + "prototype": "montage/data/service/data-service-reference", + "properties": { + "module": {"%": "spec/data/logic/service/movie-service.mjson"}, + "serviceName": "MovieService", + "prototypeName": "MovieService", + "types": [ + {"@": "MovieDescriptor"} + ] + } + }, + + "MovieDescriptor": { + "object": "spec/data/logic/model/movie.mjson" + } +} \ No newline at end of file diff --git a/test/spec/data/logic/service/movie-service.js b/test/spec/data/logic/service/movie-service.js index 9ee584cddf..aa181d72f3 100644 --- a/test/spec/data/logic/service/movie-service.js +++ b/test/spec/data/logic/service/movie-service.js @@ -7,6 +7,16 @@ exports.MovieService = RawDataService.specialize(/** @lends MovieService.prototy value: function (record, object) { return Promise.resolve(record); } + }, + + + fetchRawData: { + value: function (stream) { + this.addRawData(stream, [{ + name: "Bill and Ted's Excellent Adventure" + }]); + this.rawDataDone(stream); + } } }); diff --git a/test/spec/data/logic/service/movie-service.mjson b/test/spec/data/logic/service/movie-service.mjson index 447516f0bb..4088d22dac 100644 --- a/test/spec/data/logic/service/movie-service.mjson +++ b/test/spec/data/logic/service/movie-service.mjson @@ -16,6 +16,6 @@ {"@": "movie"}, {"@": "plotSummary"} ] - } + } } } diff --git a/test/spec/data/logic/service/raw-data-worker.mjson b/test/spec/data/logic/service/raw-data-worker.mjson new file mode 100644 index 0000000000..29679e7d8d --- /dev/null +++ b/test/spec/data/logic/service/raw-data-worker.mjson @@ -0,0 +1,20 @@ +{ + "root": { + "prototype": "montage/data/service/raw-data-worker", + "values": { + "name": "RawDataWorker", + "childServices": [ + {"@": "categoryService"}, + {"@": "movieService"} + ] + } + }, + + "categoryService": { + "object": "spec/data/logic/service/category-service-reference.mjson" + }, + + "movieService": { + "object": "spec/data/logic/service/movie-service-reference.mjson" + } +} \ No newline at end of file diff --git a/test/spec/data/raw-data-worker.js b/test/spec/data/raw-data-worker.js new file mode 100644 index 0000000000..1e87298eca --- /dev/null +++ b/test/spec/data/raw-data-worker.js @@ -0,0 +1,244 @@ +var RawDataWorker = require("montage/data/service/raw-data-worker").RawDataWorker, + OperationType = require("montage/data/service/data-operation").DataOperation.Type, + Category = require("spec/data/logic/model/category").Category, + CategoryDescriptor = require("spec/data/logic/model/category.mjson").montageObject, + Criteria = require("montage/core/criteria").Criteria, + DataMapping = require("montage/data/service/data-mapping").DataMapping, + DataService = require("montage/data/service/data-service").DataService, + DataServiceReference = require("montage/data/service/data-service-reference").DataServiceReference, + DataStream = require("montage/data/service/data-stream").DataStream, + DataObjectDescriptor = require("montage/data/model/data-object-descriptor").DataObjectDescriptor, + ObjectDescriptor = require("montage/core/meta/object-descriptor").ObjectDescriptor, + ModuleReference = require("montage/core/module-reference").ModuleReference, + RawDataTypeMapping = require("montage/data/service/raw-data-type-mapping").RawDataTypeMapping; + +var Deserializer = require("montage/core/serialization/deserializer/montage-deserializer").MontageDeserializer, + deserialize = require("montage/core/serialization/deserializer/montage-deserializer").deserialize; + +describe("A RawDataWorker", function() { + var worker, + typeReference, + operation; + + it("can be created", function () { + expect(new RawDataWorker()).toBeDefined(); + }); + + + it("can register service references", function (done) { + var serviceID = "spec/data/logic/service/category-service.mjson", + types = [CategoryDescriptor], + serviceReference = new DataServiceReference().initWithIdTypesAndRequire(serviceID, types, require); + worker = new RawDataWorker(); + + worker.registerServiceReference(serviceReference).then(function () { + expect(worker.serviceReferences.size).toBe(1); + done(); + }); + }); + + + describe("can lazily", function () { + + it("register type for RawOperation", function (done) { + var movieDescriptor, typeReference2, operation2; + // worker = new RawDataWorker(); + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + typeReference2 = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + operation = { + objectDescriptorModule: typeReference + }; + operation2 = { + objectDescriptorModule: typeReference + }; + worker._objectDescriptorForOperation(operation).then(function (descriptor) { + expect(descriptor).toBeDefined(); + movieDescriptor = descriptor; + return worker._objectDescriptorForOperation(operation2); + }).then(function (descriptor) { + expect(descriptor).toBeDefined(); + expect(descriptor).toBe(movieDescriptor); + done(); + }); + }); + + }); + + describe("can handle basic ", function () { + // worker = new RawDataWorker(); + + it("create operation", function (done) { + var rawData = { + name: "Comedy" + }; + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + operation = { + data: rawData, + objectDescriptorModule: typeReference, + type: OperationType.CREATE + }; + + worker.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data[1]).toBe(rawData.name); + done(); + }); + }); + + it("read operation", function (done) { + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + operation = { + objectDescriptorModule: typeReference, + type: OperationType.READ + }; + + worker.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(1); + done(); + }); + }); + + it("update operation", function (done) { + var rawData = { + name: "Science Fiction", + categoryID: 1 + }; + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + operation = { + data: rawData, + objectDescriptorModule: typeReference, + type: OperationType.UPDATE + }; + + worker.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data[1]).toBe(rawData.name); + done(); + }); + }); + + + it("delete operation", function (done) { + var rawData = { + name: "Science Fiction", + categoryID: 1 + }; + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + operation = { + data: rawData, + objectDescriptorModule: typeReference, + type: OperationType.DELETE + }; + + worker.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(1); + done(); + }); + }); + }); + + describe("can handle read operation", function () { + worker = new RawDataWorker(); + + it("with criteria", function (done) { + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + criteria = new Criteria().initWithExpression("id == $.id", { + categoryID: 1 + }); + operation = { + criteria: criteria, + objectDescriptorModule: typeReference, + type: OperationType.READ + }; + + worker.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(1); + expect(data[0].name).toBe("Action"); + done(); + }); + + }); + + }); + + describe("can deserialize", function () { + it("without childServices", function (done) { + var deserializer = new Deserializer(); + serialization = { + "root": { + "prototype": "montage/data/service/raw-data-worker", + "values": { + "name": "RawDataWorker" + } + } + }, + serializationString = JSON.stringify(serialization); + + deserializer.init(serializationString, require); + deserializer.deserializeObject().then(function (root) { + expect(Object.getPrototypeOf(root)).toBe(RawDataWorker.prototype); + }).catch(function(reason) { + fail(reason); + }).finally(function () { + done(); + }); + }); + + it("with childServices", function (done) { + var deserializer = new Deserializer(); + serialization = { + "root": { + "prototype": "montage/data/service/raw-data-worker", + "values": { + "name": "RawDataWorker", + "childServices": [ + {"@": "categoryService"}, + {"@": "movieService"} + ] + } + }, + "categoryService": { + "object": "spec/data/logic/service/category-service-reference.mjson" + }, + + "movieService": { + "object": "spec/data/logic/service/movie-service-reference.mjson" + } + }, + serializationString = JSON.stringify(serialization), + typeReference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/category.mjson", require); + type2Reference = new ModuleReference().initWithIdAndRequire("spec/data/logic/model/movie.mjson", require); + operation = { + objectDescriptorModule: typeReference, + type: OperationType.READ + }, + operation2 = { + objectDescriptorModule: type2Reference, + type: OperationType.READ + }; + + deserializer.init(serializationString, require); + deserializer.deserializeObject().then(function (root) { + expect(Object.getPrototypeOf(root)).toBe(RawDataWorker.prototype); + expect(root.serviceReferences.size).toBe(2); + return root.handleOperation(operation).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(1); + expect(data[0] instanceof Category).toBe(true); + return root.handleOperation(operation2); + }).then(function (data) { + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBe(1); + return null; + }); + }).catch(function(reason) { + fail(reason); + }).finally(function () { + done(); + }); + }) + }); +}) \ No newline at end of file