@@ -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");

Large diffs are not rendered by default.

@@ -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
}
}
});
@@ -7,6 +7,7 @@ NPM_DIR = $(TARGET_DIR)/npm
NPM_BASE_DIR = ./npm
TYPESYSTEM_DIR = ./TypeSystem
TYPES_DIR = ./Types
JSERVICE_DIR = ./JayService
COMPILER = ./Tools/compiler.jar
GPL_LIC = ./GPL-LICENSE.txt
MIT_LIC = ./MIT-LICENSE.txt
@@ -102,6 +103,14 @@ JAYDATA_SOURCE = $(TYPES_DIR)/Expressions/ASTParser.js\
$(TYPES_DIR)/Authentication/FacebookAuth.js\
$(TYPES_DIR)/Authentication/BasicAuth.js\

JAYDATA_SERVER = $(JSERVICE_DIR)/oDataMetaDataGenerator.js\
$(JSERVICE_DIR)/XmlResult.js\
$(JSERVICE_DIR)/JSObjectAdapter.js\
$(JSERVICE_DIR)/JayService.js\
$(JSERVICE_DIR)/ServiceBase.js\
$(JSERVICE_DIR)/EntityTransform.js\
$(JSERVICE_DIR)/oDataResponseDataBuilder.js\

IndexedDbProvider = $(TYPES_DIR)/StorageProviders/IndexedDB/IndexedDBStorageProvider.js\

SqLiteProvider = $(TYPES_DIR)/DbClient/DbCommand.js\
@@ -164,13 +173,15 @@ npmjaydata-core: $(TYPE_SYSTEM) $(JAYDATA_SOURCE) $(CREDITS)
@@cp -r $(NPM_BASE_DIR)/jaydata/* $(NPM_DIR)/jaydata-core
@@cp -xr $(TYPESYSTEM_DIR) $(NPM_DIR)/jaydata-core/lib
@@cp -xr $(TYPES_DIR) $(NPM_DIR)/jaydata-core/lib
@@cp --parents $(JAYDATA_SERVER) $(NPM_DIR)/jaydata-core/lib
@@cp -r $(GPL_LIC) $(NPM_DIR)/jaydata-core
@@cp -r $(MIT_LIC) $(NPM_DIR)/jaydata-core
@@cp -r $(CREDITS) $(NPM_DIR)/jaydata-core
@$(foreach dir,$(TYPE_SYSTEM),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata-core/lib/index.js;)
@$(foreach dir,$(JAYDATA_SOURCE),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata-core/lib/index.js;)
@$(foreach dir,$(JAYDATA_SERVER),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata-core/lib/index.js;)
@@echo 'module.exports = $$data;' >> $(NPM_DIR)/jaydata-core/lib/index.js
@@sed -e 's/"dependencies": {},//;s/"name": "jaydata"/"name": "jaydata-core"/;s/jaydata@[0-9].[0-9].[0-9]/jaydata@$(VERSION)/;s/"version": "[0-9].[0-9].[0-9]"/"version": "$(VERSION)"/' $(NPM_BASE_DIR)/jaydata/package.json > $(NPM_DIR)/jaydata-core/package.json
@@sed -e 's/"dependencies": {},/"dependencies": {"datajs": "1.0.3", "q": "0.8.5", "url": ">0.0.1", "genx": "0.9.0", "libxmljs": "0.5.4"},/;s/"name": "jaydata"/"name": "jaydata-core"/;s/jaydata@[0-9].[0-9].[0-9]/jaydata@$(VERSION)/;s/"version": "[0-9].[0-9].[0-9]"/"version": "$(VERSION)"/' $(NPM_BASE_DIR)/jaydata/package.json > $(NPM_DIR)/jaydata-core/package.json

npmjaydata: $(TYPE_SYSTEM) $(JAYDATA_SOURCE) $(CREDITS)
@@echo "Building jaydata npm package..."
@@ -184,6 +195,7 @@ npmjaydata: $(TYPE_SYSTEM) $(JAYDATA_SOURCE) $(CREDITS)
@@cp --parents $(InMemoryProvider) $(NPM_DIR)/jaydata/lib
@@cp --parents $(MongoDbProvider) $(NPM_DIR)/jaydata/lib
@@cp --parents $(StormProvider) $(NPM_DIR)/jaydata/lib
@@cp --parents $(JAYDATA_SERVER) $(NPM_DIR)/jaydata/lib
@@cp -r $(GPL_LIC) $(NPM_DIR)/jaydata
@@cp -r $(MIT_LIC) $(NPM_DIR)/jaydata
@@cp -r $(CREDITS) $(NPM_DIR)/jaydata
@@ -196,14 +208,16 @@ npmjaydata: $(TYPE_SYSTEM) $(JAYDATA_SOURCE) $(CREDITS)
@$(foreach dir,$(InMemoryProvider),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata/lib/inmemory_index.js;)
@$(foreach dir,$(MongoDbProvider),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata/lib/mongodb_index.js;)
@$(foreach dir,$(StormProvider),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata/lib/storm_index.js;)
@$(foreach dir,$(JAYDATA_SERVER),echo "require('"$(dir)"');" >> $(NPM_DIR)/jaydata/lib/service_index.js;)
@@echo "require('./indexeddb_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./sqlite_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./odata_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./inmemory_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./mongodb_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./storm_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo "require('./service_index.js');" >> $(NPM_DIR)/jaydata/lib/index.js;
@@echo 'module.exports = $$data;' >> $(NPM_DIR)/jaydata/lib/index.js
@@sed -e 's/"dependencies": {},/"dependencies": {"datajs": "1.0.3"},/;s/jaydata@[0-9].[0-9].[0-9]/jaydata@$(VERSION)/;s/"version": "[0-9].[0-9].[0-9]"/"version": "$(VERSION)"/' $(NPM_BASE_DIR)/jaydata/package.json > $(NPM_DIR)/jaydata/package.json
@@sed -e 's/"dependencies": {},/"dependencies": {"datajs": "1.0.3", "q": "0.8.5", "url": ">0.0.1", "genx": "0.9.0", "libxmljs": "0.5.4"},/;s/jaydata@[0-9].[0-9].[0-9]/jaydata@$(VERSION)/;s/"version": "[0-9].[0-9].[0-9]"/"version": "$(VERSION)"/' $(NPM_BASE_DIR)/jaydata/package.json > $(NPM_DIR)/jaydata/package.json

npmindexeddb: $(IndexedDbProvider) $(CREDITS)
@@echo "Building IndexedDb provider npm package..."
@@ -61,163 +61,3 @@ $data.ServiceOperation = function(){
return q._runQuery(clb);
}
};

Function.prototype.chain = function(before, after){
var fn = this;

var ret = function(){
var chain = arguments.callee.chainFn;
var args = [];
if (arguments.length){
for (var i = 0; i < arguments.length; i++){
args.push(arguments[i]);
}
}
var argsCount = args.length;
var i = 0;

var readyFn = function(){
if (args[args.length - 1] && args[args.length - 1].success && typeof args[args.length - 1].success === 'function'){
var fn = args[args.length - 1].success;
fn.apply(this, arguments);
}else return arguments.length ? arguments[0] : undefined;
};

var callbackFn = function(){
var fn = chain[i];
i++;

var r = fn.apply(this, args);
if (typeof r === 'function'){
var argsFn = arguments;
args[argsCount] = (i < chain.length ? (function(){ return callbackFn.apply(this, argsFn); }) : (function(){ return readyFn.apply(this, argsFn); }));
r.apply(this, args);
}else{
if (i < chain.length){
callbackFn.apply(this, arguments);
}else readyFn(this, arguments);
}
}

callbackFn();
};

if (!ret.chainFn) ret.chainFn = (before || []).concat([fn].concat(after || []));

return ret;
};

Function.prototype.before = function(on){
var ret = this;

if (!this.chainFn) ret = ret.chain();
ret.chainFn.unshift(on);

return ret;
};

Function.prototype.after = function(on){
var ret = this;

if (!this.chainFn) ret = ret.chain();
ret.chainFn.push(on);

return ret;
};

Function.prototype.contentType = function(mime){
return this.extend({
contentType: mime
});
};

Function.prototype.returns = function(type, elementType){
if (typeof type === 'string')
type = Container.resolveType(type);

if (typeof elementType === 'string')
elementType = Container.resolveType(elementType);

return this.extend({
returnType: type,
elementType: elementType
});
};

Function.prototype.params = function(params){
/*for (var p in params){
if (typeof params[p] === 'string')
params[p] = Container.resolveType(params[p]);
}*/

