Skip to content

Commit

Permalink
Support the "total" aggregator to fix #1530
Browse files Browse the repository at this point in the history
  • Loading branch information
gangadhargo authored Jan 2, 2023
1 parent 5b8054a commit b8c7bd5
Show file tree
Hide file tree
Showing 9 changed files with 650 additions and 558 deletions.
6 changes: 5 additions & 1 deletion src/38query.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ function queryfn3(query) {
if (query.selectGroup.length > 0) {
// console.log(query.selectGroup);
query.selectGroup.forEach(function (sg) {
if (sg.aggregatorid == 'COUNT' || sg.aggregatorid == 'SUM') {
if (
sg.aggregatorid == 'COUNT' ||
sg.aggregatorid == 'SUM' ||
sg.aggregatorid == 'TOTAL'
) {
g[sg.nick] = 0;
} else {
g[sg.nick] = undefined;
Expand Down
64 changes: 49 additions & 15 deletions src/423groupby.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,31 @@ if(false) {
// if(col instanceof yy.Column) colas = col.columnid;
// else colas = col.toString();
// };
let colExpIfFunIdExists = (expression) => {
let colexpression = expression.args[0];
return colexpression.toJS('p', tableid, defcols);
};
if (col instanceof yy.AggrValue) {
if (col.distinct) {
aft +=
",g['$$_VALUES_" + colas + "']={},g['$$_VALUES_" + colas + "'][" + colexp + ']=true';
}
if (col.aggregatorid === 'SUM') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return `'${colas}':(${colexp1})|| typeof ${colexp1} == 'number' ? ${colexp1} : null,`;
}
return `'${colas}':(${colexp})|| typeof ${colexp} == 'number' ? ${colexp} : null,`;
} else if (col.aggregatorid === 'TOTAL') {
if ('funcid' in col.expression) {
let colexp1 = colExpIfFunIdExists(col.expression);
return `'${colas}':(${colexp1}) || typeof ${colexp1} == 'number' ?
${colexp1} : ${colexp1} == 'string' && typeof Number(${colexp1}) == 'number' ? Number(${colexp1}) :
typeof ${colexp1} == 'boolean' ? Number(${colexp1}) : 0,`;
}
return `'${colas}':(${colexp})|| typeof ${colexp} == 'number' ?
${colexp} : ${colexp} == 'string' && typeof Number(${colexp}) == 'number' ? Number(${colexp}) :
typeof ${colexp} === 'boolean' ? Number(${colexp}) : 0,`;
} else if (
col.aggregatorid === 'FIRST' ||
col.aggregatorid === 'LAST'
Expand All @@ -163,17 +176,15 @@ if(false) {
return "'" + colas + "':" + colexp + ','; //f.field.arguments[0].toJS();
} else if (col.aggregatorid === 'MIN') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return `'${colas}': (typeof ${colexp1} == 'number' ? ${colexp1} : typeof ${colexp1} == 'object' ?
typeof Number(${colexp1}) == 'number' && ${colexp1}!== null? ${colexp1} : null : null),`;
}
return `'${colas}': (typeof ${colexp} == 'number' ? ${colexp} : typeof ${colexp} == 'object' ?
typeof Number(${colexp}) == 'number' && ${colexp}!== null? ${colexp} : null : null),`;
} else if (col.aggregatorid === 'MAX') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return `'${colas}' : (typeof ${colexp1} == 'number' ? ${colexp1} : typeof ${colexp1} == 'object' ?
typeof Number(${colexp1}) == 'number' ? ${colexp1} : null : null),`;
}
Expand Down Expand Up @@ -308,7 +319,10 @@ if(false) {
// }
*/
var colexp = col.expression.toJS('p', tableid, defcols);

let colExpIfFunIdExists = (expression) => {
let colexpression = expression.args[0];
return colexpression.toJS('p', tableid, defcols);
};
if (col instanceof yy.AggrValue) {
var pre = '',
post = '';
Expand All @@ -325,11 +339,10 @@ if(false) {
}
if (col.aggregatorid === 'SUM') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return (
pre +
`if(g['${colas}'] == null && ${colexp1} == null){g['${colas}'] = null}
`if(g['${colas}'] == null && ${colexp1} == null){g['${colas}'] = null}
else if(typeof g['${colas}']!== 'object' && typeof g['${colas}']!== 'number' && typeof ${colexp1}!== 'object' && typeof ${colexp1}!== 'number'){g['${colas}'] = null}
else if(typeof g['${colas}']!== 'object' && typeof g['${colas}']!== 'number' && typeof ${colexp1} == 'number'){g['${colas}'] = ${colexp1}}
else if(typeof g['${colas}']!== 'number' && typeof ${colexp1}!== 'number' && typeof ${colexp1}!== 'object'){g['${colas}'] = g['${colas}']}
Expand All @@ -352,7 +365,29 @@ if(false) {
else{g['${colas}'] += ${colexp}||0}` +
post
);
} else if (col.aggregatorid === 'COUNT') {
} else if (col.aggregatorid === 'TOTAL') {
if ('funcid' in col.expression) {
let colexp1 = colExpIfFunIdExists(col.expression);
return (
pre +
`if(typeof g['${colas}'] == 'string' && !isNaN(g['${colas}']) && typeof Number(g['${colas}']) == 'number' &&
typeof ${colexp1} == 'string' && !isNaN(${colexp1}) && typeof Number(${colexp1}) == 'number'){g['${colas}'] = Number(g['${colas}']) + Number(${colexp1})}
else if(typeof g['${colas}'] == 'string' && typeof ${colexp1} == 'string'){g['${colas}'] = 0}
else if(typeof g['${colas}'] == 'string' && typeof ${colexp1} == 'number'){g['${colas}'] = ${colexp1}}
else if(typeof ${colexp1} == 'string' && typeof g['${colas}'] == 'number'){g['${colas}'] = g['${colas}']}
else{g['${colas}'] += ${colexp1}||0}`
+ post
);
}
return pre +
`if(typeof g['${colas}'] == 'string' && !isNaN(g['${colas}']) && typeof Number(g['${colas}']) == 'number' &&
typeof ${colexp} == 'string' && !isNaN(${colexp}) && typeof Number(${colexp}) == 'number'){g['${colas}'] = Number(g['${colas}']) + Number(${colexp})}
else if(typeof g['${colas}'] == 'string' && typeof ${colexp} == 'string'){g['${colas}'] = 0}
else if(typeof g['${colas}'] == 'string' && typeof ${colexp} == 'number'){g['${colas}'] = ${colexp}}
else if(typeof ${colexp} == 'string' && typeof g['${colas}'] == 'number'){g['${colas}'] = g['${colas}']}
else{g['${colas}'] += ${colexp}||0}`
+ post
}else if (col.aggregatorid === 'COUNT') {
// console.log(221,col.expression.columnid == '*');
if (col.expression.columnid === '*') {
return pre + "g['" + colas + "']++;" + post;
Expand All @@ -373,8 +408,7 @@ if(false) {
return pre + "g['" + colas + "'].push(" + colexp + ');' + post;
} else if (col.aggregatorid === 'MIN') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return (
pre +
`if((g['${colas}'] == null && ${colexp1}!== null) ? y = ${colexp1} : (g['${colas}']!== null &&
Expand All @@ -398,8 +432,7 @@ if(false) {
);
} else if (col.aggregatorid === 'MAX') {
if ('funcid' in col.expression) {
let colexpression = col.expression.args[0];
let colexp1 = colexpression.toJS('p', tableid, defcols);
let colexp1 = colExpIfFunIdExists(col.expression);
return (
pre +
`if((y=${colexp1}) > g['${colas}']){if(typeof y == 'number'){g['${colas}'] = y;}
Expand Down Expand Up @@ -482,6 +515,7 @@ if(false) {

// s += ' group.amt += rec.emplid;';
// s += 'group.count++;';
//console.log(JSON.stringify(s));
s += '}';
});

Expand Down
5 changes: 2 additions & 3 deletions src/424select.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ yy.Select.prototype.compileSelect1 = function (query, params) {
//console.log(42,87,this.columns);

this.columns.forEach(function (col) {
//console.log(col);
if (col instanceof yy.Column) {
if (col.columnid === '*') {
if (col.func) {
Expand Down Expand Up @@ -291,7 +290,8 @@ yy.Select.prototype.compileSelect1 = function (query, params) {
col.aggregatorid === 'LAST' ||
col.aggregatorid === 'AVG' ||
col.aggregatorid === 'ARRAY' ||
col.aggregatorid === 'REDUCE'
col.aggregatorid === 'REDUCE' ||
col.aggregatorid === 'TOTAL'
) {
ss.push(
"'" +
Expand Down Expand Up @@ -366,7 +366,6 @@ yy.Select.prototype.compileSelect2 = function (query, params) {
query.removeKeys.push(key);
});
}

return new Function('p,params,alasql', 'var y;' + s + 'return r');
};

Expand Down
2 changes: 1 addition & 1 deletion src/427pivot.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ yy.Select.prototype.compilePivot = function (query) {
newcols.push(d[columnid]);
}

if (aggr == 'SUM' || aggr == 'AVG') {
if (aggr == 'SUM' || aggr == 'AVG' || aggr == 'TOTAL') {
if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = 0;
g[d[columnid]] += +d[exprcolid];
} else if (aggr == 'COUNT') {
Expand Down
2 changes: 1 addition & 1 deletion src/50expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@

toType() {
if (
['SUM', 'COUNT', 'AVG', 'MIN', 'MAX', 'AGGR', 'VAR', 'STDDEV'].indexOf(this.aggregatorid) >
['SUM', 'COUNT', 'AVG', 'MIN', 'MAX', 'AGGR', 'VAR', 'STDDEV', 'TOTAL'].indexOf(this.aggregatorid) >
-1
) {
return 'number';
Expand Down
3 changes: 2 additions & 1 deletion src/alasqlparser.jison
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ SETS return 'SET'
'STRATEGY' return 'STRATEGY'
'STORE' return 'STORE'
'SUM' return 'SUM'
'TOTAL' return 'TOTAL'
'TABLE' return 'TABLE'
'TABLES' return 'TABLE'
'TARGET' return 'TARGET'
Expand Down Expand Up @@ -318,7 +319,6 @@ SETS return 'SET'
'~' return 'TILDA'

[0-9]*[a-zA-Z_]+[a-zA-Z_0-9]* return 'LITERAL'

<<EOF>> return 'EOF'
. return 'INVALID'

Expand Down Expand Up @@ -1355,6 +1355,7 @@ OverOrderByClause
;
Aggregator
: SUM { $$ = "SUM"; }
| TOTAL { $$ = "TOTAL"; }
| COUNT { $$ = "COUNT"; }
| MIN { $$ = "MIN"; }
| MAX { $$ = "MAX"; }
Expand Down
957 changes: 481 additions & 476 deletions src/alasqlparser.js

Large diffs are not rendered by default.

120 changes: 60 additions & 60 deletions test/test229.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,26 @@ describe('Test 229 Calculating simple running totals', function () {
var res = alasql(
'SELECT a.id, a.[value], (SELECT SUM(b.[value]) \
FROM RunTotalTestData b \
WHERE b.id <= a.id) AS total \
WHERE b.id <= a.id) AS c \
FROM RunTotalTestData a \
ORDER BY a.id;'
);
// console.log(res);
assert.deepEqual(res, [
{id: 1, value: 1, total: 1},
{id: 2, value: 2, total: 3},
{id: 3, value: 4, total: 7},
{id: 4, value: 7, total: 14},
{id: 5, value: 9, total: 23},
{id: 6, value: 12, total: 35},
{id: 7, value: 13, total: 48},
{id: 8, value: 16, total: 64},
{id: 9, value: 22, total: 86},
{id: 10, value: 42, total: 128},
{id: 11, value: 57, total: 185},
{id: 12, value: 58, total: 243},
{id: 13, value: 59, total: 302},
{id: 14, value: 60, total: 362},
{id: 1, value: 1, c: 1},
{id: 2, value: 2, c: 3},
{id: 3, value: 4, c: 7},
{id: 4, value: 7, c: 14},
{id: 5, value: 9, c: 23},
{id: 6, value: 12, c: 35},
{id: 7, value: 13, c: 48},
{id: 8, value: 16, c: 64},
{id: 9, value: 22, c: 86},
{id: 10, value: 42, c: 128},
{id: 11, value: 57, c: 185},
{id: 12, value: 58, c: 243},
{id: 13, value: 59, c: 302},
{id: 14, value: 60, c: 362},
]);
//};

Expand All @@ -67,28 +67,28 @@ describe('Test 229 Calculating simple running totals', function () {

it('3. Select accumulated sum', function (done) {
var res = alasql(
'SELECT a.id, a.[value], SUM(b.[value]) AS total \
'SELECT a.id, a.[value], SUM(b.[value]) AS c \
FROM RunTotalTestData a, \
RunTotalTestData b \
WHERE b.id <= a.id \
GROUP BY a.id, a.[value] \
ORDER BY a.id'
);
assert.deepEqual(res, [
{id: 1, value: 1, total: 1},
{id: 2, value: 2, total: 3},
{id: 3, value: 4, total: 7},
{id: 4, value: 7, total: 14},
{id: 5, value: 9, total: 23},
{id: 6, value: 12, total: 35},
{id: 7, value: 13, total: 48},
{id: 8, value: 16, total: 64},
{id: 9, value: 22, total: 86},
{id: 10, value: 42, total: 128},
{id: 11, value: 57, total: 185},
{id: 12, value: 58, total: 243},
{id: 13, value: 59, total: 302},
{id: 14, value: 60, total: 362},
{id: 1, value: 1, c: 1},
{id: 2, value: 2, c: 3},
{id: 3, value: 4, c: 7},
{id: 4, value: 7, c: 14},
{id: 5, value: 9, c: 23},
{id: 6, value: 12, c: 35},
{id: 7, value: 13, c: 48},
{id: 8, value: 16, c: 64},
{id: 9, value: 22, c: 86},
{id: 10, value: 42, c: 128},
{id: 11, value: 57, c: 185},
{id: 12, value: 58, c: 243},
{id: 13, value: 59, c: 302},
{id: 14, value: 60, c: 362},
]);

done();
Expand Down Expand Up @@ -147,26 +147,26 @@ ORDER BY a.id;'
'SELECT a.[value]%2 as even, a.id, a.[value], (SELECT SUM(b.[value]) \
FROM RunTotalTestData b \
WHERE b.id <= a.id \
AND b.[value]%2 = a.[value]%2) as total \
AND b.[value]%2 = a.[value]%2) as c \
FROM RunTotalTestData a \
ORDER BY [value]%2, a.id;'
);

assert.deepEqual(res, [
{even: 0, id: 2, value: 2, total: 2},
{even: 0, id: 3, value: 4, total: 6},
{even: 0, id: 6, value: 12, total: 18},
{even: 0, id: 8, value: 16, total: 34},
{even: 0, id: 9, value: 22, total: 56},
{even: 0, id: 10, value: 42, total: 98},
{even: 0, id: 12, value: 58, total: 156},
{even: 0, id: 14, value: 60, total: 216},
{even: 1, id: 1, value: 1, total: 1},
{even: 1, id: 4, value: 7, total: 8},
{even: 1, id: 5, value: 9, total: 17},
{even: 1, id: 7, value: 13, total: 30},
{even: 1, id: 11, value: 57, total: 87},
{even: 1, id: 13, value: 59, total: 146},
{even: 0, id: 2, value: 2, c: 2},
{even: 0, id: 3, value: 4, c: 6},
{even: 0, id: 6, value: 12, c: 18},
{even: 0, id: 8, value: 16, c: 34},
{even: 0, id: 9, value: 22, c: 56},
{even: 0, id: 10, value: 42, c: 98},
{even: 0, id: 12, value: 58, c: 156},
{even: 0, id: 14, value: 60, c: 216},
{even: 1, id: 1, value: 1, c: 1},
{even: 1, id: 4, value: 7, c: 8},
{even: 1, id: 5, value: 9, c: 17},
{even: 1, id: 7, value: 13, c: 30},
{even: 1, id: 11, value: 57, c: 87},
{even: 1, id: 13, value: 59, c: 146},
]);

done();
Expand All @@ -178,7 +178,7 @@ ORDER BY [value]%2, a.id;'
};

var res = alasql(
'SELECT [value]%2 AS even, id, [value], SUM(b.[value]) AS total \
'SELECT [value]%2 AS even, id, [value], SUM(b.[value]) AS c \
FROM RunTotalTestData a, \
RunTotalTestData b \
WHERE a.[value]%2 = b.[value]%2 \
Expand All @@ -188,20 +188,20 @@ ORDER BY [value]%2, a.id;'
);

assert.deepEqual(res, [
{even: 0, id: 2, value: 2, total: 2},
{even: 0, id: 3, value: 4, total: 6},
{even: 0, id: 6, value: 12, total: 18},
{even: 0, id: 8, value: 16, total: 34},
{even: 0, id: 9, value: 22, total: 56},
{even: 0, id: 10, value: 42, total: 98},
{even: 0, id: 12, value: 58, total: 156},
{even: 0, id: 14, value: 60, total: 216},
{even: 1, id: 1, value: 1, total: 1},
{even: 1, id: 4, value: 7, total: 8},
{even: 1, id: 5, value: 9, total: 17},
{even: 1, id: 7, value: 13, total: 30},
{even: 1, id: 11, value: 57, total: 87},
{even: 1, id: 13, value: 59, total: 146},
{even: 0, id: 2, value: 2, c: 2},
{even: 0, id: 3, value: 4, c: 6},
{even: 0, id: 6, value: 12, c: 18},
{even: 0, id: 8, value: 16, c: 34},
{even: 0, id: 9, value: 22, c: 56},
{even: 0, id: 10, value: 42, c: 98},
{even: 0, id: 12, value: 58, c: 156},
{even: 0, id: 14, value: 60, c: 216},
{even: 1, id: 1, value: 1, c: 1},
{even: 1, id: 4, value: 7, c: 8},
{even: 1, id: 5, value: 9, c: 17},
{even: 1, id: 7, value: 13, c: 30},
{even: 1, id: 11, value: 57, c: 87},
{even: 1, id: 13, value: 59, c: 146},
]);

done();
Expand Down
Loading

0 comments on commit b8c7bd5

Please sign in to comment.