Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json generator #436

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions caravel/assets/javascripts/datasource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
var $ = window.$ || require('jquery');
var jsonGenerator = require("./modules/json_generator");

$(document).ready(function () {
var $modal = $('#json_gen_modal');

var getJsonOrWarn = function () {
var expression = $('#expression').val().trim();
var $alert = $modal.find('#errorMsg');
$alert
.removeClass('hidden')
.hide()
.html("");
try {
var parse_tree = jsonGenerator.parse(expression);
return JSON.stringify(parse_tree);
} catch (e) {
$alert
.show()
.html(e.message);
}
return null;
};

$('#convertButton').click(function () {
var json = getJsonOrWarn();
if (json) {
$('#json').val(json);
$(this).closest('.modal').modal('hide');
}
});

$('#previewButton').click(function () {
var $preview = $modal.find('#preview');
var json = getJsonOrWarn();
$preview.html(json || "");
});

$modal.on('shown.bs.modal', function () {
$('#expression').focus();
});

var showJsonGenModal = function () {
$modal.modal('show');
};

$.extend(window, {
showJsonGenModal: showJsonGenModal
});
});
92 changes: 92 additions & 0 deletions caravel/assets/javascripts/modules/json_generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
var jsep = require("jsep");

var capitalize = function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};

var convertFuncCall = function (node) {
var funcName = node.callee.name;
var fieldName = node.arguments[0].name || "";
var m = funcName.toLowerCase().match(/^(double|long)?(sum|min|max)$/);
if (!m) {
throw new Error("Unsupported function call: " + funcName);
}

var varType = m[1] || 'double'; // default to double
var funcType = m[2];

var type = varType + capitalize(funcType);

return {
type: type,
name: fieldName,
fieldName: fieldName
};
};

var convertField = function (node) {
var fieldName = node.name;
return {
type: "fieldAccess",
name: fieldName,
fieldName: fieldName
};
};

var convertBinary = function (node) {
var op = node.operator;
// TODO: Support the "quotient" type
if (!/[+\-*\/]/.test(op)) {
throw new Error("Unsupported operation: " + op);
}
return {
type: "arithmetic",
fn: op,
fields: [node.left, node.right].map(function (child) {
return convertArithmetic(child);
})
};
};

var convertLiteral = function (node) {
return {
type: "constant",
value: node.value
};
};

var arithmeticTokenHandler = {
Identifier: convertField,
BinaryExpression: convertBinary,
Literal: convertLiteral
};

var convertArithmetic = function (node) {
var converter = arithmeticTokenHandler[node.type];
if (!converter) {
throw new Error("Invalid Expression (" + node.type + ")");
}
return converter(node);
};

var parse = function (expression) {
expression = expression.trim().replace('\n', '');
if (!expression) {
throw new Error("Please enter the expression");
}
var parse_tree = jsep(expression);
var converterMap = {
CallExpression: convertFuncCall,
BinaryExpression: convertArithmetic,
Literal: convertArithmetic
};
var converter = converterMap[parse_tree.type];
if (!converter) {
throw new Error("Invalid Expression (" + parse_tree.type + ")");
}
return converter(parse_tree);
};

module.exports = {
parse: parse
};
1 change: 1 addition & 0 deletions caravel/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"imports-loader": "^0.6.5",
"jquery": "^2.2.1",
"jquery-ui": "^1.10.5",
"jsep": "^0.3.0",
"less": "^2.6.1",
"less-loader": "^2.2.2",
"nvd3": "1.8.2",
Expand Down
3 changes: 2 additions & 1 deletion caravel/assets/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var config = {
explore: APP_DIR + '/javascripts/explore.js',
welcome: APP_DIR + '/javascripts/welcome.js',
sql: APP_DIR + '/javascripts/sql.js',
standalone: APP_DIR + '/javascripts/standalone.js'
standalone: APP_DIR + '/javascripts/standalone.js',
datasource: APP_DIR + '/javascripts/datasource.js'
},
output: {
path: BUILD_DIR,
Expand Down
41 changes: 41 additions & 0 deletions caravel/templates/caravel/models/datasource/edit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends "appbuilder/general/model/edit.html" %}

{% block content %}
{{ super() }}
<div class="modal fade" id="json_gen_modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content css">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">JSON Generator</h4>
<p>Enter the algebraic expression to convert. For example: <br>
<strong>Normal metrics</strong>: longSum(price), doubleMin(price)<br>
<strong>Post Aggregation</strong>: (price/count)*100<br>
</p>
</div>
<div class="modal-body">
<textarea id="expression" rows="5" cols="60"></textarea>
<p><strong>Preview:</strong></p>
<div class="" id="preview">(Please click the preview button)</div>
<div class="alert alert-danger hidden" id="errorMsg"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-default" id="previewButton">
Preview
</button>
<button type="button" class="btn btn-default" id="convertButton">
Convert to Json
</button>
</div>
</div>
</div>
</div>
{% endblock %}

{% block tail_js %}
{{ super() }}
<script src="/static/assets/javascripts/dist/datasource.entry.js"></script>
{% endblock %}
5 changes: 5 additions & 0 deletions caravel/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ class DruidMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
"[Druid Post Aggregation]"
"(http://druid.io/docs/latest/querying/post-aggregations.html)",
True),
'json': utils.markdown(
"You can also use the "
"[generator](javascript:showJsonGenModal()) to generate json",
True),
}
appbuilder.add_view_no_menu(DruidMetricInlineView)

Expand Down Expand Up @@ -415,6 +419,7 @@ class DruidDatasourceModelView(CaravelModelView, DeleteMixin): # noqa
'datasource_name', 'cluster', 'description', 'owner',
'is_featured', 'is_hidden', 'default_endpoint', 'offset',
'cache_timeout']
edit_template = "caravel/models/datasource/edit.html"
add_columns = edit_columns
page_size = 500
base_order = ('datasource_name', 'asc')
Expand Down