/* * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; import { queryCustomizeSelect, querySelectTraceStats } from '../database/SqlLite.js'; import { LitTable } from '../../base-ui/table/lit-table.js'; import '../../base-ui/table/lit-table.js'; import { LitTableColumn } from '../../base-ui/table/lit-table-column.js'; import { info } from '../../log/Log.js'; import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; import { PageNation } from '../../base-ui/chart/pagenation/PageNation.js'; import { PaginationBox } from '../../base-ui/chart/pagenation/pagination-box.js'; import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; @element('sp-query-sql') export class SpQuerySQL extends BaseElement { private queryTableEl: LitTable | undefined; private queryText: string | undefined; private resultText: string | undefined; private notSupportList: Array | undefined; private querySize: HTMLElement | undefined; private keyList: Array | undefined; private selector: HTMLTextAreaElement | undefined; private isSupportSql: boolean = true; private querySelectTables: string = ''; private response: HTMLDivElement | undefined; private statDataArray: any = []; private sliceData: any = []; private querySqlErrorText: string = ''; private progressLoad: LitProgressBar | undefined; private pagination: PaginationBox | undefined; private pageSize: number = 200000; private maxPageSize: number = 500000; initElements(): void { this.progressLoad = this.shadowRoot?.querySelector('.load-query-sql') as LitProgressBar; this.selector = this.shadowRoot?.querySelector('.sql-select') as HTMLTextAreaElement; this.queryTableEl = new LitTable(); this.querySize = this.shadowRoot?.querySelector('.query_size') as HTMLElement; this.response = this.shadowRoot?.querySelector('#dataResult') as HTMLDivElement; this.pagination = this.shadowRoot?.querySelector('.pagination-box') as PaginationBox; this.notSupportList?.push('insert', 'delete', 'update', 'drop', 'alter', 'truncate', 'create'); let htmlDivElement = this.queryTableEl.shadowRoot?.querySelector('.table') as HTMLDivElement; htmlDivElement.style.overflowX = 'scroll'; window.addEventListener('resize', () => { this.freshTableHeadResizeStyle(); }); let copyButtonEl = this.shadowRoot?.querySelector('#copy-button') as HTMLButtonElement; copyButtonEl.addEventListener('click', () => { this.copyTableData(); }); let closeButtonEl = this.shadowRoot?.querySelector('#close-button') as HTMLButtonElement; closeButtonEl.addEventListener('click', () => { this.querySize!.textContent = 'Query result - 0 counts'; this.queryTableEl!.dataSource = []; this.response!.innerHTML = ''; }); } freshTableHeadResizeStyle() { let th = this.queryTableEl!.shadowRoot?.querySelector('.th'); if (th) { let td = th.querySelectorAll('.td'); let firstChild = this.queryTableEl!.shadowRoot?.querySelector('.body')!.firstElementChild; if (firstChild) { let bodyList = firstChild.querySelectorAll('.td'); for (let index = 0; index < bodyList.length; index++) { td[index].style.width = bodyList[index].offsetWidth + 'px'; td[index].style.overflow = 'hidden'; } } } } async copyTableData() { let copyResult = ''; for (let keyListKey of this.keyList!) { copyResult += keyListKey + '\t'; } copyResult += '\n'; let copyData = []; if (this.statDataArray.length > this.maxPageSize) { copyData = this.sliceData; } else { copyData = this.statDataArray; } for (const value of copyData) { this.keyList?.forEach((key) => { copyResult += value[key] + '\t'; }); copyResult += '\n'; } await navigator.clipboard.writeText(copyResult); } selectEventListener = (event: KeyboardEvent) => { let that = this; if (event.ctrlKey && event.keyCode == 13) { SpStatisticsHttpUtil.addOrdinaryVisitAction({ event: 'query', action: 'query', }); if (!this.isSupportSql) { this.querySize!.textContent = this.querySqlErrorText; this.queryTableEl!.dataSource = []; this.response!.innerHTML = ''; return; } this.progressLoad!.loading = true; let startData = new Date().getTime(); this.getInputSqlResult(this.selector!.value).then((resultList) => { let dur = new Date().getTime() - startData; this.statDataArray = []; this.keyList = []; for (let index = 0; index < resultList.length; index++) { const dataResult = resultList[index]; let keys = Object.keys(dataResult); // @ts-ignore let values = Object.values(dataResult); let jsonText = '{'; for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) { let key = keys[keyIndex]; if (this.keyList.indexOf(key) <= -1) { this.keyList.push(key); } let value = values[keyIndex]; if (typeof value == 'string') { value = value.replace(//gi, '>'); } jsonText += '"' + key + '"' + ': ' + '"' + value + '"'; if (keyIndex != keys.length - 1) { jsonText += ','; } else { jsonText += '}'; } } this.statDataArray.push(JSON.parse(jsonText)); } this.queryTableEl!.innerHTML = ''; this.queryText = this.selector!.value; this.initDataElement(); this.response!.appendChild(this.queryTableEl!); setTimeout(() => { let total = this.statDataArray.length; if (total > this.maxPageSize) { that.pagination!.style.opacity = '1'; new PageNation(this.pagination, { current: 1, total: total, pageSize: this.pageSize, change(num: number) { that.sliceData = that.statDataArray!.slice((num - 1) * that.pageSize, num * that.pageSize); that.queryTableEl!.recycleDataSource = that.sliceData; }, }); } else { that.pagination!.style.opacity = '0'; this.queryTableEl!.recycleDataSource = this.statDataArray; } this.freshTableHeadResizeStyle(); new ResizeObserver(() => { if (this.parentElement?.clientHeight != 0) { this.queryTableEl!.style.height = '100%'; this.queryTableEl!.reMeauseHeight(); } }).observe(this.parentElement!); info('metric query Sql result Data size is: ', this.statDataArray!.length); this.initData(); this.progressLoad!.loading = false; }, 200); }); } }; reset() { this.pagination!.style.opacity = '0'; this.response!.innerHTML = ''; this.keyList = []; this.statDataArray = []; this.selector!.value = ''; this.querySize!.textContent = 'Query result - ' + ' 0 counts'; this.resizeSqlHeight().then(() => {}); } initDataTableStyle(styleTable: HTMLDivElement): void { for (let index = 0; index < styleTable.children.length; index++) { // @ts-ignore styleTable.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)'; } } async initMetricData(): Promise { if (!this.selector || this.selector.value == null) { return []; } if (this.queryText == '' || this.queryText == null) { let statList = await querySelectTraceStats(); for (let index = 0; index < statList.length; index++) { const statsResult = statList[index]; let indexArray = { event_name: statsResult.event_name, start_type: statsResult.stat_type, count: statsResult.count, serverity: statsResult.serverity, source: statsResult.source, }; } if (this.querySize) { this.querySize!.textContent = 'Query result - ' + statList.length + ' counts'; } this.resultText = 'Query result - ' + statList.length + ' counts'; } else { return this.statDataArray; } } checkSupportSqlAbility(): boolean { let noSupportChart = ['insert', 'delete', 'update', 'drop', 'alter', 'truncate', 'create']; let result = noSupportChart.filter((item) => { return this.selector!.value.indexOf(item) > -1; }); if (result.length > 0) { this.querySqlErrorText = 'Error: Statement contains a change action keyword,The change operation is not supported.'; this.isSupportSql = false; return true; } else { return false; } } checkSafetySelectSql(): boolean { let split = this.selector?.value.trim().split(' '); if (split) { this.querySqlErrorText = 'Error: Incomplete query statement: ' + this.selector!.value; this.isSupportSql = false; return !split[0].toLowerCase().startsWith('select'); } return false; } getSelectSqlField(): string { if (this.selector!.value.indexOf('from') < 0) { return ''; } let splitSql = this.selector?.value.split('from'); if (splitSql) { if (splitSql[0].indexOf('*') > -1) { return '*'; } else { let fields = splitSql[0].split(','); return fields[0]; } } return ''; } getSelectSqlTableName(str: string): Array { if (this.selector!.value.indexOf(str) < 0) { return []; } let tableNameList = []; let splitSql = this.selector?.value.split(str); if (splitSql) { for (let index = 1; index < splitSql?.length; index++) { let splitSqlItem = splitSql[index].trim(); let tableItem = splitSqlItem.split(' '); let tableName = tableItem[0].trim(); tableNameList.push(tableName); if (tableName.indexOf('(') >= 0) { tableNameList.pop(); } else if (tableName.indexOf(')') >= 0) { tableNameList.pop(); let unitTableName = tableName.split(')'); let tableNewName = unitTableName[0]; tableNameList.push(tableNewName); } } } return tableNameList; } initDataElement() { if (this.keyList) { info('Metric query Table Colum size is: ', this.keyList.length); this.keyList.forEach((item) => { let htmlElement = document.createElement('lit-table-column') as LitTableColumn; htmlElement.setAttribute('title', item); htmlElement.setAttribute('data-index', item); htmlElement.setAttribute('key', item); htmlElement.setAttribute('align', 'flex-start'); htmlElement.setAttribute('height', '32px'); this.queryTableEl!.appendChild(htmlElement); }); } } connectedCallback() { let selectQuery = this.shadowRoot?.querySelector('.query_select'); if (selectQuery) { let querySql = selectQuery.textContent; } // Listen to the sql execution of the query this.addEventListener('keydown', this.selectEventListener); this.selector!.addEventListener('input', this.inputSqlListener); this.selector!.addEventListener('change', this.inputSqlListener); this.selector!.addEventListener('keydown', this.deleteSqlListener); } deleteSqlListener = (event: KeyboardEvent) => { if (event.key == 'Backspace') { this.resizeSqlHeight().then(() => {}); } }; async resizeSqlHeight() { let valueLength = this.selector?.value.split('\n').length; let rowNumber = Number(valueLength) - 1; let selectHeight = '3.2em'; if (rowNumber > 0) { if (rowNumber <= 10) { let allLength = 1.2 * rowNumber + 2; selectHeight = allLength + 'em'; } else { selectHeight = '14em'; } } // @ts-ignore this.selector?.style.height = selectHeight; } inputSqlListener = async (event: Event) => { this.resizeSqlHeight().then(() => {}); let startData = new Date().getTime(); if (this.selector!.value.trim() == '') { this.querySqlErrorText = 'Please enter a query'; this.querySize!.textContent = this.querySqlErrorText; return; } this.checkSafetySelectSql(); this.checkSupportSqlAbility(); if (this.selector!.value.length < 15) { return; } this.querySelectTables = this.getSelectSqlTableName('from') .concat(this.getSelectSqlTableName('join')) .toLocaleString(); info('metric query sql table size is: ', this.querySelectTables.length); this.isSupportSql = true; }; async getInputSqlResult(sql: string): Promise { return await queryCustomizeSelect(sql); } disconnectedCallback() { this.removeEventListener('keydown', this.selectEventListener); this.selector!.removeEventListener('input', this.inputSqlListener); this.selector!.removeEventListener('change', this.inputSqlListener); this.selector!.removeEventListener('keydown', this.deleteSqlListener); } initData() { if (this.statDataArray.length > 0) { this.querySize!.textContent = 'Error: ' + this.selector?.value; } if (this.isSupportSql) { let sqlField = this.keyList?.length == 0 ? '*' : this.keyList?.toLocaleString(); this.querySize!.textContent = 'Query result - ' + this.statDataArray.length + ' counts'; } else { this.querySize!.textContent = this.querySqlErrorText; } let queryHeadStyle: HTMLDivElement | undefined | null = this.queryTableEl?.shadowRoot?.querySelector( 'div.th' ) as HTMLDivElement; if (queryHeadStyle && queryHeadStyle.hasChildNodes()) { for (let index = 0; index < queryHeadStyle.children.length; index++) { // @ts-ignore queryHeadStyle.children[index].style.gridArea = null; } } this.queryTableEl!.style.height = '100%'; } static get observedAttributes() { return ['queryStr']; } attributeChangedCallback(name: string, oldValue: string, newValue: string) { let queryDataSty: HTMLDivElement | undefined | null = this.queryTableEl?.shadowRoot?.querySelector( 'div.tbody' ) as HTMLDivElement; if (queryDataSty && queryDataSty.hasChildNodes()) { for (let index = 0; index < queryDataSty.children.length; index++) { // @ts-ignore queryDataSty.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)'; } } } private _queryStr?: string; get queryStr(): string { return this.queryStr; } set queryStr(value: string) { this._queryStr = value; } initHtml(): string { return `

Enter query and press cmd/ctrl + Enter

Query result - 0 counts

`; } }