mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 05:03:57 +00:00
query history - prepare
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
"express-basic-auth": "^1.2.0",
|
||||
"express-fileupload": "^1.2.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"fs-reverse": "^0.0.3",
|
||||
"get-port": "^5.1.1",
|
||||
"http": "^0.0.0",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
@@ -71,4 +72,4 @@
|
||||
"optionalDependencies": {
|
||||
"msnodesqlv8": "^2.0.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
packages/api/src/controllers/queryHistory.js
Normal file
45
packages/api/src/controllers/queryHistory.js
Normal file
@@ -0,0 +1,45 @@
|
||||
const fsReverse = require('fs-reverse');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const { datadir } = require('../utility/directories');
|
||||
const _ = require('lodash');
|
||||
const { filterName } = require('dbgate-tools');
|
||||
|
||||
function readCore(reader, skip, limit, filter) {
|
||||
return new Promise(resolve => {
|
||||
const res = [];
|
||||
let readed = 0;
|
||||
reader.on('data', line => {
|
||||
const json = JSON.parse(line);
|
||||
if (filterName(filter, json.sql)) {
|
||||
if (!skip || readed >= skip) {
|
||||
res.push(json);
|
||||
}
|
||||
readed++;
|
||||
if (limit && readed > (skip || 0) + limit) {
|
||||
reader.destroy();
|
||||
resolve(res);
|
||||
}
|
||||
}
|
||||
});
|
||||
reader.on('end', () => resolve(res));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
read_meta: 'get',
|
||||
async read({ skip, limit, filter }) {
|
||||
const fileName = path.join(datadir(), 'query-history.jsonl');
|
||||
// @ts-ignore
|
||||
if (!(await fs.exists(fileName))) return [];
|
||||
const reader = fsReverse(fileName);
|
||||
const res = await readCore(reader, skip, limit, filter);
|
||||
return res;
|
||||
},
|
||||
|
||||
write_meta: 'post',
|
||||
async write({ data }) {
|
||||
const fileName = path.join(datadir(), 'query-history.jsonl');
|
||||
await fs.appendFile(fileName, JSON.stringify(data) + '\n');
|
||||
},
|
||||
};
|
||||
@@ -27,6 +27,7 @@ const uploads = require('./controllers/uploads');
|
||||
const plugins = require('./controllers/plugins');
|
||||
const files = require('./controllers/files');
|
||||
const scheduler = require('./controllers/scheduler');
|
||||
const queryHistory = require('./controllers/queryHistory');
|
||||
|
||||
const { rundir } = require('./utility/directories');
|
||||
const platformInfo = require('./utility/platformInfo');
|
||||
@@ -102,6 +103,7 @@ function start() {
|
||||
useController(app, '/plugins', plugins);
|
||||
useController(app, '/files', files);
|
||||
useController(app, '/scheduler', scheduler);
|
||||
useController(app, '/query-history', queryHistory);
|
||||
|
||||
// if (process.env.PAGES_DIRECTORY) {
|
||||
// app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import { GridConfig, GridCache, GridConfigColumns, createGridCache, GroupFunc } from './GridConfig';
|
||||
import {
|
||||
ForeignKeyInfo,
|
||||
TableInfo,
|
||||
ColumnInfo,
|
||||
EngineDriver,
|
||||
NamedObjectInfo,
|
||||
DatabaseInfo,
|
||||
SqlDialect,
|
||||
} from 'dbgate-types';
|
||||
import { parseFilter, getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
|
||||
import { filterName } from './filterName';
|
||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||
import { Expression, Select, treeToSql, dumpSqlSelect, Condition } from 'dbgate-sqltree';
|
||||
import { isTypeLogical } from 'dbgate-tools';
|
||||
import { TableInfo, EngineDriver, DatabaseInfo, SqlDialect } from 'dbgate-types';
|
||||
import { getFilterValueExpression } from 'dbgate-filterparser';
|
||||
import { ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay';
|
||||
|
||||
export class FormViewDisplay {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
SqlDialect,
|
||||
} from 'dbgate-types';
|
||||
import { parseFilter, getFilterType } from 'dbgate-filterparser';
|
||||
import { filterName } from './filterName';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||
import { Expression, Select, treeToSql, dumpSqlSelect, Condition } from 'dbgate-sqltree';
|
||||
import { isTypeLogical } from 'dbgate-tools';
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
Condition,
|
||||
OrderByExpression,
|
||||
} from 'dbgate-sqltree';
|
||||
import { filterName } from './filterName';
|
||||
import { TableGridDisplay } from './TableGridDisplay';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import _ from 'lodash';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay';
|
||||
import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
|
||||
import { GridConfig, GridCache, createGridCache } from './GridConfig';
|
||||
import { Expression, Select, treeToSql, dumpSqlSelect } from 'dbgate-sqltree';
|
||||
import { filterName } from './filterName';
|
||||
|
||||
export class TableGridDisplay extends GridDisplay {
|
||||
public table: TableInfo;
|
||||
|
||||
@@ -4,7 +4,6 @@ export * from './TableGridDisplay';
|
||||
export * from './ViewGridDisplay';
|
||||
export * from './JslGridDisplay';
|
||||
export * from './ChangeSet';
|
||||
export * from './filterName';
|
||||
export * from './FreeTableGridDisplay';
|
||||
export * from './FreeTableModel';
|
||||
export * from './MacroDefinition';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from 'lodash';
|
||||
import _compact from 'lodash/compact';
|
||||
|
||||
// original C# variant
|
||||
// public bool Match(string value)
|
||||
@@ -39,6 +39,6 @@ export function filterName(filter: string, ...names: string[]) {
|
||||
// const camelVariants = [name.replace(/[^A-Z]/g, '')]
|
||||
const tokens = filter.split(' ').map(x => x.trim());
|
||||
|
||||
return !!_.compact(names).find(name => !tokens.find(token => !name.toUpperCase().includes(token.toUpperCase())));
|
||||
return !!_compact(names).find(name => !tokens.find(token => !name.toUpperCase().includes(token.toUpperCase())));
|
||||
// return name.toUpperCase().includes(filter.toUpperCase());
|
||||
}
|
||||
@@ -10,3 +10,4 @@ export * from './testPermission';
|
||||
export * from './SqlGenerator';
|
||||
export * from './structureTools';
|
||||
export * from './settingsExtractors';
|
||||
export * from './filterName';
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
export let subItemsComponent = undefined;
|
||||
export let expandOnClick = false;
|
||||
export let isExpandable = undefined;
|
||||
export let filter;
|
||||
export let filter = undefined;
|
||||
export let expandIconFunc = undefined;
|
||||
export let checkedObjectsStore = null;
|
||||
export let disableContextMenu = false;
|
||||
@@ -34,6 +34,7 @@
|
||||
: null;
|
||||
|
||||
$: groups = groupFunc ? _.groupBy(listGrouped, 'group') : null;
|
||||
|
||||
</script>
|
||||
|
||||
{#if groupFunc}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import { currentArchive } from '../stores';
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import { currentArchive } from '../stores';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import { currentDatabase, extensions, getCurrentConfig, openedConnections } from '../stores';
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { showModal } from '../modals/modalTools';
|
||||
import ConnectionModal from '../modals/ConnectionModal.svelte';
|
||||
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import { currentDatabase, extensions, openedConnections } from '../stores';
|
||||
import openNewTab from '../utility/openNewTab';
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { getConnectionInfo } from '../utility/metadataLoaders';
|
||||
import fullDisplayName from '../utility/fullDisplayName';
|
||||
import ImportExportModal from '../modals/ImportExportModal.svelte';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { filterName, GridDisplay } from 'dbgate-datalib';
|
||||
import { GridDisplay } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import InlineButton from '../elements/InlineButton.svelte';
|
||||
import ManagerInnerContainer from '../elements/ManagerInnerContainer.svelte';
|
||||
@@ -13,6 +14,7 @@
|
||||
export let isJsonView = false;
|
||||
|
||||
let filter;
|
||||
|
||||
</script>
|
||||
|
||||
<SearchBoxWrapper>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { filterName, GridDisplay } from 'dbgate-datalib';
|
||||
import { GridDisplay } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
import InlineButton from '../elements/InlineButton.svelte';
|
||||
@@ -12,7 +13,7 @@
|
||||
|
||||
export let managerSize;
|
||||
export let display: GridDisplay;
|
||||
export let onReferenceClick = (ref) => {};
|
||||
export let onReferenceClick = ref => {};
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
$: foreignKeys = display?.baseTable?.foreignKeys || [];
|
||||
$: dependencies = display?.baseTable?.dependencies || [];
|
||||
|
||||
</script>
|
||||
|
||||
<SearchBoxWrapper>
|
||||
@@ -86,4 +88,5 @@
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
findReplace: true,
|
||||
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection(),
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -143,9 +144,18 @@
|
||||
}
|
||||
busy = true;
|
||||
timerLabel.start();
|
||||
const sql = selectedText || $editorValue;
|
||||
await axiosInstance.post('sessions/execute-query', {
|
||||
sesid,
|
||||
sql: selectedText || $editorValue,
|
||||
sql,
|
||||
});
|
||||
await axiosInstance.post('query-history/write', {
|
||||
data: {
|
||||
sql,
|
||||
conid,
|
||||
database,
|
||||
date: new Date().getTime(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,6 +243,7 @@
|
||||
{ command: 'query.replace' },
|
||||
];
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<VerticalSplitter isSplitter={visibleResultTabs}>
|
||||
|
||||
@@ -3,9 +3,30 @@
|
||||
|
||||
import WidgetColumnBar from './WidgetColumnBar.svelte';
|
||||
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
|
||||
|
||||
import AppObjectList from '../appobj/AppObjectList.svelte';
|
||||
import * as closedTabAppObject from '../appobj/ClosedTabAppObject.svelte';
|
||||
import * as favoriteFileAppObject from '../appobj/FavoriteFileAppObject.svelte';
|
||||
import { openedTabs } from '../stores';
|
||||
|
||||
import hasPermission from '../utility/hasPermission';
|
||||
import { useFavorites } from '../utility/metadataLoaders';
|
||||
|
||||
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
|
||||
|
||||
$: favorites = useFavorites();
|
||||
|
||||
</script>
|
||||
|
||||
<WidgetColumnBar>
|
||||
{#if hasPermission('files/favorites/read')}
|
||||
<WidgetColumnBarItem title="Favorites" name="favorites" height="20%">
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList list={$favorites || []} module={favoriteFileAppObject} />
|
||||
</WidgetsInnerContainer>
|
||||
</WidgetColumnBarItem>
|
||||
{/if}
|
||||
|
||||
<WidgetColumnBarItem title="Saved files" name="files">
|
||||
<SavedFilesList />
|
||||
</WidgetColumnBarItem>
|
||||
|
||||
@@ -14,16 +14,10 @@
|
||||
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
|
||||
|
||||
$: favorites = useFavorites();
|
||||
|
||||
</script>
|
||||
|
||||
<WidgetColumnBar>
|
||||
{#if hasPermission('files/favorites/read')}
|
||||
<WidgetColumnBarItem title="Favorites" name="favorites" height="20%">
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList list={$favorites || []} module={favoriteFileAppObject} />
|
||||
</WidgetsInnerContainer>
|
||||
</WidgetColumnBarItem>
|
||||
{/if}
|
||||
<WidgetColumnBarItem title="Recently closed tabs" name="closedTabs">
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList
|
||||
@@ -4,8 +4,9 @@
|
||||
import DatabaseWidget from './DatabaseWidget.svelte';
|
||||
import FilesWidget from './FilesWidget.svelte';
|
||||
import PluginsWidget from './PluginsWidget.svelte';
|
||||
import FavoritesWidget from './FavoritesWidget.svelte';
|
||||
import CellDataWidget from './CellDataWidget.svelte';
|
||||
import CellDataWidget from './CellDataWidget.svelte';
|
||||
import HistoryWidget from './HistoryWidget.svelte';
|
||||
|
||||
</script>
|
||||
|
||||
{#if $selectedWidget == 'database'}
|
||||
@@ -14,15 +15,15 @@ import CellDataWidget from './CellDataWidget.svelte';
|
||||
{#if $selectedWidget == 'file'}
|
||||
<FilesWidget />
|
||||
{/if}
|
||||
{#if $selectedWidget == 'history'}
|
||||
<HistoryWidget />
|
||||
{/if}
|
||||
{#if $selectedWidget == 'archive'}
|
||||
<ArchiveWidget />
|
||||
{/if}
|
||||
{#if $selectedWidget == 'plugins'}
|
||||
<PluginsWidget />
|
||||
{/if}
|
||||
{#if $selectedWidget == 'favorites'}
|
||||
<FavoritesWidget />
|
||||
{/if}
|
||||
{#if $selectedWidget == 'cell-data'}
|
||||
<CellDataWidget />
|
||||
{/if}
|
||||
|
||||
@@ -18,7 +18,12 @@
|
||||
{
|
||||
icon: 'icon file',
|
||||
name: 'file',
|
||||
title: 'Closed tabs & Saved SQL files',
|
||||
title: 'Favorites & Saved files',
|
||||
},
|
||||
{
|
||||
icon: 'icon history',
|
||||
name: 'history',
|
||||
title: 'Query history & Closed tabs',
|
||||
},
|
||||
{
|
||||
icon: 'icon archive',
|
||||
@@ -30,11 +35,6 @@
|
||||
name: 'plugins',
|
||||
title: 'Extensions & Plugins',
|
||||
},
|
||||
{
|
||||
icon: 'icon favorite',
|
||||
name: 'favorites',
|
||||
title: 'Favorites',
|
||||
},
|
||||
{
|
||||
icon: 'icon cell-data',
|
||||
name: 'cell-data',
|
||||
|
||||
Reference in New Issue
Block a user