Skip to content

Commit

Permalink
better MDX parser, code optimizations, refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitaeverywhere committed Dec 3, 2014
1 parent f021005 commit de46551
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 100 deletions.
13 changes: 12 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ var gulp = require("gulp"),
wrap = require("gulp-wrap"),
minifyCSS = require("gulp-minify-css"),
htmlReplace = require("gulp-html-replace"),
replace = require('gulp-replace');
header = require("gulp-header"),
replace = require("gulp-replace"),
pkg = require("./package.json");

var banner = [
"/** <%= pkg.name %>: <%= pkg.description %>",
" ** @author <%= pkg.author %>",
" ** @version <%= pkg.version %>",
" **/",
""
].join("\n");

gulp.task("clean", function () {
return gulp.src("build", {read: false})
Expand All @@ -22,6 +32,7 @@ gulp.task("gatherScripts", ["clean"], function () {
ascii_only: true
}
}))
.pipe(header(banner, { pkg: pkg }))
.pipe(gulp.dest("build/js/"));
});

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "LightPivotTable",
"author": "ZitRo",
"version": "0.5.2",
"description": "Light pivot table for MDX2JSON source for InterSystems Cache",
"version": "0.6.0",
"description": "A lightweight pivot table for MDX2JSON source for InterSystems Cache",
"main": "test/testServer.js",
"directories": {
"test": "test"
Expand Down
2 changes: 0 additions & 2 deletions source/js/DataController.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,6 @@ DataController.prototype.sortByColumn = function (columnIndex) {
.concat(newRawData)
.concat(this.SUMMARY_SHOWN ? [data._rawDataOrigin[data._rawDataOrigin.length - 1]] : []);

console.log(data.rawData);

this._trigger();

};
2 changes: 1 addition & 1 deletion source/js/DataSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ DataSource.prototype.getCurrentData = function (callback) {
mdx = mdxParser.applyFilter(mdx, this.FILTERS[i]);
}

console.log("MDX: " + mdx);
console.log("Request MDX: " + mdx);

this._post(this.SOURCE_URL + "/" + this.ACTION, {
MDX: mdx
Expand Down
43 changes: 28 additions & 15 deletions source/js/LightPivotTable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Light pivot table global object.
*
* @param {object} configuration
* @constructor
*/
var LightPivotTable = function (configuration) {

var _ = this;
Expand All @@ -16,7 +22,7 @@ var LightPivotTable = function (configuration) {
* @type {DataController}
*/
this.dataController = new DataController(this, function () {
_.dataChangeTrigger.call(_);
_.dataIsChanged.call(_);
});

this.init();
Expand Down Expand Up @@ -70,6 +76,10 @@ LightPivotTable.prototype.clearFilters = function () {

};

/**
* @param {object} config - part of dataSource configuration. Usually a part of config given to LPT.
* @returns {DataSource}
*/
LightPivotTable.prototype.pushDataSource = function (config) {

var newDataSource;
Expand All @@ -92,12 +102,20 @@ LightPivotTable.prototype.popDataSource = function () {

};

LightPivotTable.prototype.dataChangeTrigger = function () {
/**
* Data change handler.
*/
LightPivotTable.prototype.dataIsChanged = function () {

this.pivotView.renderRawData(this.dataController.getData().rawData);

};

/**
* Try to DrillDown with given filter.
*
* @param {string} filter
*/
LightPivotTable.prototype.tryDrillDown = function (filter) {

var _ = this,
Expand All @@ -108,8 +126,8 @@ LightPivotTable.prototype.tryDrillDown = function (filter) {
for (var i in _.CONFIG.dataSource) { ds[i] = _.CONFIG.dataSource[i]; }

if (this.CONFIG.DrillDownExpression && this._dataSourcesStack.length < 2) {
ds.basicMDX = this.mdxParser.customDrillDown(
this.dataSource.BASIC_MDX, this.CONFIG.DrillDownExpression, filter
ds.basicMDX = this.mdxParser.drillDown(
this.dataSource.BASIC_MDX, filter, this.CONFIG.DrillDownExpression
) || this.dataSource.BASIC_MDX;
} else {
ds.basicMDX = this.mdxParser.drillDown(this.dataSource.BASIC_MDX, filter) || this.dataSource.BASIC_MDX;
Expand All @@ -134,9 +152,11 @@ LightPivotTable.prototype.tryDrillDown = function (filter) {
};

/**
* Try to DrillThrough with given filters.
*
* @param {string[]} [filters]
*/
LightPivotTable.prototype.showDrillThrough = function (filters) {
LightPivotTable.prototype.tryDrillThrough = function (filters) {

var _ = this,
oldDataSource,
Expand All @@ -145,19 +165,12 @@ LightPivotTable.prototype.showDrillThrough = function (filters) {
// clone dataSource config object
for (var i in _.CONFIG.dataSource) { ds[i] = _.CONFIG.dataSource[i]; }
ds.action = "MDXDrillthrough";
if (filters instanceof Array) {
console.log("BASIC MDX: " + this.dataSource.BASIC_MDX, "\n\nFILTERS: " + filters);
ds.basicMDX = this.mdxParser.customDrillThrough(this.dataSource.BASIC_MDX, filters)
|| this.dataSource.basicMDX;
} else {
ds.basicMDX = this.dataSource.BASIC_MDX;
ds.basicMDX = this.mdxParser.drillThrough(ds.basicMDX) || ds.basicMDX;
}

oldDataSource = this.dataSource;
ds.basicMDX = this.mdxParser.drillThrough(this.dataSource.BASIC_MDX, filters)
|| this.dataSource.basicMDX;

oldDataSource = this.dataSource;
this.pushDataSource(ds);

this.dataSource.FILTERS = oldDataSource.FILTERS;

this.dataSource.getCurrentData(function (data) {
Expand Down
126 changes: 52 additions & 74 deletions source/js/MDXParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,114 +5,92 @@ var MDXParser = function () {
};

/**
* Performs DrillDown on MDX query.
* Debug method.
*
* @param {string} basicMDX
* @param {string} filter
* @returns {string} - new query.
* @param {string} mdx
* @param {string} [message]
* @private
*/
MDXParser.prototype.drillDown = function (basicMDX, filter) {

try {

var filterParts = filter.split(/(\(?)([^\)]*)(\)?)/),
clearFilter = filterParts[2],
parts = basicMDX.split(/(\s+ON\s+0,\s*)(.*)(\s+ON\s+1\s*)/i),
oldPath = parts[2].split(/(\(?)(\[[^\(^\)]*)(\)?)/);

oldPath[2] = clearFilter + ".children";
parts[2] = oldPath.join("");

//console.log("\n\nIN: "+basicMDX+"\n\nFILTER: " + filter + "\n\nCUSTOM: "+ parts.join("")
// + " %FILTER " + filterParts.join(""));

return parts.join("") + " %FILTER " + filterParts.join("");

} catch (e) {

console.error("Unable to get DrillDown statement from", basicMDX, "with filter", filter);
return "";

}

MDXParser.prototype._warnMDX = function (mdx, message) {
console.warn("MDX is not parsed:\n\n%s\n\n" + (message ? "(" + message + ")" : ""), mdx);
};

/**
* Replace dimension [1] with expression.
* Converts filter to setExpression that can be inserted to MDX.
*
* @param {string} basicMDX
* @param {string} expression
* @param {string} [filter]
* @returns {string}
* @param filterSpec
*/
MDXParser.prototype.customDrillDown = function (basicMDX, expression, filter) {

try {

var parts = basicMDX.split(/(\s+ON\s+0,\s*)(.*)(\s+ON\s+1\s*)/i);

parts[2] = expression;

if (filter) parts.push(" %FILTER " + filter);

//console.log("\n\nIN: "+basicMDX+"\n\nEXPR: " + expression + "\n\nFILTER: "
// + filter + "\n\nCUSTOM: " + parts.join(""));

return parts.join("");

} catch (e) {

console.error("Unable to get DrillDown statement from", basicMDX, "by", expression,
"with filter", filter);
return "";

MDXParser.prototype.makeSetExpressionFromFilter = function (filterSpec) {
if (filterSpec.match(/^\([^\),]*,[^\)]*\)$/)) {
return "NONEMPTYCROSSJOIN" + filterSpec.slice(0, filterSpec.length - 1) + ".children)";
} else {
return filterSpec + ".children";
}

};

/**
* Returns DrillThrough query for given MDX query.
* Performs DrillDown on MDX query.
*
* @param {string} basicMDX
* @returns {string}
* @param {string} mdx
* @param {string} filter
* @param {string} [expression] - if is set, "* ON 1" will be replaced with "{value} ON 1"
* @returns {string} - new query.
*/
MDXParser.prototype.drillThrough = function (basicMDX) {
MDXParser.prototype.drillDown = function (mdx, filter, expression) {

try {
if (!filter) {
this._warnMDX(mdx, "no filter specified");
return "";
}

var statement = ["DRILLTHROUGH SELECT "]
.concat(basicMDX.split(/(\s+ON\s+0,\s*)(.*)(\s+ON\s+1\s*)/i).slice(2)).join("");
var parts = mdx.split(/(select)(.*?)(from)/ig); // split by SELECT queries

console.log("DRILLTHROUGH STATEMENT:", statement);
if (parts.length < 4) {
this._warnMDX(mdx);
return ""; // no select query matched
}

return statement === "DRILLTHROUGH SELECT " ? "" : statement;
var selectBody = parts[parts.length - 3],
dimensions = selectBody.split(/(\s*ON\s*[01]\s*,?\s*)/);

} catch (e) {
if (dimensions.length < 2) {
this._warnMDX(mdx);
return ""; // no dimensions matched
}

console.error("Unable to get DrillThrough statement from", basicMDX);
return "";
var index = -1;
dimensions.map(function(e,i){if(e.match(/\s*ON\s*[01]\s*,?\s*/)) index=i-1; return e;});

if (index === -1) {
this._warnMDX(mdx, "DrillDown is impossible");
return ""; // DrillDown is impossible (no "1" dimension)
}

dimensions[index] = expression || this.makeSetExpressionFromFilter(filter);
for (var i in dimensions) {
if (dimensions[i].length === 1) { // "0" || "1"
dimensions[i](parseInt(i), 1);
}
}
parts[parts.length - 3] = dimensions.join("");

return this.applyFilter(parts.join(""), filter);

};

/**
* @param {string} basicMDX
* @param {string[]} filters
* @param {string[]} [filters]
*/
MDXParser.prototype.customDrillThrough = function (basicMDX, filters) {
MDXParser.prototype.drillThrough = function (basicMDX, filters) {

var cubeAndFilters = basicMDX.split(/(FROM\s*\[[^\]]*].*)/i)[1],
query = "DRILLTHROUGH SELECT " + cubeAndFilters;

if (!(filters instanceof Array)) filters = [filters];

for (var i in filters) {
query += " %FILTER " + filters[i];
query = this.applyFilter(query, filters[i]);
}

console.log("CUSTOM DRILLTHROUGH STATEMENT: " + query);

return query;

};
Expand Down
11 changes: 6 additions & 5 deletions source/js/PivotView.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ PivotView.prototype._backClickHandler = function (event) {

PivotView.prototype._drillThroughClickHandler = function (event) {

this.controller.showDrillThrough();
this.controller.tryDrillThrough();

event.cancelBubble = true;
event.stopPropagation();
Expand All @@ -164,7 +164,7 @@ PivotView.prototype._drillThroughClickHandler = function (event) {
PivotView.prototype._cellClickHandler = function (x, y) {

var data = this.controller.dataController.getData(),
f1, f2;
f = [], f1, f2;

try {
f1 = data.rawData[y][data.info.leftHeaderColumnsNumber - 1].source.path;
Expand All @@ -173,14 +173,15 @@ PivotView.prototype._cellClickHandler = function (x, y) {
console.warn("Unable to get filters for cell (%d, %d)", x, y);
}

if (!f1) return;
if (f1) f.push(f1);
if (f2) f.push(f2);

if (this.controller.CONFIG["drillDownTarget"]) {
window.location = location.origin + location.pathname + "?DASHBOARD="
+ encodeURIComponent(this.controller.CONFIG["drillDownTarget"]) + "&SETTINGS=FILTER:"
+ encodeURIComponent(f1 + "~" + f2) + ";";
+ encodeURIComponent(f.join("~")) + ";";
} else {
this.controller.showDrillThrough(f2 ? [f1, f2] : [f1]);
this.controller.tryDrillThrough(f);
}

};
Expand Down

0 comments on commit de46551

Please sign in to comment.