Skip to content

Commit

Permalink
Add Presto web connector for Tableau
Browse files Browse the repository at this point in the history
  • Loading branch information
nezihyigitbasi authored and haozhun committed Nov 7, 2015
1 parent 02c8f9f commit 0f50a33
Show file tree
Hide file tree
Showing 7 changed files with 665 additions and 1 deletion.
1 change: 1 addition & 0 deletions presto-docs/src/main/sphinx/index.rst
Expand Up @@ -15,4 +15,5 @@ Presto Documentation
sql
migration
develop
tableau
release
27 changes: 27 additions & 0 deletions presto-docs/src/main/sphinx/tableau.rst
@@ -0,0 +1,27 @@
*************************
Web Connector for Tableau
*************************

Presto web connector for Tableau implements the functions in the Tableau web
connector API and lets users run queries from Tableau against Presto. You can
get more info about the Tableau web connector API at
`<http://community.tableau.com/community/developers/web-data-connectors>`_.

When creating a new web data source Tableau will ask for the URL of the web
connector, which is
``http://[presto_coordinator_host]:[port]/tableu/presto-connector.html``
where ``presto_coordinator_host`` is the hostname that Presto coordinator is
running on, ``port`` is 8080 by default. When Tableau first loads the Presto
web connector it will render an HTML form. In this form you need to fill in
details such as your user name, the catalog and the schema you want to query,
the data source name, and finally the SQL query to run. After you click
``Submit`` the query will be submitted to the Presto coordinator and Tableau
will then create an extract out of the results retrieved from the coordinator
page by page. After Tableau is done extracting the results of your query you
can then use this extract for further analysis with Tableau.

.. note::
With Presto web connector you can only create Tableau extracts as the web
connector API currently doesn't support the live mode.


102 changes: 102 additions & 0 deletions presto-main/src/main/resources/webapp/tableu/presto-client.js
@@ -0,0 +1,102 @@
/**
Tableau web connector doc says that it supports: bool, date, datetime, float, int, and string
So, fields with complex types are converted to json strings.
*/
function StatementClient(connectionData, headerCallback, dataCallback, errorCallback) {
this.query = connectionData.query;
this.catalog = connectionData.catalog;
this.schema = connectionData.schema;
this.source = 'Tableau Web Connector';
this.user = connectionData.userName;
this.sessionParameters = [];

this.headerCallback = headerCallback;
this.dataCallback = dataCallback;
this.errorCallback = errorCallback;

this.currentResults = null;
this.valid = true;

if (!(connectionData.sessionParameters === undefined)) {
var parameterMap = JSON.parse(connectionData.sessionParameters);
for (var name in parameterMap) {
var value = parameterMap[name];
this.sessionParameters.push(name + '=' + value);
}
}

this.headers = {
"X-Presto-User": this.user ? this.user : 'N/A',
"X-Presto-Source": this.source,
"X-Presto-Catalog": this.catalog,
"X-Presto-Schema": this.schema,
"X-Presto-Session": this.sessionParameters
};

// lastRecordNumber starts with 0 according to Tableau web connector docs
this.submitQuery(0);
}

StatementClient.prototype.submitQuery = function(lastRecordNumber) {
var statementClient = this;
$.ajax({
type: "POST",
url: '/v1/statement',
headers: this.headers,
data: this.query,
dataType: 'json',
// FIXME having problems when async: true
async: false,
error: function(xhr, statusStr, errorStr) {
statementClient.errorCallback(xhr.responseText, errorStr);
},
success: function(response) {
statementClient.currentResults = response;
statementClient.responseHandler(response, lastRecordNumber);
}
});
};

StatementClient.prototype.advance = function(lastRecordNumber) {
if (!this.currentResults || !this.currentResults.nextUri) {
this.valid = false;
return;
}

var statementClient = this;
$.ajax({
type: "GET",
url: this.currentResults.nextUri,
headers: this.headers,
dataType: 'json',
// FIXME having problems when async: true
async: false,
error: function(xhr, statusStr, errorStr) {
statementClient.errorCallback(xhr.responseText, errorStr);
},
success: function(response) {
statementClient.currentResults = response;
statementClient.responseHandler(response, lastRecordNumber);
if (!(response.data || response.error)) {
// no data in this batch, schedule another GET
statementClient.advance(lastRecordNumber);
}
}
});
};

StatementClient.prototype.responseHandler = function(response, lastRecordNumber) {
if (response.error) {
this.errorCallback(response.error.errorName, response.error.message);
}

if (response.columns) {
this.headerCallback(response.columns);
}

if (response.data) {
// push the columns first in case we didn't get columns in previous requests
this.headerCallback(response.columns);
this.dataCallback(response.data, response.columns, lastRecordNumber);
}
}

0 comments on commit 0f50a33

Please sign in to comment.