UNPKG

redash-client

Version:
170 lines (153 loc) 4.14 kB
'use strict'; const fetch = require('cross-fetch'); const delay = require('delay'); const DEFAULT_POLLING_TIMEOUT_MS = 60 * 1000; /** * Redash Client */ class RedashClient { /** * @param {{endPoint: string, apiToken: string, agent: ?http.Agent, authHeaderName: ?string}} options */ constructor({endPoint, apiToken, agent, authHeaderName = 'Authorization'} = {}) { /** * @param {string} path * @param {Object=} body * @param {Object=} options * @return {Promise<Response>} * @private */ this.fetchJson_ = (path, body, options = {}) => { options.headers = { ...options.headers, agent, [authHeaderName]: `Key ${apiToken}`, 'content-type': 'application/json', }; if (body) { options.body = JSON.stringify(body); } return fetch(endPoint + path, options).then(resp => resp.json()); }; } /** * @param {string} path * @return {Promise<Response>} * @private */ get_(path) { const options = { method: 'GET', }; return this.fetchJson_(path, null, options); } /** * @param {string} path * @param {Object=} body * @return {Promise<Response>} * @private */ post_(path, body = {}) { const options = { method: 'POST', }; return this.fetchJson_(path, body, options); } /** * @return {Promise<Array<DataSource>>} */ getDataSources() { return this.get_(`api/data_sources`); } /** * @param {number} id * @return {Promise<DataSource>} */ getDataSource(id) { if (typeof id !== 'number') { throw new TypeError(`Data Source ID should be number: ${id}`); } return this.get_(`api/data_sources/${id}`); } /** * @param {{query: string, data_source_id: number, name: string, description: string?}} query * @return {Promise<Query>} */ postQuery(query) { return this.post_('api/queries', query); } /** * @param {{id: number, query: string, data_source_id: number, name: string, description: string?}} query * @return {Promise<Query>} */ updateQuery(query) { if (typeof query.id !== 'number') { throw new TypeError(`Query ID should be number: ${query.id}`); } return this.post_(`api/queries/${query.id}`, query); } /** * @return {Promise<{count: number, page: number, page_size: number, results: Array<Query>}>} */ getQueries() { return this.get_(`api/queries`); } /** * @param {number} id * @return {Promise<Query>} */ getQuery(id) { return this.get_(`api/queries/${id}`); } /** * @param {{data_source_id: number, max_age: number, query: string, query_id: number}} query * @return {Promise<{job: Job}|{query_result: QueryResult}>} */ postQueryResult(query) { return this.post_('api/query_results', query); } /** * @param {number} queryResultId * @return {Promise<{query_result: QueryResult}>} */ getQueryResult(queryResultId) { if (typeof queryResultId !== 'number') { throw new TypeError(`Query Result ID should be number: ${queryResultId}`); } return this.get_(`api/query_results/${queryResultId}`); } /** * @param {number} id * @return {Promise<{job: Job}>} */ getJob(id) { return this.get_(`api/jobs/${id}`); } /** * @param {{data_source_id: number, query: string, query_id: number}} query * @param {number=} timeout * @return {Promise<{query_result: QueryResult}>} */ async queryAndWaitResult(query, timeout = DEFAULT_POLLING_TIMEOUT_MS) { // `max_age` should be 0 to disable cache always query = {...query, max_age: 0}; const { job: {id}, } = await this.postQueryResult(query); let queryResultId; const start = Date.now(); while (true) { const {job} = await this.getJob(id); if (job.status === 3) { queryResultId = job.query_result_id; break; } if (Date.now() - start > timeout) { throw new Error('polling timeout'); } await delay(1000); } return this.getQueryResult(queryResultId); } } module.exports = RedashClient;