Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Updates

  • Loading branch information...
commit 8be7a3b7891f2ba6230b03530d043a3efbbc1e46 1 parent 8d17832
@kriszyp authored
View
9 jackconfig.js
@@ -1,9 +0,0 @@
-var PinturaApp = require("pintura").App;
-var Cascade = require("jack/cascade").Cascade;
-var Static = require("jack/static").Static;
-
-exports.app = Cascade([
- Static(null,{urls:[""],root:["web"]}),
- PinturaApp({
- })
-]);
View
21 lib/global.js
@@ -1,21 +0,0 @@
-/**
- * Various global cleanup operations
- */
-(function(){
- var secureRandom = new java.security.SecureRandom();
- Math.random = function(){
- return secureRandom.nextDouble();
- };
- if(!Object.defineProperty){
- Object.defineProperty = function(target, property, def){
- if(def.get || def.set){
- target.__defineGetter__(property, def.get);
- target.__defineSetter__(property, def.set);
- }
- else if ("value" in def){
- target[property] = def.value;
- }
- };
- }
-})();
-
View
8 lib/jsgi/auth.js
@@ -1,8 +0,0 @@
-exports.Authentication = function(nextApp){
- return function(env){
- var client;
- var response = nextApp(env);
- response.headers.Username = client.username || "";
- return response;
- };
-};
View
91 lib/jsgi/comet.js
@@ -1,91 +0,0 @@
-var Future = require("promise").Future;
-//var Lock = require("concurrency").Lock;
-/**
- * Comet JSGI app factory that allows data to be sent to clients
- */
-var Comet = exports.Comet = function(env, options){
- return function(env){
- if(options.maxConnections == 1 && env.session && env.session.cometCanceller){
- // if a comet connection has already been made to this clientSession, we need to try to end the other one
- env.session.cometCanceller();
- }
- var streaming = options.streaming;
- if(!env.USER_AGENT.match(/Firefox|Safari/)){
- streaming = false;
- }
- var clientSession = env.clientSession;
- var bytesSent = 0;
- var future = new Future();
- var response = {
- status: 200,
- headers:{},
- body:{
- forEach: function(write){
- clientSession.cometListener = function(chunk){
- bytesSent += chunk.length;
- write(chunk);
- if(!streaming || (bytesSent > bytesSentThreshold)){
- delete clientSession.cometListener;
- future.fulfill();
- }
- };
- if(env.session){
- env.session.cometCanceller = function(){
- response.status = 409;
- future.fulfill();
- }
- }
- sendToPage(clientSession);
- return future.promise;
- }
- }
- };
-
- return response;
- };
-};
-
-var sendToPage = exports.sendToPage = function(clientSession, chunk){
- var chunks = clientSession.cometChunks;
- if(!chunks){
- var chunks = clientSession.cometChunks = [];
- clientSession.chunks.lock = new Lock();
- }
- var lock = chunks.lock;
- lock.lock();
- if(chunks){
- chunks.push(chunk);
- }
- var chunksToSend;
- if(clientSession.cometListener && chunks.length){
- clientSession.cometListener(chunks.splice(0,chunks.length));
- }
- lock.unlock();
-}
-
-
-/**
- * Middleware that adds REST Channels to the server
- */
-exports.Channels= function(nextApp, options /*subscribe, serializer, path*/){
- var path = options.path || "/channels";
- var serializer = options.serializer || JSON.stringify;
- var cometApp = Comet(options);
- return function(env){
- if(path == env.PATH_INFO){
- // channels handler
- return cometApp(env);
- }else{
- if(env.HTTP_SUBSCRIBE == "*"){
- // add subscription
- var clientSession = env.clientSession;
- options.subscribe(env.PATH_INFO, function(notification){
- sendToPage(clientSession, serializer(notification, env));
- });
- }
- var response = nextApp(env);
- response.headers["Link"] = '<' + path + '>; rel="monitor"';
- return response;
- }
- };
-};
View
80 lib/jsgi/session.js
@@ -1,80 +0,0 @@
-exports.ClientSession = function(nextApp, options){ //onNew, onDestroy){
- var clientSessions = {};
-
- if(typeof setInterval == "function"){
- // if setInterval is available, we will use it to clean out unused sessions
- setInterval(function(){
- var timeout = options.timeout || 60000; // one minute is the default
- for(var i in clientSessions){
- if(new Date().getTime() - clientSessions[i].lastUsed > timeout){
- options.onDestroy(clientSessions[i]);
- delete clientSessions[i];
- }
- }
- }, 1000);
- }
- return function(env){
- var clientId = env.HTTP_CLIENT_ID;
- env.clientSessions = clientSessions;
- var clientSession = clientSessions[clientId];
- if(!clientSession){
- clientSessions[clientId] = clientSession = {};
- options.onNew(clientSession);
- }
- clientSession.lastUsed = new Date().getTime();
- env.clientSession = clientSession;
-
- return nextApp(env);
- };
-};
-
-exports.Sequential = function(nextApp){
- var assignSync = sync(function(target, func){
- return target._sequenceLock = target._sequenceLock || sync(func);
- });
- return function(env){
- if(env.HTTP_SEQ_ID != null){
- // just sequence anything in the http session
- return (assignSync(env.session, function(env){
- return nextApp(env);
- }))(env);
- }
- var clientSession = env.clientSession;
-
- var nextId = (clientSession.sequence.lastId || 0) + 1;
- if(env.HTTP_SEQ_ID == nextId){
- var response = nextApp(env);
- }
- else{
- var future = clientSession.sequence[nextId] = new Future();
- var response = {
- status:200,
- headers:{},
- body: {
- forEach:function(write){
- return future.promise.then(function(){
- var resp = nextApp(env);
- for(var i in resp){
- response[i] = resp[i];
- }
- return resp.body.forEach(write);
- });
- }
- }
- };
- setTimeout(function(){
- future.fulfill();
- },5000);
- return response;
- }
- for(var i in clientSession.sequence){
- if(i < nextId){
- // execute it out of this thread so this request can finish
- setTimeout(function(){
- clientSession.sequence[i].future.fulfill();
- },0);
- break;
- }
- }
- }
-};
View
72 lib/jsgi/xsite.js
@@ -1,72 +0,0 @@
-// Combines JsonP, WindowName, and CrossSiteXhr for full support for all common
-// of cross-site web app access to resources
-exports.CrossSite = function(nextApp){
- return JsonP(
- WindowName(
- CrossSiteXhr(nextApp)));
-
-};
-
-var httpParamRegex = /^http[_-]/;
-var convertParams = function(env){
- // must warn other apps that this is a cross-domain request so they can apply
- // proper security defenses
- env.crossSite = true;
- var parts = env.QUERY_STRING.split("&");
- var i = 0;
- for each(var part in parts){
- var nameValue = parts.split("=");
- if(httpParamRegex.test(nameValue[0])){
- env["HTTP_" + nameValue[0].substring(5).replace(/-/,'_').toUpperCase()] = decodeURIComponent(nameValue[1]);
- // TODO: handle specific ones, in particular the http-content
- parts.splice(i,1);
- }else{
- i++;
- }
- }
- if(parts){
- env.QUERY_STRING = parts.join("&");
- }
-};
-
-var JsonP = exports.JsonP = function(nextApp){
- return function(env){
- var callback = getURLParameter("callback") || getURLParameter("jsonp");
- if(callback){
- convertParams(env);
- var response = nextApp(env);
- response.headers["Content-Type"] = "application/javascript; charset=UTF-8";
-
- var body = response.body;
- // TODO: Add async support
- response.body = {forEach : function(write) {
- write(callback+"(");
- var possiblePromise = body.forEach(write);
- write(")");
- }};
- }
- return response;
- };
-};
-
-var WindowName = exports.WindowName = function(nextApp){
- return function(env){
- var windowName = getURLParameter("windowname");
- if(windowName){
- convertParams(env);
- var response = nextApp(env);
- response.headers["Content-Type"] = "text/html; charset=UTF-8";
- var body = response.body;
- response.body = {forEach : function(write) {
- write("<html><script type='text/javascript'>var loc = window.name;window.name=\"");
- body.forEach(function(part){
- var part = JSON.stringify(part);
- write(part.substring(1, part.length - 1));
- });
- write("\";location=loc;</script></html>");
- }};
- }
- return response;
- };
-};
-
View
265 lib/query.js → lib/json-query.js
@@ -1,23 +1,22 @@
-Query = function(){
- throw new TypeError("Can not directly instantiate a Query");
-};
-Query.prototype = [];
+/**
+ * This module provides querying functionality, with a JSONQuery implementation
+ * and a helper class for parsing JSONQueries
+ */
+
+// The main function for executing JSONQueries
+exports.jsonQuery = jsonQuery;
-QueryString = function(string, params){
- this.string = string;
- this.params = params;
-};
-QueryString.prototype = new String("");
// its easier to write (and read) these as regular expressions (since that is how they are used)
var $prop = /(?:@?\.?([a-zA-Z_$][\w_$]*))/.source;
-var $value = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/[\w_$]+\/[\w]+|\-?[0-9]+(?:\.[0-9]+)?(?:[eE]\-?[0-9]+)|true(?![\w])|false(?![\w])|null(?![\w]))/.source;
+var $value = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/[\w_$]+\/[\w]+|\-?[0-9]+(?:\.[0-9]+)?(?:[eE]\-?[0-9]+)?|true(?![\w])|false(?![\w])|null(?![\w]))/.source;
var $comparator = /(===|!==|==|!=|>=|<=|=|<|>)/.source;
var $operator = /([\+\-\*\/\&\|\?\:])/.source;
var $logic = /([\&\|])/.source;
var $expression = /((?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\[(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\]])*\]|[^\]])*)/.source;
var $filter = "(?:\\[?\\?" + $expression + "\\]?)";
var $sort = "(?:\\[[\\\\\\/]" + $expression + "\\])";
-function convertRegex(regexp){
+exports.QueryRegExp = QueryRegExp;
+function QueryRegExp(regexp){
return new RegExp((regexp.source || regexp).replace(/\$[a-z]+/g, function(t){
switch(t){
case "$prop" : return $prop;
@@ -32,62 +31,187 @@ function convertRegex(regexp){
return t;
}), (regexp.global ? "g" : "") + (regexp.ignoreCase ? "m" : ""));
}
-for each (let i in ["charAt", "toString", "valueOf"]){
- QueryString.prototype[i] = function(){
- return String.prototype[i].apply(this.string, arguments);
- }
+function throwMaxIterations(){
+ throw new Error("Query has taken too much computation, and the user is not allowed to execute resource-intense queries. Increase maxIterations in your config file to allow longer running non-indexed queries to be processed.");
}
-QueryString.prototype.match = function(regexp){
- var matches = String.prototype.match.call(this.string, convertRegex(regexp));
- for each(let i in matches){
- matches[i] = new QueryString(i);
+exports.maxIterations = 10000;
+function stringToValue(string){
+ switch(string){
+ case "true": return true;
+ case "false": return false;
+ case "null": return null;
+ default:
+ var number = parseFloat(string, 10);
+ if(isNaN(number)){
+ if(exports.compatible){
+ if(string.charAt(0) == "'" && string.charAt(string.length-1) == "'"){
+ return JSON.parse('"' + string.substring(1,string.length-1) + '"');
+ }
+ }
+ return string;
+ }
+ return number;
}
- return matches;
+
};
-QueryString.prototype.replace = function(regexp, newStr){
- if(typeof newStr == 'function'){
- var func = newStr;
- newStr = function(){
- for(var i = 0; i < arguments.length; i++){
- arguments[i] = new QueryString(arguments[i]);
+function convertComparator(comparator){
+ switch(comparator){
+ case "-+" : return "<";
+ case "+-" : return ">";
+ case "+=-" : return "=>";
+ case "-=+" : return "=<";
+ }
+ return comparator;
+}
+exports.compatible = true;
+exports.parseQuery = function(/*String*/query){
+ if(exports.compatible){
+ query = query.replace(/%3C=/g,"-=+").replace(/%3E=/g,"+=-").replace(/%3C/g,"-+").replace(/%3E/g,"+-");
+ }
+ var ast = {children:[], type:"group"};
+ var originalAst = ast;
+ query.replace(/(([\w%\._]+)([\-=\+!]+)([\+\-\w%\._]+))|([&\|,\)])|(([\+\-\w%\._]*)(\(?))/g,
+ function(t, expression, name, comparator, value, token, callOrGroup, methodOrValue, openParan){
+ if(expression){
+ comparison = {
+ type:"comparison",
+ comparator: convertComparator(comparator),
+ name: decodeURIComponent(name),
+ value: stringToValue(decodeURIComponent(value))
+ };
+ ast.children.push(comparison);
+ }
+ else if(callOrGroup){
+ if(openParan){
+ var newAst = {type:"group", children:[]};
+ ast.children.push(newAst);
+ newAst.parent = ast;
+ ast = newAst;
+ if(methodOrValue){
+ ast.type = "call";
+ ast.method = methodOrValue;
+ }
+ }
+ else{
+ ast.children.push(stringToValue(methodOrValue));
+ }
+ }
+ else if(token){
+ switch(token){
+ case ')' :
+ ast = ast.parent;
+ break;
+ case '&' : case '|':
+ if(!ast.logic){
+ ast.logic = token;
+ }
+ else if(ast.logic != token){
+ var newAst = {type:"group", children:[]};
+ newAst.children.push(ast);
+ if(ast.parent){
+ ast.parent.children[ast.parent.length-1] = newAst;
+ }
+ // set the parent to that because a real paran should go up to the real parent
+ newAst.parent = ast.parent;
+ ast = newAst;
+ ast.logic = token;
+ }
+ }
+ }
+ });
+ ast.logic = ast.logic || "&";
+ return ast;
+ /*
+ var TOKEN = /\(|[\w%\._]+/g;
+var OPERATOR = /[-=+!]+|\(/g;
+var NEXT = /[&\|\)]/g;
+
+ TOKEN.lastIndex = 0;
+ function group(){
+ var ast = [];
+ var match = TOKEN.exec(query);
+ if(match === '('){
+ ast.push(group());
+ }
+ else{
+ OPERATOR.lastIndex = TOKEN.lastIndex;
+ var operator = OPERATOR.exec(query);
+ var comparison = {};
+ ast.push(comparison);
+ if(operator == '('){
+ comparison.type = "call";
+ comparison.parameters =
}
- return func.apply(this, arguments);
+ comparison.type = operator;
+
}
+ return ast;
}
- return new QueryString(String.prototype.replace.call(this.string, convertRegex(regexp), newStr));
-};
-QueryString.prototype.execute = function(target){
- return jsonQuery(this, this.params)(target);
+ return group();*/
}
-onRemoteRequest = function(xhr, method, url){
- // console.log("onRemoteRequest ", url);
-};
-
-var clientId = Math.random() + "";
-//var hostSeqId = {};
-// remote request handling
-remoteRequest = function(method, url, body, start, end){
- var xhr = new XMLHttpRequest();
- xhr.open(method, url, false);
- xhr.setRequestHeader("Accept", "application/javascript;q=1,application/json;q=0.8");
- xhr.setRequestHeader("Client-Id", clientId);
- //var host = url.match(/^\w+:\/\/[^\/]+/)[0];
- //var seqId = hostSeqId[host] = (hostSeqId[host] || 0) + 1;
- //xhr.setRequestHeader("Seq-Id", seqId);
- xhr.setRequestHeader("Server-Methods", "false");
- if(start || end){
- xhr.setRequestHeader("Range", "items=" + start + "-" + end);
+function executeQuery(query, options, target){
+ if(typeof query === "string"){
+ query = parseQuery(query);
}
- onRemoteRequest(xhr, method, url);
- xhr.send(body);
- return xhr;
-};
-function throwMaxIterations(){
- throw new AccessError("Query has taken too much computation, and the user is not allowed to execute resource-intense queries. Increase maxIterations in your config file to allow longer running non-indexed queries to be processed.");
+ var methods = options.methods || {};
+ if(!methods.sort){
+ methods.sort = function(sortAttribute){
+ var firstChar = sortAttribute.charAt(0);
+ var ascending = true;
+ if(firstChar == "-" || firstChar == "+"){
+ if(firstChar == "-"){
+ ascending = false;
+ }
+ sortAttribute = sortAttribute.substring(1);
+ }
+ this.sort(function(a, b){
+ return ascending == a[sortAttribute] > b[sortAttribute] ? 1 : -1;
+ });
+ return this;
+ }
+ }
+ var first = true;
+ var js = "";
+ query.children.forEach(function(child){
+ if(child.type == "comparison"){
+ if(!options){
+ throw new Error("Values must be set as parameters on the options argument, which was not provided");
+ }
+ if(first){
+ js += "target = target.filter(function(item){return ";
+ first = false;
+ }
+ else{
+ js += query.logic + query.logic;
+ }
+ var index = (options.parameters = options.parameters || []).push(child.value);
+ if(child.comparator == "="){
+ child.comparator = "==";
+ }
+ js += "item." + child.name + child.comparator + "options.parameters[" + (index -1) + "]";
+
+ }
+ if(!first){
+ js += "});";
+ }
+ else if(child.type == "call"){
+ if(methods[child.method]){
+ var index = (options.parameters = options.parameters || []).push(child.children);
+ js += "target = methods." + child.method + ".apply(target,options.parameters[" + (index -1) + "]);";
+ }
+ else{
+ throw new URIError("Invalid JSON Query syntax, " + child.method + " not implemented");
+ }
+ }
+ else{
+ throw new URIError("Invalid JSON Query syntax, unknown type");
+ }
+ });
+ return eval(js + "target;");
+
}
-// persevere edit
-var tempQuery = function(/*String*/query, args){// persevere edit
+function jsonQuery(/*String*/query, obj, args){
// summary:
// Performs a JSONQuery on the provided object and returns the results.
// If no object is provided (just a query), it returns a function that evaluates objects
@@ -101,14 +225,13 @@ var tempQuery = function(/*String*/query, args){// persevere edit
// | evaluator = dojox.json.query("?foo='bar'&rating>3");
query = query.toString();
var iterations = 0;
- var maxIterations = org.persvr.data.PersistableArray.maxIterations;
// setup JSONQuery library
function slice(obj,start,end,step){
var i, results = [];
if(step < 5){
// do an iterator friendly
i = 0;
- for each(var item in obj){
+ obj.forEach(function(item){
if(i >= end){
return results;
}
@@ -116,10 +239,10 @@ var tempQuery = function(/*String*/query, args){// persevere edit
results.push(item);
}
i++;
- if(i > maxIterations){
+ if(i > exports.maxIterations){
throwMaxIterations();
}
- }
+ });
return results;
}
var len=obj.length;
@@ -128,7 +251,7 @@ var tempQuery = function(/*String*/query, args){// persevere edit
start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end);
iterations += end - start;
- if(iterations > maxIterations){
+ if(iterations > exports.maxIterations){
throwMaxIterations();
}
for(i=start; i<end; i+=step){
@@ -149,8 +272,8 @@ var tempQuery = function(/*String*/query, args){// persevere edit
results.push(obj[name]);
}
}
- for each(var val in obj){
- if(iterations++ > maxIterations){
+ obj.forEach(function(val){
+ if(iterations++ > exports.maxIterations){
throwMaxIterations();
}
if(!name){
@@ -159,7 +282,7 @@ var tempQuery = function(/*String*/query, args){// persevere edit
}else if(val && typeof val == 'object'){
walk(val);
}
- }
+ });
}
if(name instanceof Array){
// this is called when multiple items are in the brackets: [3,4,5]
@@ -170,7 +293,7 @@ var tempQuery = function(/*String*/query, args){// persevere edit
return obj[name[0]];
}
for(var i = 0; i < name.length; i++){
- if(iterations++ > maxIterations){
+ if(iterations++ > exports.maxIterations){
throwMaxIterations();
}
results.push(obj[name[i]]);
@@ -254,7 +377,7 @@ var tempQuery = function(/*String*/query, args){// persevere edit
if(oper){
// make a copy of the array and then sort it using the sorting expression
var first = true;
- return ".fastSort(" + oper[1].replace(/\s*,?\s*([\/\\])\s*([^,\\\/]+)/g,function(t,a,b){
+ return ".sort(" + oper[1].replace(/\s*,?\s*([\/\\])\s*([^,\\\/]+)/g,function(t,a,b){
return (first ? (first=false) || '': ',') + "function($obj){return " + b + "}," + (a== "/");
}) + ")";
}
@@ -291,5 +414,11 @@ var tempQuery = function(/*String*/query, args){// persevere edit
});
// create a function within this scope (so it can use expand and slice)
- return eval("1&&function($,$1,$2,$3,$4,$5,$6,$7,$8,$9){var $obj=$;return " + query + "}");
+ var executor = eval("1&&function($,$1,$2,$3,$4,$5,$6,$7,$8,$9){var $obj=$;return " + query + "}");
+
+ for(var i = 0;i<arguments.length-1;i++){
+ arguments[i] = arguments[i+1];
+ }
+ return obj ? executor.apply(this,arguments) : executor;
+
};
View
122 lib/media.js
@@ -1,122 +0,0 @@
-exports.Media = function Media(props){
- Object.clone(props, this);
- Media.instances[this.mediaType] = this;
-};
-Media.instances = {};
-Media.facetOf= function(source, acceptTypeHeader){
- var bestMedia = null;
- var bestQuality = 0;
- var bestType = null;
- if(acceptTypeHeader==null)
- acceptTypeHeader = "*/*";
- var acceptTypes = acceptTypeHeader.split(/\s*,\s*/);
- for each (var acceptType in acceptTypes){
- var parts = acceptType.split(/\s*;\s*/);
- var type = parts[0];
- var clientQuality = 1;
- for each(var part in parts){
- if(part.substring(0,2) == "q="){
- clientQuality = parseFloat(part.substring(2)) || 0;
- }
- }
- if("*/*" == type){
- for each(var media in Media.instances){
- var quality = clientQuality + media.getQuality(source);
- if(quality > bestQuality){
- bestMedia = media;
- bestQuality = quality;
- bestType = media.contentType;
- }
- }
- }
- else{
- var media = Media.instances.filter(function(media){
- return media.mediaType == type;
- })[0];
- if(media){
- var quality = clientQuality + media.getQuality(source);
- if(quality > bestQuality){
- bestMedia = media;
- bestQuality = quality;
- bestType = media.contentType;
- }
- }
- }
- }
- return bestMedia || org.persvr.remote.DataSerializer.findMedia(source, acceptTypeHeader, true);
- };
-
-commit();
-var JSONSerializer = org.persvr.remote.JSONSerializer,
- JavaScriptSerializer = org.persvr.remote.JavaScriptSerializer;
-Media({
- mediaType:"application/json",
- getQuality: function(object){
- return 0.9;
- },
- serialize: function(object, env){
- return {
- forEach:function(callback){
- new JSONSerializer().serialize(object, callback);
- }
- };
- },
- deserialize: function(inputStream, env){
-
- }
-});
-Media({
- mediaType:"application/javascript",
- getQuality: function(object){
- return 0.9;
- },
- serialize: function(object, env){
- return {
- forEach:function(callback){
- new JavaScriptSerializer().serialize(object, callback);
- }
- };
- },
- deserialize: function(inputStream, env){
-
- }
-});
-/*Media({
- mediaType:"* /*",
- getQuality: function(object){
- return 0;
- },
- serialize: function(object, env, response){
- response.status = 406;
- return "No acceptable MIME type was specified in the Accept header, it is recommended that you include * /* in the Accept header to get the best representation."
- },
- deserialize: function(inputStream, env){
-
- }
-});*/
-Media({
- mediaType:"application/x-www-form-urlencoded",
- getQuality: function(object){
- return 0.1;
- },
- serialize: function(object, env, response){
- response.status = 406;
- return "No acceptable MIME type was specified in the Accept header, it is recommended that you include */* in the Accept header to get the best representation."
- },
- deserialize: function(inputStream, env){
-
- }
-});
-Media({
- mediaType:"multipart/*",
- getQuality: function(object){
- return 0.2;
- },
- serialize: function(object, env, response){
- response.status = 406;
- return "No acceptable MIME type was specified in the Accept header, it is recommended that you include */* in the Accept header to get the best representation."
- },
- deserialize: function(inputStream, env){
-
- }
-});
View
78 lib/persistence.js
@@ -1,78 +0,0 @@
-pintura.getDataLoader(env).get(id) or .query(query)
-
-pintura.facetedDataInterface = pintura.dataInterface(Facet);
-var OtherPersistable = pintura.dataInterface.transactionFor(env);
-var SomePersistable = pintura.dataInterface.transactionFor(env).forTable(tableName);
-var obj = SomePersistable.get(id);
-new SomePersistable();
-SomePersistable.set(obj, 3);
-obj.foo = 3;
-SomePersistable.get(obj);
-SomePersistable.save(obj);
-
-pintura.dataInterface = function(Facet){
- return {
- transactionFor: function(env){
- function Transaction(){
-
- }
-
- Object.copy({
- forTable: function(table){
-
- },
- get: function(idOrInstance, name){
-
- var facet = Facet.facetOf(stores[table].get(id));
- Object.defineProperty(facet,{
- value: id,
- configurable: false,
- writable: false
- });
- // now apply JSON Schema
- },
- set: function(instance, name, value){
-
- },
- save: function(instance){
-
- },
- remove: function(instance){
-
- },
- commit: function(precondition){
-
- },
- abort:
- lock:
-
- }, Persistable);
- return Persistable;
- }
- }
-}
-
-
-pintura.Facet = function(props){
- var facetClass = function(source,env){
- if(!facetClass.allowed(source, env)){
- throw new AccessError("Access denied to " + source);
- }
- var facet = {};
- Object.clone(source, facet);
- return facet;
- }
- Object.copy(props, facetClass);
-}
-var Something = Facet({
- properties: {
- foo: String,
- bar: {hidden: true}
- },
- allowed: function(object, env){
- return env.authenticatedUser.name == "bill";
- }
-});
-SomePersistable
-pintura.dataLoader.forEnv(env).getTable(tableName)
-Facet.facetOf
View
8 lib/persvr.js
@@ -0,0 +1,8 @@
+/**
+* Some backwards compatible functions for Persevere
+*/
+
+var Model = require("./model").Model;
+Class = function(schema){
+ return global[schema.id] = Model(schema.id, schema);
+};
View
77 lib/pintura.js
@@ -1,77 +0,0 @@
-/**
- * This is the essential breakdown of components for the Pintura
- */
-exports.PinturaApp = function(nextApp){
- return require("jsgi/xsite").CrossSite(
- require("jsgi/session").ClientSession(
- require("jsgi/auth").Authentication(
- require("jsgi/comet").Channels(
- require("jsgi/session").Sequential(
- ObjectHandler(
- require("jsgi/static").Static(
- nextApp
- ),
- require("media").Media,
- require("facet").facetedLoad
- )
- )
- )
- )
- )
- );
-};
-
-exports.ObjectHandler = function ObjectHandler(env, options){
- var media = options.media;
- var load = options.load;
- return function(env){
- try{
- checkForTablePut(env);
- var precondition = getPrecondition(env);
- if(!precondition()){
- throw Error();
- }
- var headers = setCommonHeaders();
- var target = env.requestObject;
- var status = 200;
- var method = env.REQUEST_METHOD.toLowerCase();
- switch(method){
- // get, head, and put have precise semantics that shouldn't be overriden by classes
- case "get":
- break;
- case "put":
- if(env.requestObject.id != objId){
- throw new Error();
- }
- status = 201;
- break;
- case "head":
- return {status: 204, headers: {}};
- default:
- // delete, post, and others are handled by classes
- var requestObject = getRequestObject();
- if(method == "post" && jsonRpc)
- doJsonRpc();
- if(typeof target[method] == 'function'){
- target = target[method](requestObject, env);
- }else{
- return methodNotAllowed(); // return 405
- }
- }
- if(env.HTTP_RANGE){
- response.headers["Content-Range"] =
- load(env.PATH_INFO, start, end);
- }
- commit(precondition);
- return {
- status: status,
- headers: headers,
- body: target
- };
- }catch(e){
- abort();
- // convert different JS errors to HTTP status codes and any other headers and body
- return javascriptErrorToHttp(e);
- }
-};
-};
View
144 lib/promise.js
@@ -1,144 +0,0 @@
-// this is based on the CommonJS spec for promises:
-// http://wiki.commonjs.org/wiki/Promises
-
-// A typical usage:
-// A provider will create a future and fulfill when it completes an action
-// var Future = require("promise").Future;
-// var future = new Future();
-// asyncOperation(function(){
-// future.fulfill("succesful result");
-// });
-// future.promise -> given to the consume
-//
-// A consumer can use the promise
-// promise.then(function(result){
-// ... when the action is complete this is executed ...
-// },
-// function(error){
-// ... executed when the promise fails
-// });
-
-var Promise = exports.Promise = function(){
-};
-
-Promise.prototype.then = function(fulfilledCallback, errorCallback, progressCallback){
- throw new TypeError("The Promise base class is abstract, this function must be implemented by the Promise implementation");
-};
-
-/**
- * If an implementation of a promise supports a concurrency model that allows
- * execution to block until the promise is fulfilled, the wait function may be
- * added.
- */
-// Promise.prototype.wait = function(){
-// };
-
-/**
- * If an implementation of a promise can be cancelled, it may add this function
- */
- // Promise.prototype.cancel = function(){
- // };
-
-Promise.prototype.get = function(propertyName){
- return this.then(function(value){
- return value[propertyName];
- });
-};
-
-Promise.prototype.call = function(functionName /*, args */){
- return this.then(function(value){
- return value[propertyName].apply(value, Array.prototype.slice.call(arguments, 1));
- });
-};
-
-
-// A future provides an API for creating and fulfilling a promise.
-var Future = exports.Future = function(){
- var result, finished, isError, waiting = [];
- var promise = this.promise = new Promise();
-
- function notifyAll(value){
- if(finished){
- throw new Error("This future has already been fulfilled");
- }
- result = value;
- finished = true;
- for(var i = 0; i < waiting.length; i++){
- notify(waiting[i]);
- }
- }
- function notify(listener){
- var func = (isError ? listener.error : listener.fulfilled);
- try{
- var newResult = func && func(result);
- if(newResult instanceof Promise){
- newResult.then(function(result){
- listener.future.fulfill(result);
- },
- function(error){
- listener.future.error(error);
- });
- }
- else{
- listener.future.fulfill(newResult === undefined ? result : newResult);
- }
- }
- catch(e){
- listener.future.error(e);
- }
- }
- // calling fulfill will fulfill the promise
- this.fulfill = function(value){
- notifyAll(value);
- };
- // calling error will indicate that the promise failed
- this.error = function(error){
- isError = true;
- notifyAll(error);
- }
- // call progress to provide updates on the progress on the completion of the promise
- this.progress = function(update){
- for(var i = 0; i < waiting.length; i++){
- var progress = waiting[i].progress;
- progress && progress(update);
- }
- }
- // provide the implementation of the promise
- promise.then = function(fulfilledCallback, errorCallback, progressCallback){
- var returnFuture = new Future();
- var listener = {fulfilled: fulfilledCallback, error: errorCallback, progress: progressCallback, future: returnFuture};
- if(finished){
- notify(listener);
- }
- else{
- waiting.push(listener);
- }
- return returnFuture.promise;
- };
-};
-
-/**
- * Promise manager to make it easier to consume promises
- */
-exports.Queue = {
- when: function(value, fulfilledCallback, errorCallback, progressCallback){
- try{
- if(value instanceof Promise){
- value = value.then(fulfilledCallback, errorCallback, progressCallback);
- }
- else{
- value = fulfilledCallback(value);
- }
- if(value instanceof Promise){
- return value;
- }
- var future = new Future();
- future.fulfill(value);
- return future.promise;
- }catch(e){
- var future = new Future();
- future.error(e);
- return future.promise;
- }
- };
-};
View
226 lib/schema.js
@@ -1,226 +0,0 @@
-/**
- * JSONSchema Validator - Validates JavaScript objects using JSON Schemas
- * (http://www.json.com/json-schema-proposal/)
- *
- * Copyright (c) 2007 Kris Zyp SitePen (www.sitepen.com)
- * Licensed under the MIT (MIT-LICENSE.txt) license.
-To use the validator call JSONSchema.validate with an instance object and an optional schema object.
-If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
-that schema will be used to validate and the schema parameter is not necessary (if both exist,
-both validations will occur).
-The validate method will return an array of validation errors. If there are no errors, then an
-empty list will be returned. A validation error will have two properties:
-"property" which indicates which property had the error
-"message" which indicates what the error was
- */
-
-// setup primitive classes to be JSON Schema types
-String.type = "string";
-Boolean.type = "boolean";
-Number.type = "number";
-Integer = {type:"integer"};
-Object.type = "object";
-Array.type = "array";
-Date.type = "string";
-Date.format = "date-time";
-
-exports.validate = function(/*Any*/instance,/*Object*/schema) {
- // Summary:
- // To use the validator call JSONSchema.validate with an instance object and an optional schema object.
- // If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
- // that schema will be used to validate and the schema parameter is not necessary (if both exist,
- // both validations will occur).
- // The validate method will return an object with two properties:
- // valid: A boolean indicating if the instance is valid by the schema
- // errors: An array of validation errors. If there are no errors, then an
- // empty list will be returned. A validation error will have two properties:
- // property: which indicates which property had the error
- // message: which indicates what the error was
- //
- return validate(instance,schema,false);
- };
-exports.checkPropertyChange = function(/*Any*/value,/*Object*/schema, /*String*/ property) {
- // Summary:
- // The checkPropertyChange method will check to see if an value can legally be in property with the given schema
- // This is slightly different than the validate method in that it will fail if the schema is readonly and it will
- // not check for self-validation, it is assumed that the passed in value is already internally valid.
- // The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for
- // information.
- //
- return validate(value,schema, property || "property");
- };
-var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*Boolean*/ _changing) {
-
- var errors = [];
- // validate a value against a property definition
- function checkProp(value, schema, path,i){
- var l;
- path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i;
- function addError(message){
- errors.push({property:path,message:message});
- }
-
- if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function')){
- if(typeof schema == 'function'){
- if(!(value instanceof schema)){
- addError("is not an instance of the class/constructor " + schema.name);
- }
- }else if(schema){
- addError("Invalid schema/property definition " + schema);
- }
- return null;
- }
- if(_changing && schema.readonly){
- addError("is a readonly field, it can not be changed");
- }
- if(schema['extends']){ // if it extends another schema, it must pass that schema as well
- checkProp(value,schema['extends'],path,i);
- }
- // validate a value against a type definition
- function checkType(type,value){
- if(type){
- if(typeof type == 'string' && type != 'any' &&
- (type == 'null' ? value !== null : typeof value != type) &&
- !(value instanceof Array && type == 'array') &&
- !(type == 'integer' && value%1===0)){
- return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}];
- }
- if(type instanceof Array){
- var unionErrors=[];
- for(var j = 0; j < type.length; j++){ // a union type
- if(!(unionErrors=checkType(type[j],value)).length){
- break;
- }
- }
- if(unionErrors.length){
- return unionErrors;
- }
- }else if(typeof type == 'object'){
- var priorErrors = errors;
- errors = [];
- checkProp(value,type,path);
- var theseErrors = errors;
- errors = priorErrors;
- return theseErrors;
- }
- }
- return [];
- }
- if(value === undefined){
- if(!schema.optional){
- addError("is missing and it is not optional");
- }
- }else{
- errors = errors.concat(checkType(schema.type,value));
- if(schema.disallow && !checkType(schema.disallow,value).length){
- addError(" disallowed value was matched");
- }
- if(value !== null){
- if(value instanceof Array){
- if(schema.items){
- if(schema.items instanceof Array){
- for(i=0,l=value.length; i<l; i++){
- errors.concat(checkProp(value[i],schema.items[i],path,i));
- }
- }else{
- for(i=0,l=value.length; i<l; i++){
- errors.concat(checkProp(value[i],schema.items,path,i));
- }
- }
- }
- if(schema.minItems && value.length < schema.minItems){
- addError("There must be a minimum of " + schema.minItems + " in the array");
- }
- if(schema.maxItems && value.length > schema.maxItems){
- addError("There must be a maximum of " + schema.maxItems + " in the array");
- }
- }else if(schema.properties){
- errors.concat(checkObj(value,schema.properties,path,schema.additionalProperties));
- }
- if(schema.pattern && typeof value == 'string' && !value.match(schema.pattern)){
- addError("does not match the regex pattern " + schema.pattern);
- }
- if(schema.maxLength && typeof value == 'string' && value.length > schema.maxLength){
- addError("may only be " + schema.maxLength + " characters long");
- }
- if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){
- addError("must be at least " + schema.minLength + " characters long");
- }
- if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum &&
- schema.minimum > value){
- addError("must have a minimum value of " + schema.minimum);
- }
- if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum &&
- schema.maximum < value){
- addError("must have a maximum value of " + schema.maximum);
- }
- if(schema['enum']){
- var enumer = schema['enum'];
- l = enumer.length;
- var found;
- for(var j = 0; j < l; j++){
- if(enumer[j]===value){
- found=1;
- break;
- }
- }
- if(!found){
- addError("does not have a value in the enumeration " + enumer.join(", "));
- }
- }
- if(typeof schema.maxDecimal == 'number' &&
- (value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){
- addError("may only have " + schema.maxDecimal + " digits of decimal places");
- }
- }
- }
- return null;
- }
- // validate an object against a schema
- function checkObj(instance,objTypeDef,path,additionalProp){
-
- if(typeof objTypeDef =='object'){
- if(typeof instance != 'object' || instance instanceof Array){
- errors.push({property:path,message:"an object is required"});
- }
-
- for(var i in objTypeDef){
- if(objTypeDef.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
- var value = instance[i];
- var propDef = objTypeDef[i];
- checkProp(value,propDef,path,i);
- }
- }
- }
- for(i in instance){
- if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){
- errors.push({property:path,message:(typeof value) + "The property " + i +
- " is not defined in the schema and the schema does not allow additional properties"});
- }
- var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires;
- if(requires && !(requires in instance)){
- errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"});
- }
- value = instance[i];
- if(objTypeDef && typeof objTypeDef == 'object' && !(i in objTypeDef)){
- checkProp(value,additionalProp,path,i);
- }
- if(!_changing && value && value.$schema){
- errors = errors.concat(checkProp(value,value.$schema,path,i));
- }
- }
- return errors;
- }
- if(schema){
- checkProp(instance,schema,'',_changing || '');
- }
- if(!_changing && instance && instance.$schema){
- checkProp(instance,instance.$schema,'','');
- }
- return {valid:!errors.length,errors:errors};
-};
- /* will add this later
- newFromSchema : function() {
- }
-*/
-
View
16 package.json
@@ -0,0 +1,16 @@
+{
+ "name": "persevere",
+ "author": "Kris Zyp",
+ "dependencies": ["pintura"],
+ "contributors": [],
+ "keywords": [
+ "json",
+ "database",
+ "javascript",
+ "persistence",
+ "rest"
+ ],
+ "githubName": "persevere",
+ "type": "zip",
+ "location": "http://github.com/kriszyp/persevere/zipball/master"
+}
Please sign in to comment.
Something went wrong with that request. Please try again.