Skip to content
Snippets Groups Projects
Commit 5faaf857 authored by Allen Gilliland's avatar Allen Gilliland
Browse files

initial ability to pivot result data.

parent d1e66dc2
Branches
Tags
No related merge requests found
'use strict';
/*global _*/
var DataGrid = {
pivot: function(data) {
// find the lowest cardinality dimension and make it our "pivoted" column
// TODO: we assume dimensions are in the first 2 columns, which is less than ideal
var pivotCol = 0,
normalCol = 1,
pivotColValues = DataGrid.distinctValues(data, pivotCol);
if (DataGrid.cardinality(data, 1) <= pivotColValues.length) {
pivotCol = 1;
normalCol = 0;
pivotColValues = DataGrid.distinctValues(data, pivotCol);
}
// sort the pivot column values sensibly
pivotColValues.sort();
pivotColValues.unshift(null);
// build the pivoted data grid
var values = data.rows.reduce(function(last, now) {
// grab the last "row" from the total dataset (if possible)
var row = (last.length > 0) ? last[last.length - 1] : null;
if (row === null || row[0] !== now[normalCol]) {
row = Array.apply(null, Array(pivotColValues.length)).map(function() { return null; });
row[0] = now[normalCol];
last.push(row);
}
// put current value into the result at the correct pivoted index
// TODO: we are hard coding to the 3rd value here, assuming that is always the metric :/
row[pivotColValues.lastIndexOf(now[pivotCol])] = now[2];
return last;
}, []);
var cols = pivotColValues.map(function(val) {
var colDef = _.clone(data.cols[pivotCol]);
colDef['display_name'] = val || "";
colDef['name'] = val || "";
return colDef;
});
return {
cols: cols,
columns: pivotColValues,
rows: values
};
},
distinctValues: function(data, colIdx) {
var vals = data.rows.map(function(r) {
return r[colIdx];
});
return vals.filter(function(v, i) { return i==vals.lastIndexOf(v); });
},
cardinality: function(data, colIdx) {
return DataGrid.distinctValues(data, colIdx).length;
}
};
export default DataGrid;
......@@ -2,6 +2,14 @@
var Query = {
isStructured: function(query) {
return query && query.type && query.type === "query";
},
isNative: function(query) {
return query && query.type && query.type === "native";
},
canRun: function(query) {
return query && query.source_table != undefined && Query.hasValidAggregation(query);
},
......@@ -57,7 +65,17 @@ var Query = {
canAddDimensions: function(query) {
var MAX_DIMENSIONS = 2;
return (query.breakout.length < MAX_DIMENSIONS);
return query && query.breakout && (query.breakout.length < MAX_DIMENSIONS);
},
numDimensions: function(query) {
if (query && query.breakout) {
return query.breakout.filter(function(b) {
return b !== null;
}).length;
}
return 0;
},
hasValidBreakout: function(query) {
......
......@@ -9,6 +9,7 @@ import VisualizationSettings from './visualization_settings.react';
import LoadingSpinner from '../components/icons/loading.react';
import Query from "metabase/lib/query";
import DataGrid from "metabase/lib/data_grid";
var cx = React.addons.classSet;
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
......@@ -195,15 +196,28 @@ export default React.createClass({
} else if (this.props.card.display === "table") {
var sort = (this.props.card.dataset_query.query && this.props.card.dataset_query.query.order_by) ?
var tableData = this.props.result.data,
cellClickable = this.props.cellIsClickableFn,
sortFunction = this.props.setSortFn,
sort = (this.props.card.dataset_query.query && this.props.card.dataset_query.query.order_by) ?
this.props.card.dataset_query.query.order_by : null;
// check if the data is pivotable (2 groupings + 1 agg != 'rows')
if (Query.isStructured(this.props.card.dataset_query) &&
!Query.isBareRowsAggregation(this.props.card.dataset_query.query) &&
tableData.cols.length === 3) {
tableData = DataGrid.pivot(this.props.result.data);
sortFunction = undefined;
cellClickable = function() { return false; };
}
viz = (
<QueryVisualizationTable
data={this.props.result.data}
data={tableData}
maxRows={this.props.maxTableRows}
setSortFn={this.props.setSortFn}
setSortFn={sortFunction}
sort={sort}
cellIsClickableFn={this.props.cellIsClickableFn}
cellIsClickableFn={cellClickable}
cellClickedFn={this.props.cellClickedFn}
/>
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment