gethue
Version:
Hue is an Open source SQL Query Editor for Databases/Warehouses
183 lines (160 loc) • 6.36 kB
JavaScript
// 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 * as ko from 'knockout';
import { MULTI_NAME as SIMPLE_ACE_MULTI } from '../../../ko/components/simpleAceEditor/ko.simpleAceEditor';
import { CONTEXT_SELECTOR_COMPONENT } from '../../../ko/components/ko.contextSelector';
import { HUE_DROP_DOWN_COMPONENT } from '../../../ko/components/ko.dropDown';
import { SIMPLE_RESULT_GRID_COMPONENT } from '../../../apps/editor/components/resultGrid/ko.simpleResultGrid';
import 'apps/editor/components/ExecutableActionsKoBridge.vue';
import Executor from '../../../apps/editor/execution/executor';
import SqlExecutable from '../../../apps/editor/execution/sqlExecutable';
import { CONFIG_REFRESHED_TOPIC } from '../../../config/events';
import { filterEditorConnectors } from '../../../config/hueConfig';
import componentUtils from '../../../ko/components/componentUtils';
import DisposableComponent from '../../../ko/components/DisposableComponent';
import { getStatementsParser } from '../../../parse/utils';
export const NAME = 'quick-query-context';
// prettier-ignore
const TEMPLATE = `
<div class="context-popover-flex-fill" style="overflow: auto;">
<div style="display: inline-block" data-bind="
component: {
name: '${ HUE_DROP_DOWN_COMPONENT }',
params: {
value: connector,
labelAttribute: 'displayName',
entries: availableConnectors,
linkTitle: 'Active connector'
}
}
"></div>
<!-- ko if: connector() -->
<div class="margin-left-10" style="display: inline-block" data-bind="
component: {
name: '${ CONTEXT_SELECTOR_COMPONENT }',
params: {
connector: connector,
compute: compute,
namespace: namespace,
availableDatabases: availableDatabases,
database: database,
hideLabels: true
}
}
"></div>
<!-- /ko -->
<!-- ko ifnot: loadingContext -->
<!-- ko with: connector -->
<div style="margin: 10px;" data-bind="
component: {
name: '${ SIMPLE_ACE_MULTI }',
params: {
autocomplete: $parent.autocomplete,
value: $parent.statement,
lines: 3,
aceOptions: {
minLines: 3,
maxLines: 5
},
mode: dialect,
database: $parent.database,
availableDatabases: $parent.availableDatabases,
namespace: $parent.namespace,
compute: $parent.compute,
executor: $parent.executor,
activeExecutable: $parent.activeExecutable
}
}
"></div>
<executable-actions-ko-bridge data-bind="vueKoProps: {
'executable-observable': $parent.activeExecutable
}"></executable-actions-ko-bridge>
<div data-bind="
component: {
name: '${ SIMPLE_RESULT_GRID_COMPONENT }',
params: { activeExecutable: $parent.activeExecutable }
}
"></div>
<!-- /ko -->
<!-- /ko -->
</div>
`;
class QuickQueryContext extends DisposableComponent {
constructor(params) {
super(params);
this.availableConnectors = ko.observableArray();
this.connector = ko.observable();
this.availableDatabases = ko.observableArray();
this.database = ko.observable();
this.activeExecutable = ko.observable();
// TODO: Switch over to connector in ko.simpleAceEditor
this.namespace = ko.observable();
this.compute = ko.observable();
this.statement = ko.observable();
this.loadingContext = ko.pureComputed(
() => !this.namespace() || !this.compute() || !this.database()
);
this.dialect = ko.pureComputed(() => this.connector() && this.connector().dialect);
this.type = ko.pureComputed(() => this.connector() && this.connector().id);
this.defaultLimit = ko.observable(10);
this.executor = new Executor({
sourceType: this.type,
namespace: this.namespace,
compute: this.compute,
connector: this.connector,
defaultLimit: this.defaultLimit
});
this.autocomplete = ko.pureComputed(
() => this.connector() && { type: this.connector().dialect, connector: this.connector }
);
this.updateFromConfig();
this.subscribe(CONFIG_REFRESHED_TOPIC, this.updateFromConfig.bind(this));
let refreshExecutableThrottle = -1;
const refreshExecutable = () => {
window.clearTimeout(refreshExecutableThrottle);
refreshExecutableThrottle = window.setTimeout(() => {
const parsedStatement = getStatementsParser(this.connector()).parse(
this.statement() || ''
)[0];
const executable = new SqlExecutable({
executor: this.executor,
parsedStatement: parsedStatement,
database: this.database()
});
this.activeExecutable(executable);
this.executor.setExecutables([executable]);
}, 200);
};
this.subscribe(this.statement, refreshExecutable);
this.subscribe(this.database, refreshExecutable);
}
updateFromConfig() {
const configuredSqlConnectors = filterEditorConnectors(connector => connector.is_sql);
this.availableConnectors(configuredSqlConnectors);
const found =
this.connector() &&
this.availableConnectors().some(connector => {
if (connector.id === this.connector().id) {
this.connector(connector);
return true;
}
});
if (!found) {
this.connector(this.availableConnectors().length ? this.availableConnectors()[0] : undefined);
}
}
}
componentUtils.registerComponent(NAME, QuickQueryContext, TEMPLATE);