From 6af21b8bae064dd2316dfabad57391dfb12f13c7 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 8 Apr 2021 14:30:35 +0200 Subject: [PATCH] nosql queries --- packages/api/src/proc/sessionProcess.js | 6 +- packages/api/src/shell/requirePlugin.js | 2 +- packages/datalib/src/CollectionGridDisplay.ts | 114 +++++++++--------- packages/datalib/src/JslGridDisplay.ts | 44 ++++--- packages/web/src/datagrid/JslDataGrid.svelte | 15 ++- .../web/src/datagrid/JslDataGridCore.svelte | 2 +- packages/web/src/query/ResultTabs.svelte | 1 + packages/web/src/tabs/QueryTab.svelte | 51 +++++--- 8 files changed, 137 insertions(+), 98 deletions(-) diff --git a/packages/api/src/proc/sessionProcess.js b/packages/api/src/proc/sessionProcess.js index 6e71ba4f..4dae1f2b 100644 --- a/packages/api/src/proc/sessionProcess.js +++ b/packages/api/src/proc/sessionProcess.js @@ -17,12 +17,12 @@ let afterConnectCallbacks = []; // let currentHandlers = []; class TableWriter { - constructor(columns, resultIndex) { + constructor(structure, resultIndex) { this.jslid = uuidv1(); this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`); this.currentRowCount = 0; this.currentChangeIndex = 1; - fs.writeFileSync(this.currentFile, JSON.stringify({ columns }) + '\n'); + fs.writeFileSync(this.currentFile, JSON.stringify(structure) + '\n'); this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' }); this.writeCurrentStats(false, false); this.resultIndex = resultIndex; @@ -92,7 +92,7 @@ class StreamHandler { recordset(columns) { this.closeCurrentWriter(); - this.currentWriter = new TableWriter(columns, this.resultIndexHolder.value); + this.currentWriter = new TableWriter(Array.isArray(columns) ? { columns } : columns, this.resultIndexHolder.value); this.resultIndexHolder.value += 1; // this.writeCurrentStats(); diff --git a/packages/api/src/shell/requirePlugin.js b/packages/api/src/shell/requirePlugin.js index cee58693..3eef6cb6 100644 --- a/packages/api/src/shell/requirePlugin.js +++ b/packages/api/src/shell/requirePlugin.js @@ -21,7 +21,7 @@ function requirePlugin(packageName, requiredPlugin = null) { // @ts-ignore module = __non_webpack_require__(modulePath); } catch (err) { - console.error('Failed load webpacked module', err); + console.log('Failed load webpacked module', err.message); module = require(modulePath); } requiredPlugin = module.__esModule ? module.default : module; diff --git a/packages/datalib/src/CollectionGridDisplay.ts b/packages/datalib/src/CollectionGridDisplay.ts index 3d89bd9a..8f54c2f1 100644 --- a/packages/datalib/src/CollectionGridDisplay.ts +++ b/packages/datalib/src/CollectionGridDisplay.ts @@ -25,6 +25,62 @@ function createHeaderText(path) { return res; } +function getColumnsForObject(basePath, obj, res: any[], display) { + for (const name of getObjectKeys(obj)) { + const uniqueName = [...basePath, name].join('.'); + let column = res.find(x => x.uniqueName == uniqueName); + if (!column) { + column = getDisplayColumn(basePath, name, display); + if (basePath.length > 0) { + const lastIndex1 = _.findLastIndex(res, x => x.parentHeaderText.startsWith(column.parentHeaderText)); + const lastIndex2 = _.findLastIndex(res, x => x.headerText == column.parentHeaderText); + // console.log(uniqueName, lastIndex1, lastIndex2); + if (lastIndex1 >= 0) res.splice(lastIndex1 + 1, 0, column); + else if (lastIndex2 >= 0) res.splice(lastIndex2 + 1, 0, column); + else res.push(column); + } else { + res.push(column); + } + } + if (_.isPlainObject(obj[name]) || _.isArray(obj[name])) { + column.isExpandable = true; + } + + if (display.isExpandedColumn(column.uniqueName)) { + getColumnsForObject([...basePath, name], obj[name], res, display); + } + } +} + +function getDisplayColumn(basePath, columnName, display) { + const uniquePath = [...basePath, columnName]; + const uniqueName = uniquePath.join('.'); + return { + columnName, + headerText: createHeaderText(uniquePath), + uniqueName, + uniquePath, + isStructured: true, + parentHeaderText: createHeaderText(basePath), + filterType: 'mongo', + pureName: display.collection?.pureName, + schemaName: display.collection?.schemaName, + }; +} + +export function analyseCollectionDisplayColumns(rows, display) { + const res = []; + for (const row of rows || []) { + getColumnsForObject([], row, res, display); + } + return ( + res.map(col => ({ + ...col, + isChecked: display.isColumnChecked(col), + })) || [] + ); +} + export class CollectionGridDisplay extends GridDisplay { constructor( public collection: CollectionInfo, @@ -36,7 +92,7 @@ export class CollectionGridDisplay extends GridDisplay { loadedRows ) { super(config, setConfig, cache, setCache, driver); - this.columns = this.getDisplayColumns(loadedRows || []); + this.columns = analyseCollectionDisplayColumns(loadedRows, this); this.filterable = true; this.sortable = true; this.editable = true; @@ -45,60 +101,4 @@ export class CollectionGridDisplay extends GridDisplay { this.changeSetKeyFields = ['_id']; this.baseCollection = collection; } - - getDisplayColumns(rows) { - const res = []; - for (const row of rows) { - this.getColumnsForObject([], row, res); - } - return ( - res.map(col => ({ - ...col, - isChecked: this.isColumnChecked(col), - })) || [] - ); - } - - getColumnsForObject(basePath, obj, res: any[]) { - for (const name of getObjectKeys(obj)) { - const uniqueName = [...basePath, name].join('.'); - let column = res.find(x => x.uniqueName == uniqueName); - if (!column) { - column = this.getDisplayColumn(basePath, name); - if (basePath.length > 0) { - const lastIndex1 = _.findLastIndex(res, x => x.parentHeaderText.startsWith(column.parentHeaderText)); - const lastIndex2 = _.findLastIndex(res, x => x.headerText == column.parentHeaderText); - // console.log(uniqueName, lastIndex1, lastIndex2); - if (lastIndex1 >= 0) res.splice(lastIndex1 + 1, 0, column); - else if (lastIndex2 >= 0) res.splice(lastIndex2 + 1, 0, column); - else res.push(column); - } else { - res.push(column); - } - } - if (_.isPlainObject(obj[name]) || _.isArray(obj[name])) { - column.isExpandable = true; - } - - if (this.isExpandedColumn(column.uniqueName)) { - this.getColumnsForObject([...basePath, name], obj[name], res); - } - } - } - - getDisplayColumn(basePath, columnName) { - const uniquePath = [...basePath, columnName]; - const uniqueName = uniquePath.join('.'); - return { - columnName, - headerText: createHeaderText(uniquePath), - uniqueName, - uniquePath, - isStructured: true, - parentHeaderText: createHeaderText(basePath), - filterType: 'mongo', - pureName: this.collection.pureName, - schemaName: this.collection.schemaName, - }; - } } diff --git a/packages/datalib/src/JslGridDisplay.ts b/packages/datalib/src/JslGridDisplay.ts index 01130676..8341a5e2 100644 --- a/packages/datalib/src/JslGridDisplay.ts +++ b/packages/datalib/src/JslGridDisplay.ts @@ -1,34 +1,44 @@ import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay'; import { QueryResultColumn } from 'dbgate-types'; import { GridConfig, GridCache } from './GridConfig'; +import { analyseCollectionDisplayColumns } from './CollectionGridDisplay'; export class JslGridDisplay extends GridDisplay { constructor( jslid, - columns: QueryResultColumn[], + structure, config: GridConfig, setConfig: ChangeConfigFunc, cache: GridCache, - setCache: ChangeCacheFunc + setCache: ChangeCacheFunc, + rows: any ) { super(config, setConfig, cache, setCache, null); this.filterable = true; - this.columns = columns - .map(col => ({ - columnName: col.columnName, - headerText: col.columnName, - uniqueName: col.columnName, - uniquePath: [col.columnName], - notNull: col.notNull, - autoIncrement: col.autoIncrement, - pureName: null, - schemaName: null, - })) - ?.map(col => ({ - ...col, - isChecked: this.isColumnChecked(col), - })); + if (structure.columns) { + this.columns = structure.columns + .map(col => ({ + columnName: col.columnName, + headerText: col.columnName, + uniqueName: col.columnName, + uniquePath: [col.columnName], + notNull: col.notNull, + autoIncrement: col.autoIncrement, + pureName: null, + schemaName: null, + })) + ?.map(col => ({ + ...col, + isChecked: this.isColumnChecked(col), + })); + } + + if (structure.__isDynamicStructure) { + this.columns = analyseCollectionDisplayColumns(rows, this); + } + + if (!this.columns) this.columns = []; } } diff --git a/packages/web/src/datagrid/JslDataGrid.svelte b/packages/web/src/datagrid/JslDataGrid.svelte index 3f17d79d..1953f5a4 100644 --- a/packages/web/src/datagrid/JslDataGrid.svelte +++ b/packages/web/src/datagrid/JslDataGrid.svelte @@ -10,20 +10,27 @@ export let jslid; + let loadedRows; + $: info = useFetch({ params: { jslid }, url: 'jsldata/get-info', defaultValue: {}, }); - $: columns = ($info && $info.columns) || []; + // $: columns = ($info && $info.columns) || []; const config = writable(createGridConfig()); const cache = writable(createGridCache()); - $: display = new JslGridDisplay(jslid, columns, $config, config.update, $cache, cache.update); - + $: display = new JslGridDisplay(jslid, $info, $config, config.update, $cache, cache.update, loadedRows); {#key jslid} - + {/key} diff --git a/packages/web/src/datagrid/JslDataGridCore.svelte b/packages/web/src/datagrid/JslDataGridCore.svelte index 23b404b7..b2f8fd2d 100644 --- a/packages/web/src/datagrid/JslDataGridCore.svelte +++ b/packages/web/src/datagrid/JslDataGridCore.svelte @@ -60,7 +60,7 @@ export const activator = createActivator('JslDataGridCore', false); - let loadedRows = []; + export let loadedRows = []; let domGrid; let changeIndex = 0; diff --git a/packages/web/src/query/ResultTabs.svelte b/packages/web/src/query/ResultTabs.svelte index 5e85cfbd..55bf3111 100644 --- a/packages/web/src/query/ResultTabs.svelte +++ b/packages/web/src/query/ResultTabs.svelte @@ -36,6 +36,7 @@ $: { if (executeNumber >= 0) { resultInfos = []; + if (domTabs) domTabs.setValue(0); } } diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index aba6db1e..2a87a9e7 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -5,7 +5,7 @@ id: 'query.formatCode', category: 'Query', name: 'Format code', - testEnabled: () => getCurrentEditor() != null, + testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().formatCode(), }); registerCommand({ @@ -13,7 +13,7 @@ category: 'Query', name: 'Insert SQL Join', keyText: 'Ctrl+J', - testEnabled: () => getCurrentEditor() != null, + testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().insertSqlJoin(), }); registerFileCommands({ @@ -54,6 +54,8 @@ import InsertJoinModal from '../modals/InsertJoinModal.svelte'; import useTimerLabel from '../utility/useTimerLabel'; import createActivator, { getActiveComponent } from '../utility/createActivator'; + import { findEngineDriver } from 'dbgate-tools'; + import AceEditor from '../query/AceEditor.svelte'; export let tabid; export let conid; @@ -73,6 +75,7 @@ let domEditor; $: connection = useConnectionInfo({ conid }); + $: driver = findEngineDriver($connection, $extensions); $: effect = useEffect(() => { return onSession(sessionId); @@ -102,6 +105,10 @@ domEditor?.getEditor()?.focus(); } + export function isSqlEditor() { + return !driver?.dialect?.nosql; + } + export function canKill() { return !!sessionId; } @@ -225,19 +232,33 @@ - setEditorData(e.detail)} - on:focus={() => { - activator.activate(); - invalidateCommands(); - }} - bind:this={domEditor} - /> + {#if driver?.dialect?.nosql} + setEditorData(e.detail)} + on:focus={() => { + activator.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + /> + {:else} + setEditorData(e.detail)} + on:focus={() => { + activator.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + /> + {/if}