SQLike={q:function(obj){
// Copyright: Thomas Frank 2010, v 1.021 (MIT style license, see EULA)
// variables
var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,obj2,d2,toSort,sortParas,ohaving,ot,coMax,co,labels,
xLen,whereIndexes,distinct,distinctHash,ags,fieldCo,lastProp,distinctKey,pname,pname2,theVal,ag_type,
agsCo,uu,orgD,o2,o3,intoAr,owhere,ewhere,setop,t1,t2,t1name,t2name,func,fh,tc,f2,lex,setopFuncHolder,joinFuncHolder;
// The strange "funcHolder" vars fixes eluding AS2-bug where a function defined in a if clause is not readily available...
// (could have been rewritten with var x = function, but this wouldn't have worked in AS3)
// handle multiple commands/inparameters
if (arguments.length>1){
a = arguments, r = uu;
for(i=0;i<a.length;i++){
r = arguments.callee(a[i])
};
return r
};
// o - new object with all the props in uppercase, without underscore
o = {};
for(i in obj){o[i.toUpperCase().split("_").join("")] = obj[i]};
// check that we have ONE basic query type
if (o.DELETE && o.FROM){o.DELETEFROM = o.FROM};
setop =!!o.UNIONDISTINCT+!!o.UNION+!!o.UNIONALL+!!o.INTERSECTDISTINCT+!!o.INTERSECT+
!!o.INTERSECTALL+!!o.MINUS+!!o.EXCEPTDISTINCT+!!o.EXCEPT+!!o.EXCEPTALL;
if (setop+!!o.SELECT+!!o.SELECTDISTINCT+!!o.INSERTINTO+!!o.UPDATE+!!o.DELETEFROM+!!o.UNPACK+!!o.PACK!= 1){return []}
else if (o.TESTSUB){return "issub"};
// d - our data provider (an array of objects)
d = (o.SELECT || o.SELECTDISTINCT) ? o.FROM : o.INSERTINTO || o.UPDATE || o.DELETEFROM || o.PACK || o.UNPACK, orgD = d;
// test if d is a subquery and if so perform it
if(d && typeof d=="object" && !d.push){
o2={TESTSUB:true};
for(i in d){o2[i]=d[i]};
if(arguments.callee(o2)=="issub"){d=arguments.callee(d)}
};
// LIMIT
if (o.LIMIT){
x=o.LIMIT;
o.LIMIT=uu;
return arguments.callee(o).slice(0,x)
};
// INTO
if(o.INTO && o.INTO.push){
intoAr=o.INTO;
o.INTO=uu;
intoAr.splice.apply(intoAr,[intoAr.length,0].concat(arguments.callee(o)));
return intoAr
};
// INSERT INTO
if (o.INSERTINTO){
d.push(o.VALUES);
return d
};
// UNION, INTERSECT, EXCEPT, MINUS (set operations)
if(setop){
setopFuncHolder = {f:function(o,a){
var x=[], All, Type, dr=[], f={}, f2={}, h={}, k, o, hkey, hash={},testHash, testHashCo, mfd=[],
d=o.UNIONDISTINCT||o.UNION||o.UNIONALL||o.INTERSECTDISTINCT||o.INTERSECT||
o.INTERSECTALL||o.MINUS||o.EXCEPTDISTINCT||o.EXCEPT||o.EXCEPTALL, lex=d.length;
// determine query type
for(var z in o){
if(o[z]===d){
var j=z.toUpperCase();
All=j.split("ALL").length>1;
Type=j.split("UNION").length>1?1:j.split("INTERSECT").length>1?2:3;
if(j=="MINUS"){Type=3;All=false}
}
};
// perform subqueries
for(var i=0;i<d.length;i++){dr.push(a(d[i]))};
// determine shared fieldnames
for(i=0;i<lex;i++){for(j in dr[i][0]){if(!f[j]){f[j]=0};f[j]++}};
for(i in f){if(f[i]==lex){f2[i]=true}};
// concatenate tables and build hash info
for(i=0;i<lex;i++){
for(j=0;j<dr[i].length;j++){
o={}, hkey=[];
for(k in f2){o[k]=dr[i][j][k];hkey.push(dr[i][j][k])};
hkey=hkey.join("|||");
x.push(o);
if(!hash[hkey]){hash[hkey]=[]};
hash[hkey].push({indexNo:x.length-1,tableNo:'t'+i})
}
};
// just return if UNIONALL
if(Type==1 && All){return x};
// mark tuples for deletion depending on query type
for(i in hash){
testHash={},testHashCo=0;
for(j=0;j<hash[i].length;j++){testHash[hash[i][j].tableNo]=true};
for(j in testHash){testHashCo++};
for(j=0;j<hash[i].length;j++){
if(
(Type==2 && testHashCo!=lex) ||
(Type==3 && (testHashCo!=1 || testHash.t1)) ||
(!All && j>0)
){
mfd[hash[i][j].indexNo]=true
}
}
};
// delete tuples
for(i=x.length-1;i>=0;i--){
if(mfd[i]){x.splice(i,1)}
};
return x
}};
return setopFuncHolder.f(o,arguments.callee)
};
// UNPACK - from array of arrays to array of objects
if (o.UNPACK){
c=o.COLUMNS
if(!c){return false};
for(i=0;i<d.length;i++){
o = {};
for(j=0;j<c.length;j++){
o[c[j]] = d[i][j];
};
d[i] = o;
};
return d
};
// PACK - from array of objects to array of arrays
if (o.PACK){
if(!o.COLUMNS){
o.COLUMNS = [];
for (i in d[0]){o.COLUMNS.push(i)}
};
c = o.COLUMNS;
for(i=0;i<d.length;i++){
a = [];
for(j=0;j<c.length;j++){
a[j] = d[i][c[j]];
};
d[i] = a;
};
return d
};
// ORDER BY
if (o.ORDERBY && !o.ORDERBY.prep){
o.ORDERBY.prep=true;
x=arguments.callee(o), toSort=[];
if(o.GROUPBY){x=[x,x]};
// build toSort from selected x[0] and unselected x[1] fields
for(i=0;i<x[0].length;i++){
a={}, co=0;
for(j in x[0][i]){co++;a[j]=x[0][i][j]};
for(j in x[1][i]){co++
if(a[j]===uu){a[j]=x[1][i][j]}
};
a.__sqLikeSelectedData=x[0][i];
toSort.push(a)
};
// check asc/desc
sortParas = {a:[],d:[]}, a = o.ORDERBY||[], f;
x = sortParas;
for(i=0;i<a.length;i++){
if(a[i]=="|desc|" || a[i]=="|asc|"){continue};
x.d.push(a[i+1]=="|desc|"?-1:1)
x.a.push(a[i])
};
// sort
toSort.sort(function(x,y){
a=sortParas.a;
d=sortParas.d;
r=0;
for(i=0;i<a.length;i++){
if(typeof x+typeof y!="objectobject"){return typeof x=="object"?-1:1};
m,n;
if(typeof a[i]=="function"){
m=a[i].apply(x);
n=a[i].apply(y)
}
else {
m=x[a[i]]; n=y[a[i]]
};
if((m===true || m===false) && (n===true || n===false)){m*=-1;n*=-1};
r=m-n;
if(isNaN(r)){r= m>n?1:m<n?-1:0};
if(r!=0){return r*d[i]}
};
return r
});
// retrieve selected fields
r=[];
for(i=0;i<toSort.length;i++){
r.push(toSort[i].__sqLikeSelectedData)
};
return r
};
// HAVING
if(o.HAVING){
ohaving=o.HAVING;
o.HAVING=uu;
x=arguments.callee(o);
r = arguments.callee(
{
SELECT:['*'],
FROM:x,
WHERE:ohaving
}
);
return r
};
// GROUP BY
if(o.GROUPBY){
t=[], q = {
SELECTDISTINCT:o.GROUPBY,
FROM:o.FROM,
WHERE:o.WHERE
};
g=arguments.callee(q);
for(i=0;i<g.length;i++){
q={};
for(j in o){q[j]=o[j]};
q.GROUPBY=q.ORDERBY=uu;
owhere = o.WHERE || function(){return true};
ewhere = g[i];
q.WHERE=function(){
var x=owhere.apply(this);
for(var i in ewhere){
x=x && this[i]==ewhere[i]
};
return x
};
t.push(arguments.callee(q)[0])
};
return t
};
// JOIN - convert all types of joins to where clauses + outer flags
o.JOIN=o.JOIN||o.INNERJOIN||o.NATURALJOIN||o.CROSSJOIN||o.LEFTOUTERJOIN||o.RIGHTOUTERJOIN||
o.LEFTJOIN||o.RIGHTJOIN||o.FULLOUTERJOIN||o.OUTERJOIN||o.FULLJOIN;
if(o.NATURALJOIN || o.USING){
// optimize by building a hash for equijoin thereby omitting loops in the on clause for 2-3 table joins
// ugly code block but saves som milliseconds, before this "naturaljoin" and "join using"
// were really slow, now they're almost on par with other types of joins
for(j in o.JOIN){if(!d[j]){d[j]=o.JOIN[j]}};
f={}, f2=[], lex=0;
for(i in d){lex++;for(j in d[i][0]){if(!f[j]){f[j]=0};f[j]++}};
for(i in f){if(f[i]==lex){f2.push(i)}};
o.USING=o.USING||f2, b={};
for(i=0;i<o.USING.length;i++){b[o.USING[i]]=true};
for(i in d){
x=d[i];
d[i]=[];
for(k=0;k<x.length;k++){
o2={}, h=[];
for(j in x[k]){o2[j]=x[k][j]};
for(j=0;j<o.USING.length;j++){h.push(x[k][o.USING[j]])};
o2.__SQLikeHash__=h.join('|');
d[i][k]=o2
}
};
o.ON=function(){
var a=arguments.callee;
if(a.LEN==2){
return this[a.TABLELABEL[0]].__SQLikeHash__==
this[a.TABLELABEL[1]].__SQLikeHash__?a.USINGOBJ:false
};
if(a.LEN==3){
return this[a.TABLELABEL[0]].__SQLikeHash__==
this[a.TABLELABEL[1]].__SQLikeHash__ &&
this[a.TABLELABEL[0]].__SQLikeHash__==
this[a.TABLELABEL[2]].__SQLikeHash__?a.USINGOBJ:false
};
var x=this[a.TABLELABEL[0]].__SQLikeHash__
for(var i in this){if(this[i].__SQLikeHash__!=x){return false}};
return a.USINGOBJ
};
o.ON.TABLELABEL=[];
for(i in d){o.ON.TABLELABEL.push(i)};
o.ON.USINGOBJ=b;
o.ON.LEN=lex;
o.NATURALJOIN=o.USING=uu
};
if(o.CROSSJOIN){
o.ON=function(){return true};
o.CROSSJOIN=false
};
if (o.JOIN && o.ON && !d.join && !o.JOIN.join){
for(j in o.JOIN){if(!d[j]){d[j]=o.JOIN[j]}};
ot={},k;
for(j in d){
if(o.FULLOUTERJOIN || o.FULLJOIN || o.OUTERJOIN){k=true;ot[j]=true};
if((o.LEFTOUTERJOIN || o.LEFTJOIN) && !o.JOIN[j]){k=true;ot[j]=true};
if((o.RIGHTOUTERJOIN || o.RIGHTJOIN) && o.JOIN[j]){k=true;ot[j]=true};
};
o.OUTERTABLES=k?ot:false;
f=o.WHERE||function(){return true};
o.WHERE=o.ON;
o.WHERE.org=f;
o.JOIN=o.INNERJOIN=o.NATURALJOIN=o.CROSSJOIN=o.LEFTOUTERJOIN=o.RIGHTOUTERJOIN=o.LEFTJOIN=
o.RIGHTJOIN=o.FULLOUTERJOIN=o.OUTERJOIN=o.FULLJOIN=o.ON=uu;
return arguments.callee(o)
};
// JOIN (from WHERE clause)
if (!d.join) {
joinFuncHolder={f:function (x,where,outer){
var d=[], e=[], coMax=[], co=[], labels=[], xLen=0, m=[];
for(i in x){
coMax.push(x[i].length);
labels.push(i);
m.push([]);
co.push(0);
xLen++
};
while(co[xLen-1]<coMax[xLen-1]){
var o={};
for(i=0;i<xLen;i++){
o[labels[i]]=x[labels[i]][co[i]];
};
q=where.apply(o);
if(q){
if(outer){
for(i=0;i<xLen;i++){
m[i][co[i]]=true
}
};
obj={};
for(i=0;i<xLen;i++){
for(j in o[labels[i]]){
if(j=="__SQLikeHash__"){continue};
obj[(typeof q=="object" && q[j]?'':labels[i]+'_')+j]=o[labels[i]][j]
}
};
d.push(obj);
e.push(o);
};
for(i=0;i<xLen;i++){
co[i]++;
if(co[i]<coMax[i]){break};
if(i<xLen-1){co[i]=0}
};
};
if(outer){
for(i=0;i<xLen;i++){
if(!outer[labels[i]]){continue};
for(j=0;j<coMax[i];j++){
if(!m[i][j]){
o=x[labels[i]][j],o2={},o3={};
for(k=0;k<xLen;k++){o3[labels[k]]={}};
for(k in o){o3[labels[i]][k]=o[k];o2[labels[i]+"_"+k]=o[k]};
d.push(o2);
e.push(o3)
}
}
}
};
if(where.org){
for(i=d.length-1;i>=0;i--){
if(!where.org.apply(e[i])){d.splice(i,1)}
}
};
return d
}};
d=joinFuncHolder.f(d,o.WHERE,o.OUTERTABLES)
}
// WHERE
else {
d2 = [], whereIndexes=[];
for(i=0;i<d.length;i++){
if (!o.WHERE || o.WHERE.apply(d[i])){
d2.push(d[i]);
whereIndexes.push(i)
}
};
d = d2;
};
// DELETE
if (o.DELETEFROM){
for(i=whereIndexes.length-1;i>=0;i--){
orgD.splice(whereIndexes[i],1)
}
return orgD
};
// UPDATE
if (o.UPDATE && o.SET){
for(i=0;i<=whereIndexes.length;i++){
o.SET.apply(orgD[whereIndexes[i]])
}
return orgD
};
// SELECT
distinct=!!o.SELECTDISTINCT;
o.SELECT=o.SELECT||o.SELECTDISTINCT;
if (o.SELECT && o.SELECT.length>0){
d2 = [], distinctHash={}, ags={}, fieldCo=0, s=o.SELECT;
if (s[0]=="|count|" && s[1]=="*"){
return [{count:d.length}]
};
for(i=0;i<s.length;i++){
if(s[i]=="*"){
h={}, t=[];
for(k=0;k<d.length;k++){for(j in d[k]){if(!h[j]){t.push(j);h[j]=true}}};
s.splice(i,1);
for(j=t.length-1;j>=0;j--){s.splice(i,0,t[j])}
break
}
};
for(i=0;i<d.length;i++){
lastProp, obj = {}, distinctKey;
for (j=0;j<s.length;j++){
pname=s[j], pname2 = pname, theVal = d[i][pname2];
if (typeof s[j]=="string" && s[j].toLowerCase()=="|as|"){j+=1;continue};
if (typeof s[j]=="string" && s[j].charAt(0)=="|" && s[j].charAt(s[j].length-1)=="|"){continue};
if (typeof pname == "function"){
theVal = pname.apply(d[i]);
co=1;
pname="udf_1";
while(obj[pname]){co++;pname="udf_"+co}
};
if (typeof s[j+1]=="string" && typeof s[j+2]=="string" && s[j+1].toLowerCase()=="|as|"){
pname=s[j+2]
};
if (typeof s[j-1]=="string" && s[j-1].charAt(0)=="|" && s[j-1].charAt(s[j-1].length-1)=="|"){
ag_type=s[j-1].split('|')[1];
pname=ag_type+'_'+pname;
ags[pname]={type:ag_type,count:0,sum:0,avg:0}
};
if(o.JHELP && !o.JHELP[pname]){pname=o.JTNAME+pname};
lastProp = pname;
obj[pname] = theVal
if(i==0){fieldCo++};
};
if(distinct){x=[];for(k in obj){x.push(obj[k])};distinctKey=x.join('|||')};
if(!distinct || !distinctHash[distinctKey]){
d2.push(obj)
};
if(distinct){distinctHash[distinctKey]=true};
};
// aggregate functions
agsCo=0;
for(i in ags){
agsCo++;
y=ags[i];
for(j=0;j<d2.length;j++){
x=d2[j][i];
if(x!==uu){
y.count++;
if(y.min===uu){y.min=x};
if(y.max===uu){y.max=x};
if(y.min>x){y.min=x};
if(y.max<x){y.max=x};
if(x/1==x){y.sum+=x}
}
};
y.avg=y.sum/y.count;
d2[0][i]=ags[i][ags[i].type]
};
if(agsCo>0){d2=[d2[0]];d=[d2[0]]};
if(o.ORDERBY && o.ORDERBY.prep){return [d2,d]};
return d2
};
return []
}
};