2018-10-23 23:45:42 +08:00
|
|
|
'use strict';
|
|
|
|
|
2016-05-31 21:30:38 +08:00
|
|
|
var BaseOverviewsDataview = require('./base');
|
2016-05-14 00:46:58 +08:00
|
|
|
var BaseDataview = require('../formula');
|
2017-06-15 22:31:24 +08:00
|
|
|
var debug = require('debug')('windshaft:widget:formula:overview');
|
2017-11-29 19:33:41 +08:00
|
|
|
const utils = require('../../../utils/query-utils');
|
2016-05-14 00:46:58 +08:00
|
|
|
|
|
|
|
var dot = require('dot');
|
|
|
|
dot.templateSettings.strip = false;
|
|
|
|
|
2017-11-29 19:33:41 +08:00
|
|
|
const VALID_OPERATIONS = {
|
|
|
|
count: true,
|
|
|
|
sum: true,
|
|
|
|
avg: true
|
2016-05-14 00:46:58 +08:00
|
|
|
};
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
/** Formulae to calculate the end result using _feature_count from the overview table */
|
|
|
|
function dataviewResult (ctx) {
|
2017-11-29 19:33:41 +08:00
|
|
|
switch (ctx.operation) {
|
2019-10-22 01:07:24 +08:00
|
|
|
case 'count':
|
|
|
|
return 'sum(_feature_count)';
|
|
|
|
case 'sum':
|
|
|
|
return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)`;
|
|
|
|
case 'avg':
|
|
|
|
return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)/sum(_feature_count) `;
|
2017-11-29 19:33:41 +08:00
|
|
|
}
|
|
|
|
return `${ctx.operation}(${utils.handleFloatColumn(ctx)})`;
|
|
|
|
}
|
|
|
|
|
|
|
|
const formulaQueryTpl = ctx =>
|
2019-10-22 01:07:24 +08:00
|
|
|
`SELECT
|
2017-11-29 19:33:41 +08:00
|
|
|
${dataviewResult(ctx)} AS result,
|
|
|
|
${utils.countNULLs(ctx)} AS nulls_count
|
2019-10-22 01:07:24 +08:00
|
|
|
${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ''}
|
|
|
|
${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ''}
|
2017-11-29 19:33:41 +08:00
|
|
|
FROM (${ctx.query}) __cdb_formula`;
|
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
function Formula (query, options, queryRewriter, queryRewriteData, params, queries) {
|
2017-06-23 22:53:16 +08:00
|
|
|
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries);
|
2016-05-14 00:46:58 +08:00
|
|
|
this.column = options.column || '1';
|
|
|
|
this.operation = options.operation;
|
2017-06-15 22:31:24 +08:00
|
|
|
this._isFloatColumn = null;
|
2017-06-24 00:59:51 +08:00
|
|
|
this.queries = queries;
|
2016-05-14 00:46:58 +08:00
|
|
|
}
|
|
|
|
|
2016-05-31 21:30:38 +08:00
|
|
|
Formula.prototype = Object.create(BaseOverviewsDataview.prototype);
|
2016-05-14 00:46:58 +08:00
|
|
|
Formula.prototype.constructor = Formula;
|
|
|
|
|
|
|
|
module.exports = Formula;
|
|
|
|
|
2017-06-16 00:04:35 +08:00
|
|
|
Formula.prototype.sql = function (psql, override, callback) {
|
2017-06-15 22:31:24 +08:00
|
|
|
var self = this;
|
2017-11-29 19:33:41 +08:00
|
|
|
if (!VALID_OPERATIONS[this.operation]) {
|
|
|
|
return this.defaultSql(psql, override, callback);
|
|
|
|
}
|
2017-06-15 22:31:24 +08:00
|
|
|
|
2017-11-29 19:33:41 +08:00
|
|
|
if (this._isFloatColumn === null) {
|
|
|
|
this._isFloatColumn = false;
|
|
|
|
this.getColumnType(psql, this.column, this.queries.no_filters, function (err, type) {
|
|
|
|
if (!err && !!type) {
|
|
|
|
self._isFloatColumn = type.float;
|
|
|
|
}
|
|
|
|
self.sql(psql, override, callback);
|
2016-05-14 00:46:58 +08:00
|
|
|
});
|
2017-11-29 19:33:41 +08:00
|
|
|
return null;
|
|
|
|
}
|
2017-06-16 00:04:35 +08:00
|
|
|
|
2017-11-29 19:33:41 +08:00
|
|
|
var formulaSql = formulaQueryTpl({
|
|
|
|
isFloatColumn: this._isFloatColumn,
|
|
|
|
query: this.rewrittenQuery(this.query),
|
|
|
|
operation: this.operation,
|
|
|
|
column: this.column
|
|
|
|
});
|
2017-06-15 22:31:24 +08:00
|
|
|
|
2017-11-29 19:33:41 +08:00
|
|
|
callback = callback || override;
|
2016-05-14 00:46:58 +08:00
|
|
|
|
2017-11-29 19:33:41 +08:00
|
|
|
debug(formulaSql);
|
2017-06-15 22:31:24 +08:00
|
|
|
|
2018-08-29 19:50:21 +08:00
|
|
|
return callback(null, formulaSql, { usesOverviews: true });
|
2016-05-14 00:46:58 +08:00
|
|
|
};
|