sql-js
Version:
SQL-like interface for JavaScript
136 lines (120 loc) • 4.54 kB
JavaScript
const query = (status= { data: [],}) => {
// INNER JOIN
const innerJoin = (a, b, f) => {
let m = a.length, n = b.length, c = [];
for (var i = 0; i < m; i++) {
const x = a[i];
for (var j = 0; j < n; j++) { // cartesian product - all combinations
let y;
if(f){
y = (f([x, b[j]])) ? [x,b[j]] : undefined;
}else{
y = [x,b[j]];
}
if (y) c.push(y); // if a row is returned add it to the table
}
}
return c;
}
const where = (fns, data) => {
// APPLY MULTIPLE WHERE CLASES WITH 'OR'
const whereOR = (fns, data) => {
let res = [];
fns.forEach(f => res = res.concat(data.filter(f).reverse()));
return res;
}
// APPLY MULTIPLE WHERE CLASES WITH 'OR'
const whereAND = (fns, data) => {
let res = [];
fns.forEach(f => res = data.filter(f));
status.whereLogic = 'OR';
return res;
}
return (status.whereLogic === 'AND') ? whereAND(fns,data) : whereOR(fns, data);
}
// GROUP DATASET BY ATTR
const groupBy = (fns, data) => {
// GROUP FUNCTION WHEN DATASET INST GROUPED
const group = (f, data) => {
if(!data) return [];
const groupArray = (f, data) => {
let groupsMap = {};
let groups = [];
data.forEach(d => {
if(groupsMap[f(d)]) {
groupsMap[f(d)].push(d)
} else {
groupsMap[f(d)] = [d];
}
});
Object.keys(groupsMap).forEach(groupName => {
let items = groupsMap[groupName];
if(!Number.isNaN(Number.parseInt(groupName))) groupName = Number.parseInt(groupName)
groups.push([groupName, items]);
});
return groups;
}
if(typeof data[0][0] != 'object' && typeof data[0][1] === 'object'){
return regroup(f,data);
}else{
return groupArray(f, data);
}
}
// GROUP FUNCTION WHEN DATASET IS ALREADY GROUPED
const regroup = (f, data) => {
for (var i = 0; i < data.length; i++) {
let g = data[i];
data[i][1] = group(f, g[1]);
}
return data;
}
fns.forEach(f => data = group(f, data));
return data;
}
return {
select: (f) => {
if(status.hasOwnProperty('select')) throw new Error('Duplicate SELECT');
status.select = f;
return query(status);
},
from: (...data) => {
if(status.hasOwnProperty('from')) throw new Error('Duplicate FROM');
status.from = data;
status.data = data;
return query(status);
},
where: (...f) => {
status.where = (status.where) ? status.where.concat(f) : f;
return query(status);
},
groupBy: (...f) => {
if(status.hasOwnProperty('groupBy')) throw new Error('Duplicate GROUPBY');
status.groupBy = f;
return query(status);
},
orderBy: (f) => {
if(status.hasOwnProperty('orderBy')) throw new Error('Duplicate ORDERBY');
status.orderBy = f;
return query(status);
},
having: (f) => {
status.having = f;
return query(status);
},
execute: () => {
if(status.data.length === 2){
status.data = (status.where) ? innerJoin(status.data[0], status.data[1], status.where[0]) : innerJoin(status.data[0], status.data[1]);
status.whereLogic = 'AND';
}else{
status.data = status.data[0] || [];
}
if(status.where) status.data = where(status.where, status.data);
if(status.groupBy) status.data = groupBy(status.groupBy, status.data);
if(status.having) status.data = status.data.filter(status.having);
if(status.select) status.data = status.data.map(status.select);
if(status.orderBy) status.data = status.data.sort(status.orderBy);
return status.data;
}
}
}
export default query;