| @@ -0,0 +1,160 @@ | ||
|
|
||
| function DefaultArgumentBinder(name, options, request) { | ||
| var result = request.query[name]; | ||
| return result; | ||
| } | ||
| Function.prototype.curry = function () { | ||
| var self = this; | ||
| var args = arguments; | ||
| return function () { | ||
| var _args = Array.prototype.slice.call(args, 1); | ||
| var _args2 = Array.prototype.slice.call(arguments); | ||
| args = _args.concat(_args2); | ||
| return self.apply(null, args); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| $data.Class.define("$data.JSObjectAdapter", null, null, { | ||
| constructor:function (type, instanceFactory) { | ||
| var url = require('url'); | ||
| var q = require('q'); | ||
| Object.defineProperty(this, "type", { value:type, enumerable:true, writable:false, configurable:false }); | ||
| Object.defineProperty(this, "instanceFactory", { value:instanceFactory, enumerable:true, writable:false, configurable:false }); | ||
| Object.defineProperty(this, 'urlHelper', {value: url, enumerable:true, writable:false, configurable:false}); | ||
| Object.defineProperty(this, 'promiseHelper', {value: q, enumerable:true, writable:false, configurable:false}); | ||
| }, | ||
| handleRequest:function (req, res, next) { | ||
| var serviceInstance = this.instanceFactory(); | ||
|
|
||
| var memberName = this.resolveMemberName(req, serviceInstance); | ||
| var member = this.resolveMember(req, memberName); | ||
| var memberInfo = this.createMemberContext(member, serviceInstance); | ||
| var methodArgs = this.resolveArguments(req, serviceInstance, memberInfo); | ||
|
|
||
| //this will be something much more dynamic | ||
|
|
||
|
|
||
| var _v = memberInfo.invoke(methodArgs); | ||
|
|
||
|
|
||
| var self = this; | ||
|
|
||
| this.promiseHelper.when(_v).then(function (value) { | ||
| var isXml = false; | ||
| var responseType = "text/plain"; | ||
| if (value instanceof $data.XmlResult) { | ||
| value = value.data; | ||
| responseType = "text/xml"; | ||
| } else { | ||
| responseType = "application/json"; | ||
| var builder = new $data.oDataServer.oDataResponseDataBuilder( | ||
| { | ||
| version:"V2", | ||
| context:self.type, | ||
| methodConfig:member, | ||
| methodName:memberName | ||
| } | ||
| ); | ||
| value = builder.convertToResponse(value); | ||
| value = JSON.stringify(value); | ||
| } | ||
|
|
||
| res.setHeader('Content-Type', responseType); | ||
| res.end(value); | ||
|
|
||
| // res.setHeader('Content-Type', responseType); | ||
| // | ||
| // //if (value instanceof ) | ||
| // | ||
| // var translatedValue = (member.responseType === 'application/json' ? builder.convertToResponse(value) : value); | ||
| // var formatter = responseFormatters[responseType]; | ||
| // res.end(formatter(translatedValue)); | ||
| }); | ||
| }, | ||
|
|
||
| resolveMemberName:function (request, serviceInstance) { | ||
| var parsedUrl = this.urlHelper.parse(request.url); | ||
| //there will always be a leading '/' | ||
| var pathElements = parsedUrl.pathname.split('/').slice(1); | ||
| return pathElements[0]; | ||
| }, | ||
| resolveMember:function (request, memberName) { | ||
| var prefixedMemberName = request.method + "_" + memberName; | ||
| if (prefixedMemberName in this.type.prototype) { | ||
| return this.type.prototype[prefixedMemberName]; | ||
| } else { | ||
| return this.type.prototype[memberName]; | ||
| } | ||
| ; | ||
| }, | ||
| createMemberContext:function (member, serviceInstance) { | ||
| var self = this; | ||
|
|
||
| var memberContext = {}; | ||
|
|
||
| var params = member.params || []; | ||
| var paramBinders = []; | ||
|
|
||
|
|
||
| for (var i = 0; i < params.length; i++) { | ||
| var param = params[i]; | ||
| paramBinders.push(DefaultArgumentBinder.curry(null, param.name, {})) | ||
| } | ||
|
|
||
| memberContext.paramBinders = paramBinders; | ||
| memberContext.resultType = member.resultType; | ||
| memberContext.elementType = member.elementType; | ||
|
|
||
|
|
||
| memberContext.invoke = function (args, request, response) { | ||
| var executionContext = { | ||
| request:request, | ||
| response:response | ||
| }; | ||
|
|
||
| Object.defineProperty(serviceInstance, "executionContext", { | ||
| value:executionContext, | ||
| enumerable:false, | ||
| writable:false, | ||
| configurable:false | ||
| }); | ||
|
|
||
|
|
||
| var result = member.apply(serviceInstance, args); | ||
|
|
||
|
|
||
| var defer = self.promiseHelper.defer(); | ||
|
|
||
| function success(r) { | ||
| defer.resolve(r); | ||
| } | ||
|
|
||
| function error(r) { | ||
| defer.reject(r); | ||
| } | ||
|
|
||
| if (typeof result === 'function') { | ||
| result(success, error); | ||
| } else { | ||
| return self.promiseHelper.fcall(function () { | ||
| return result | ||
| }); | ||
| } | ||
| return defer.promise; | ||
| } | ||
|
|
||
| return memberContext; | ||
| }, | ||
| resolveArguments:function (request, serviceInstance, memberContext) { | ||
|
|
||
| var paramBinders = memberContext.paramBinders; | ||
| var paramValues = []; | ||
| for (var i = 0; i < paramBinders.length; i++) { | ||
| var binder = paramBinders[i]; | ||
| var result = binder(request); | ||
| paramValues.push(result); | ||
| } | ||
| return paramValues; | ||
| } | ||
| }, null); |
| @@ -0,0 +1,50 @@ | ||
| $data.Class.define("$data.JayService", null, null, { | ||
| constructor:function () { | ||
| } | ||
| }, { | ||
| serviceFunction:function (fn) { | ||
|
|
||
| var f = fn || function (fn) { | ||
| var keys = Object.keys(f); | ||
| for (var i = 0; i < keys.length; i++) { | ||
| fn[keys[i]] = f[keys[i]]; | ||
| } | ||
| return fn; | ||
| } | ||
|
|
||
| f.param = function (name, type) { | ||
| f.params = f.params || []; | ||
| f.params.push({name:name, type:type}); | ||
| return f; | ||
| } | ||
|
|
||
| f.returns = function (type) { | ||
| f.returnType = type; | ||
| return f; | ||
| } | ||
|
|
||
| f.returnsArrayOf = function (type) { | ||
| f.returnType = "Array"; | ||
| f.elementType = type; | ||
| return f; | ||
| } | ||
|
|
||
| f.returnsCollectionOf = function (type) { | ||
| f.returnType = "Collection"; | ||
| f.elementType = type; | ||
| return f; | ||
| } | ||
|
|
||
| return f; | ||
| }, | ||
| createAdapter:function (type, instanceFactory) { | ||
| return function (req, res, next) { | ||
| var adapter = new $data.JSObjectAdapter(type, instanceFactory); | ||
| adapter.handleRequest(req, res, next); | ||
| } | ||
| }, | ||
| resultAsXml:function (data) { | ||
| return new $data.XmlResult(data); | ||
| } | ||
| }); | ||
|
|
| @@ -0,0 +1,7 @@ | ||
| $data.Class.define("$data.ServiceBase", null, null, { | ||
| $metadata:$data.JayService.serviceFunction().returns("string")( | ||
| function (a, b) { | ||
| var meta = new $data.oDataServer.MetaDataGenerator({}, this.getType()); | ||
| return $data.JayService.resultAsXml(meta.generateMetadataXml()); | ||
| }) | ||
| }); |
| @@ -0,0 +1,9 @@ | ||
| $data.Class.define('$data.XmlResult', null, null, { | ||
| constructor:function (data) { | ||
| this.data = data; | ||
| }, | ||
| data:{value:{}}, | ||
| toString:function () { | ||
| return this.data; | ||
| } | ||
| }, null); |
| @@ -0,0 +1,71 @@ | ||
| /** | ||
| * Created with JetBrains WebStorm. | ||
| * User: zpace | ||
| * Date: 7/6/12 | ||
| * Time: 8:00 PM | ||
| * To change this template use File | Settings | File Templates. | ||
| */ | ||
| require('jaydata');//["$data"]; | ||
|
|
||
| $data.Entity.extend("Demo.Person", { | ||
| FirstName:{ type:"string" }, | ||
| LastName:{type:"string" }, | ||
| Age:{ type:"number" } | ||
| }); | ||
|
|
||
| $data.ServiceBase.extend("Demo.Service", { | ||
|
|
||
| MyFunkyFunction:$data.JayService.serviceFunction() | ||
| .param("a", "number") | ||
| .returnsArrayOf("number") | ||
| (function (a) { | ||
| return [5, 6, 7, 8, 9]; | ||
| }), | ||
|
|
||
|
|
||
| GetPersonsByAge:function (age) { | ||
| ///<param name="age" type="number" /> | ||
| ///<returns type="Array" /> | ||
| ///<elements type="Object" /> | ||
| return function (result, error) { | ||
|
|
||
| result([ | ||
| new Demo.Person({FirstName:"Viktor", LastName:'Borza'}), | ||
| new Demo.Person({FirstName:"Viktor", LastName:'Lazar'}) | ||
| ]); | ||
| } | ||
| }, | ||
|
|
||
| MyOtherFunction:function (a, b, c) { | ||
| ///<param name="a" type="string" /> | ||
| ///<param name="b" type="string" /> | ||
| ///<param name="c" type="number" /> | ||
| ///<returns type="Array" /> | ||
| ///<elements type="string" /> | ||
| return [a, b, c]; | ||
| }, | ||
| MyOtherFunctionX:function (a, b, c) { | ||
| ///<param name="a" type="string" /> | ||
| ///<param name="b" type="string" /> | ||
| ///<param name="c" type="number" /> | ||
| ///<returns type="Object" /> | ||
| return [a, b, c]; | ||
| } | ||
| }); | ||
|
|
||
| Demo.Service.annotateFromVSDoc(); | ||
|
|
||
| //var adapter = service.createAdapter(ServiceClass, instanceFactory); | ||
| var connect = require('connect'); | ||
| var app = require('connect')(); | ||
| app.use(connect.query()); | ||
| app.use("/", connect.static("/home/zpace/JSService/")); | ||
| //app.use("/ServiceClass", adapter); | ||
| app.use("/x", $data.JayService.createAdapter(Demo.Service, function () { | ||
| return new Demo.Service | ||
| })); | ||
| //var myAdapter = service.createAdapter($abc.SVC, function() { return new $abc.SVC({name:'Facebook'}) }); | ||
| //app.use("/my", myAdapter); | ||
|
|
||
| app.listen(3001); | ||
| console.log("started"); |
| @@ -0,0 +1,98 @@ | ||
| $data.Class.define('$data.oDataServer.oDataResponseDataBuilder', null, null, { | ||
| constructor:function (cfg) { | ||
| this.config = $data.typeSystem.extend({ | ||
| Version:'V2' | ||
| //context | ||
| //baseUrl | ||
| //CountRequest | ||
|
|
||
| //collectionName | ||
| //selectedFields | ||
| //includes | ||
|
|
||
| //or | ||
|
|
||
| //methodConfig, | ||
| //methodName | ||
|
|
||
| }, cfg); | ||
| }, | ||
| convertToResponse:function (data) { | ||
| if (this.config.CountRequest) | ||
| return data; | ||
|
|
||
| if (this.config.methodConfig) { | ||
| if (!this.config.methodConfig.returnType) | ||
| return undefined; | ||
|
|
||
| if (typeof this.config.context.isAssignableTo === 'function' && this.config.context.isAssignableTo($data.Base)) { | ||
| return this._convertJayDataFunction(data); | ||
| } else { | ||
| return this._convertFunction(data); | ||
| } | ||
| } else if (this.config.collectionName) { | ||
| return this._convertData(data); | ||
| } | ||
| }, | ||
| _convertFunction:function (data) { | ||
| var methodCfg = this.config.methodConfig; | ||
| if (Container.resolveType(methodCfg.returnType) === $data.Array && methodCfg.elementType) { | ||
| return { d:data }; | ||
| } else { | ||
| var result = { d:{} }; | ||
| result.d[methodCfg.serviceOpName || this.config.methodName] = data; | ||
| return result; | ||
| } | ||
| }, | ||
| _convertJayDataFunction:function (data) { | ||
| var methodCfg = this.config.methodConfig; | ||
| if (!methodCfg.returnType) | ||
| return undefined; | ||
|
|
||
| var rType = Container.resolveType(methodCfg.returnType); | ||
| if (rType === $data.Array || (typeof rType.isAssignableTo === 'function' && rType.isAssignableTo($data.Queryable))) { | ||
| var elementType = Container.resolveType(methodCfg.elementType); | ||
| var entitySets = this.config.context.memberDefinitions.getPublicMappedProperties(); | ||
| for (var i = 0; i < entitySets.length; i++) { | ||
| var memDef = entitySets[i]; | ||
| var memDefType = Container.resolveType(memDef.type); | ||
| if (typeof memDefType.isAssignableTo === 'function' && memDefType.isAssignableTo($data.EntitySet) && Container.resolveType(memDef.elementType) === elementType) { | ||
| //entitySet type | ||
| return this._convertData(data, elementType); | ||
| } | ||
| } | ||
|
|
||
| if (typeof elementType.isAssignableTo === 'function' && elementType.isAssignableTo($data.Entity)) { | ||
| //complexType | ||
| return this._convertData(data, elementType); | ||
| } else { | ||
| //primitiveType | ||
| return { d:data }; | ||
| } | ||
| } else { | ||
| if (typeof rType.isAssignableTo === 'function' && rType.isAssignableTo($data.Entity)) | ||
| data = this._convertData([data], rType, false)[0]; | ||
|
|
||
| var result = { d:{} }; | ||
| result.d[methodCfg.serviceOpName || this.config.methodName] = data; | ||
| return result; | ||
| } | ||
| }, | ||
| _convertData:function (data, elementType, versionSelector) { | ||
| var transform = new $data.oDataServer.EntityTransform(this.config.context, this.config.baseUrl); | ||
| var result = transform.convertToResponse( | ||
| data, | ||
| elementType || this.config.collectionName, | ||
| this.config.selectedFields, | ||
| this.config.includes); | ||
|
|
||
| if (versionSelector || versionSelector === undefined) { | ||
| if (this.config.version === 'V1') | ||
| return { d:result }; | ||
| else | ||
| return { d:{ results:result, __count:result.length } }; | ||
| } else { | ||
| return result | ||
| } | ||
| } | ||
| }); |
| @@ -61,163 +61,3 @@ $data.ServiceOperation = function(){ | ||
| return q._runQuery(clb); | ||
| } | ||
| }; | ||