// Licensed to Cloudera, Inc. under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. Cloudera, Inc. licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { fetchResults, fetchResultSize, ResultApiResponse, ResultMeta, ResultSizeApiResponse } from '../../../apps/editor/execution/api'; import { EXECUTABLE_RESULT_UPDATED_TOPIC, ExecutableResultUpdatedEvent } from '../../../apps/editor/execution/events'; import { Observable } from 'knockout'; import * as ko from 'knockout'; import huePubSub from '../../../utils/huePubSub'; import sleep from '../../../utils/timing/sleep'; import SqlExecutable, { ExecutionStatus } from './sqlExecutable'; export const RESULT_TYPE = { TABLE: 'table' }; const META_TYPE_TO_CSS: { [key: string]: string } = { bigint: 'sort-numeric', date: 'sort-date', datetime: 'sort-date', decimal: 'sort-numeric', double: 'sort-numeric', float: 'sort-numeric', int: 'sort-numeric', real: 'sort-numeric', smallint: 'sort-numeric', timestamp: 'sort-date', tinyint: 'sort-numeric' }; const NUMERIC_TYPES: { [key: string]: boolean } = { bigint: true, decimal: true, double: true, float: true, int: true, real: true, smallint: true, tinyint: true }; const DATE_TIME_TYPES: { [key: string]: boolean } = { date: true, datetime: true, timestamp: true }; const COMPLEX_TYPES: { [key: string]: boolean } = { array: true, map: true, struct: true }; // huePubSub.subscribe('editor.ws.query.fetch_result', executionResult => { // if (executionResult.status != 'finalMessage') { // const result = new ExecutionResult(null); // result.fetchedOnce = true; // result.handleResultResponse(executionResult); // // eslint-disable-next-line no-undef // executionResult.data.forEach(element => $('#wsResult').append('
  • ' + element + '
  • ')); // } // }); export interface KoEnrichedMeta extends ResultMeta { cssClass: string; checked: Observable; originalIndex: number; } export type ResultRow = (string | number)[]; export enum ResultType { Table = 'table' } export default class ExecutionResult { executable: SqlExecutable; streaming: boolean; type?: ResultType; rows: ResultRow[] = []; meta: ResultMeta[] = []; cleanedMeta: ResultMeta[] = []; cleanedDateTimeMeta: ResultMeta[] = []; cleanedStringMeta: ResultMeta[] = []; cleanedNumericMeta: ResultMeta[] = []; koEnrichedMeta: KoEnrichedMeta[] = []; lastRows: ResultRow[] = []; images = []; hasMore = true; isEscaped = false; fetchedOnce = false; constructor(executable: SqlExecutable, streaming?: boolean) { this.executable = executable; this.streaming = !!streaming; } async fetchResultSize(): Promise { if (this.executable.status === ExecutionStatus.failed) { return; } let attempts = 0; const waitForRows = async (): Promise => { attempts++; if (attempts < 10) { const resultSizeResponse = await fetchResultSize({ executable: this.executable, silenceErrors: true }); if (resultSizeResponse.rows) { return resultSizeResponse; } else { await sleep(1000); return await waitForRows(); } } else { return Promise.reject(); } }; return await waitForRows(); } async fetchRows(options?: { rows?: number; startOver?: boolean }): Promise { const resultResponse = await fetchResults({ executable: this.executable, rows: (options && options.rows) || 100, startOver: !!(options && options.startOver) }); if (resultResponse) { this.handleResultResponse(resultResponse); } } handleResultResponse(resultResponse: ResultApiResponse): void { const initialIndex = this.rows.length; resultResponse.data.forEach((row, index) => { row.unshift(initialIndex + index + 1); }); this.rows.push(...resultResponse.data); this.lastRows = resultResponse.data; if (!this.meta.length) { this.meta = resultResponse.meta; this.meta.unshift({ type: 'INT_TYPE', name: '', comment: null }); this.meta.forEach((item, index) => { const cleanedType = item.type.replace(/_type/i, '').toLowerCase(); if (index) { this.cleanedMeta.push(item); if (NUMERIC_TYPES[cleanedType]) { this.cleanedNumericMeta.push(item); } else if (DATE_TIME_TYPES[cleanedType]) { this.cleanedDateTimeMeta.push(item); } else if (!COMPLEX_TYPES[cleanedType]) { this.cleanedStringMeta.push(item); } } this.koEnrichedMeta.push({ name: item.name, type: cleanedType, comment: item.comment, cssClass: META_TYPE_TO_CSS[cleanedType] || 'sort-string', checked: ko.observable(true), originalIndex: index }); }); } this.hasMore = resultResponse.has_more; this.isEscaped = resultResponse.isEscaped; if (resultResponse.type) { this.type = resultResponse.type; } this.fetchedOnce = true; this.notify(); } notify(): void { huePubSub.publish(EXECUTABLE_RESULT_UPDATED_TOPIC, this); } }