return this.extend({
params: params
});
};

Function.prototype.serviceName = function(serviceName){
return this.extend({
serviceName: serviceName
});
};

Function.prototype.method = function(method){
return this.extend({
method: method
});
};

Function.prototype.webGet = function(){
return this.method('GET');
};

Function.prototype.webInvoke = function(){
return this.method('POST');
};

Function.prototype.authorize = function(roles, callback){
var r = {};
if (roles instanceof Array){
for (var i = 0; i < roles.length; i++){
if (typeof roles[i] === 'string') r[roles[i]] = true;
}
}else r = roles;

this.roles = r;

var fn = this;

ret = function(){
var pHandler = new $data.PromiseHandler();
var clbWrapper = pHandler.createCallback(callback);
var pHandlerResult = pHandler.getPromise();
var args = arguments;

clbWrapper.success = clbWrapper.success.after(function(){
fn.apply(this, args);
});

$data.Access.isAuthorized($data.Access.Execute, this.user, fn.roles, clbWrapper);

return pHandlerResult;
};

return ret;
};

Function.prototype.promise = function(callback){
var fn = this;

var ret = function(){
var pHandler = new $data.PromiseHandler();
var clbWrapper = pHandler.createCallback(callback);
var pHandlerResult = pHandler.getPromise();

arguments[arguments.length++] = clbWrapper;
fn.apply(this, arguments);

return pHandlerResult;
};

return ret;
};