mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
mong support WIP
This commit is contained in:
parent
d4bd6e03c9
commit
394c6028c9
@ -92,6 +92,13 @@ module.exports = {
|
||||
return res;
|
||||
},
|
||||
|
||||
collectionData_meta: 'post',
|
||||
async collectionData({ conid, database, options }) {
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
|
||||
return res;
|
||||
},
|
||||
|
||||
status_meta: 'get',
|
||||
async status({ conid, database }) {
|
||||
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
||||
|
@ -17,7 +17,7 @@ module.exports = {
|
||||
listObjects_meta: 'get',
|
||||
async listObjects({ conid, database }) {
|
||||
const opened = await databaseConnections.ensureOpened(conid, database);
|
||||
const types = ['tables', 'views', 'procedures', 'functions', 'triggers'];
|
||||
const types = ['tables', 'collections', 'views', 'procedures', 'functions', 'triggers'];
|
||||
return types.reduce(
|
||||
(res, type) => ({
|
||||
...res,
|
||||
|
@ -94,6 +94,17 @@ async function handleQueryData({ msgid, sql }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCollectionData({ msgid, options }) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
try {
|
||||
const result = await driver.readCollection(systemConnection, options);
|
||||
process.send({ msgtype: 'response', msgid, result });
|
||||
} catch (err) {
|
||||
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSqlPreview({ msgid, objects, options }) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
@ -129,6 +140,7 @@ function handlePing() {
|
||||
const messageHandlers = {
|
||||
connect: handleConnect,
|
||||
queryData: handleQueryData,
|
||||
collectionData: handleCollectionData,
|
||||
sqlPreview: handleSqlPreview,
|
||||
ping: handlePing,
|
||||
// runCommand: handleRunCommand,
|
||||
|
46
packages/datalib/src/CollectionGridDisplay.ts
Normal file
46
packages/datalib/src/CollectionGridDisplay.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import _ from 'lodash';
|
||||
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
|
||||
import { EngineDriver, ViewInfo, ColumnInfo, CollectionInfo } from 'dbgate-types';
|
||||
import { GridConfig, GridCache } from './GridConfig';
|
||||
|
||||
export class CollectionGridDisplay extends GridDisplay {
|
||||
constructor(
|
||||
public collection: CollectionInfo,
|
||||
driver: EngineDriver,
|
||||
config: GridConfig,
|
||||
setConfig: ChangeConfigFunc,
|
||||
cache: GridCache,
|
||||
setCache: ChangeCacheFunc
|
||||
) {
|
||||
super(config, setConfig, cache, setCache, driver);
|
||||
this.columns = [];
|
||||
this.filterable = true;
|
||||
this.sortable = true;
|
||||
this.editable = false;
|
||||
this.supportsReload = true;
|
||||
}
|
||||
|
||||
// getDisplayColumns(view: ViewInfo) {
|
||||
// return (
|
||||
// view?.columns
|
||||
// ?.map(col => this.getDisplayColumn(view, col))
|
||||
// ?.map(col => ({
|
||||
// ...col,
|
||||
// isChecked: this.isColumnChecked(col),
|
||||
// })) || []
|
||||
// );
|
||||
// }
|
||||
|
||||
// getDisplayColumn(view: ViewInfo, col: ColumnInfo) {
|
||||
// const uniquePath = [col.columnName];
|
||||
// const uniqueName = uniquePath.join('.');
|
||||
// return {
|
||||
// ...col,
|
||||
// pureName: view.pureName,
|
||||
// schemaName: view.schemaName,
|
||||
// headerText: col.columnName,
|
||||
// uniqueName,
|
||||
// uniquePath,
|
||||
// };
|
||||
// }
|
||||
}
|
@ -49,7 +49,7 @@ export class DatabaseAnalyser {
|
||||
}
|
||||
|
||||
const res = {};
|
||||
for (const field of ['tables', 'views', 'functions', 'procedures', 'triggers']) {
|
||||
for (const field of ['tables', 'collections', 'views', 'functions', 'procedures', 'triggers']) {
|
||||
const removedIds = this.modifications
|
||||
.filter(x => x.action == 'remove' && x.objectTypeField == field)
|
||||
.map(x => extractObjectId(x));
|
||||
@ -78,6 +78,7 @@ export class DatabaseAnalyser {
|
||||
static createEmptyStructure(): DatabaseInfo {
|
||||
return {
|
||||
tables: [],
|
||||
collections: [],
|
||||
views: [],
|
||||
functions: [],
|
||||
procedures: [],
|
||||
|
@ -56,6 +56,10 @@ function fillTableExtendedInfo(db: DatabaseInfo): DatabaseInfo {
|
||||
constraintType: 'unique',
|
||||
})),
|
||||
})),
|
||||
collections: (db.collections || []).map(obj => ({
|
||||
...obj,
|
||||
objectTypeField: 'collections',
|
||||
})),
|
||||
views: (db.views || []).map(obj => ({
|
||||
...obj,
|
||||
objectTypeField: 'views',
|
||||
|
3
packages/types/dbinfo.d.ts
vendored
3
packages/types/dbinfo.d.ts
vendored
@ -74,6 +74,8 @@ export interface TableInfo extends DatabaseObjectInfo {
|
||||
checks?: CheckInfo[];
|
||||
}
|
||||
|
||||
export interface CollectionInfo extends DatabaseObjectInfo {}
|
||||
|
||||
export interface ViewInfo extends SqlObjectInfo {
|
||||
columns: ColumnInfo[];
|
||||
}
|
||||
@ -91,6 +93,7 @@ export interface SchemaInfo {
|
||||
|
||||
export interface DatabaseInfoObjects {
|
||||
tables: TableInfo[];
|
||||
collections: CollectionInfo[];
|
||||
views: ViewInfo[];
|
||||
procedures: ProcedureInfo[];
|
||||
functions: FunctionInfo[];
|
||||
|
1
packages/types/dialect.d.ts
vendored
1
packages/types/dialect.d.ts
vendored
@ -8,4 +8,5 @@ export interface SqlDialect {
|
||||
explicitDropConstraint?: boolean;
|
||||
anonymousPrimaryKey?: boolean;
|
||||
enableConstraintsPerTable?: boolean;
|
||||
nosql?: boolean; // mongo
|
||||
}
|
||||
|
9
packages/types/engines.d.ts
vendored
9
packages/types/engines.d.ts
vendored
@ -24,6 +24,14 @@ export interface EngineAuthType {
|
||||
disabledFields: string[];
|
||||
}
|
||||
|
||||
export interface ReadCollectionOptions {
|
||||
pureName: string;
|
||||
schemaName?: string;
|
||||
|
||||
countDocuments?: boolean;
|
||||
skip?: number;
|
||||
limit?: number;
|
||||
}
|
||||
export interface EngineDriver {
|
||||
engine: string;
|
||||
title: string;
|
||||
@ -52,6 +60,7 @@ export interface EngineDriver {
|
||||
dialect: SqlDialect;
|
||||
createDumper(): SqlDumper;
|
||||
getAuthTypes(): EngineAuthType[];
|
||||
readCollection(pool: any, options: ReadCollectionOptions): Promise<any>;
|
||||
|
||||
analyserClass?: any;
|
||||
dumperClass?: any;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
const icons = {
|
||||
tables: 'img table',
|
||||
collections: 'img collection',
|
||||
views: 'img view',
|
||||
procedures: 'img procedure',
|
||||
functions: 'img function',
|
||||
@ -11,6 +12,7 @@
|
||||
|
||||
const defaultTabs = {
|
||||
tables: 'TableDataTab',
|
||||
collections: 'CollectionDataTab',
|
||||
views: 'ViewDataTab',
|
||||
};
|
||||
|
||||
|
189
packages/web/src/datagrid/CollectionDataGridCore.svelte
Normal file
189
packages/web/src/datagrid/CollectionDataGridCore.svelte
Normal file
@ -0,0 +1,189 @@
|
||||
<script context="module" lang="ts">
|
||||
async function loadDataPage(props, offset, limit) {
|
||||
const { conid, database } = props;
|
||||
|
||||
const response = await axiosInstance.request({
|
||||
url: 'database-connections/collection-data',
|
||||
method: 'post',
|
||||
params: {
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
data: {
|
||||
options: {
|
||||
limit,
|
||||
skip: offset,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data.errorMessage) return response.data;
|
||||
return response.data.rows;
|
||||
}
|
||||
|
||||
function dataPageAvailable(props) {
|
||||
const { display } = props;
|
||||
const sql = display.getPageQuery(0, 1);
|
||||
return !!sql;
|
||||
}
|
||||
|
||||
async function loadRowCount(props) {
|
||||
const { conid, database } = props;
|
||||
|
||||
const response = await axiosInstance.request({
|
||||
url: 'database-connections/collection-data',
|
||||
method: 'post',
|
||||
params: {
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
data: {
|
||||
options: {
|
||||
countDocuments: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return response.data.count;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { changeSetToSql, createChangeSet } from 'dbgate-datalib';
|
||||
import { scriptToSql } from 'dbgate-sqltree';
|
||||
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
||||
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
||||
import ImportExportModal from '../modals/ImportExportModal.svelte';
|
||||
import { showModal } from '../modals/modalTools';
|
||||
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
import openNewTab from '../utility/openNewTab';
|
||||
import ChangeSetGrider from './ChangeSetGrider';
|
||||
|
||||
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
|
||||
|
||||
export let conid;
|
||||
export let display;
|
||||
export let database;
|
||||
export let schemaName;
|
||||
export let pureName;
|
||||
export let config;
|
||||
export let changeSetState;
|
||||
export let dispatchChangeSet;
|
||||
|
||||
export let macroPreview;
|
||||
export let macroValues;
|
||||
export let selectedCellsPublished;
|
||||
|
||||
// export let onChangeGrider = undefined;
|
||||
|
||||
let loadedRows = [];
|
||||
|
||||
// $: console.log('loadedRows BIND', loadedRows);
|
||||
$: grider = new ChangeSetGrider(
|
||||
loadedRows,
|
||||
changeSetState,
|
||||
dispatchChangeSet,
|
||||
display,
|
||||
macroPreview,
|
||||
macroValues,
|
||||
selectedCellsPublished
|
||||
);
|
||||
// $: console.log('GRIDER', grider);
|
||||
// $: if (onChangeGrider) onChangeGrider(grider);
|
||||
|
||||
async function handleConfirmSql(sql) {
|
||||
const resp = await axiosInstance.request({
|
||||
url: 'database-connections/query-data',
|
||||
method: 'post',
|
||||
params: {
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
data: { sql },
|
||||
});
|
||||
const { errorMessage } = resp.data || {};
|
||||
if (errorMessage) {
|
||||
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
|
||||
} else {
|
||||
dispatchChangeSet({ type: 'reset', value: createChangeSet() });
|
||||
display.reload();
|
||||
}
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const script = changeSetToSql(changeSetState && changeSetState.value, display.dbinfo);
|
||||
const sql = scriptToSql(display.driver, script);
|
||||
showModal(ConfirmSqlModal, {
|
||||
sql,
|
||||
onConfirm: () => handleConfirmSql(sql),
|
||||
engine: display.engine,
|
||||
});
|
||||
}
|
||||
|
||||
function exportGrid() {
|
||||
const initialValues: any = {};
|
||||
initialValues.sourceStorageType = 'query';
|
||||
initialValues.sourceConnectionId = conid;
|
||||
initialValues.sourceDatabaseName = database;
|
||||
initialValues.sourceSql = display.getExportQuery();
|
||||
initialValues.sourceList = display.baseTable ? [display.baseTable.pureName] : [];
|
||||
showModal(ImportExportModal, { initialValues });
|
||||
}
|
||||
|
||||
function openQuery() {
|
||||
openNewTab(
|
||||
{
|
||||
title: 'Query #',
|
||||
icon: 'img sql-file',
|
||||
tabComponent: 'QueryTab',
|
||||
props: {
|
||||
schemaName: display.baseTable.schemaName,
|
||||
pureName: display.baseTable.pureName,
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
},
|
||||
{
|
||||
editor: display.getExportQuery(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function openActiveChart() {
|
||||
openNewTab(
|
||||
{
|
||||
title: 'Chart #',
|
||||
icon: 'img chart',
|
||||
tabComponent: 'ChartTab',
|
||||
props: {
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
},
|
||||
{
|
||||
editor: {
|
||||
config: { chartType: 'bar' },
|
||||
sql: display.getExportQuery(select => {
|
||||
select.orderBy = null;
|
||||
}),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<LoadingDataGridCore
|
||||
{...$$props}
|
||||
{loadDataPage}
|
||||
{dataPageAvailable}
|
||||
{loadRowCount}
|
||||
onExportGrid={exportGrid}
|
||||
onOpenQuery={openQuery}
|
||||
onOpenActiveChart={openActiveChart}
|
||||
bind:loadedRows
|
||||
frameSelection={!!macroPreview}
|
||||
{grider}
|
||||
onSave={handleSave}
|
||||
isDynamicStructure
|
||||
/>
|
@ -69,7 +69,7 @@
|
||||
name="references"
|
||||
height="30%"
|
||||
collapsed={isDetailView}
|
||||
skip={!showReferences || !display.hasReferences}
|
||||
skip={!showReferences || !display?.hasReferences}
|
||||
>
|
||||
<ReferenceManager {...$$props} {managerSize} />
|
||||
</WidgetColumnBarItem>
|
||||
|
@ -269,6 +269,7 @@
|
||||
export let isLoadedAll;
|
||||
export let loadedTime;
|
||||
export let changeSetStore;
|
||||
export let isDynamicStructure = false;
|
||||
// export let generalAllowSave = false;
|
||||
|
||||
const wheelRowCount = 5;
|
||||
@ -1025,7 +1026,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if !columns || columns.length == 0}
|
||||
{#if !isDynamicStructure && (!columns || columns.length == 0)}
|
||||
<LoadingInfo wrapper message="Waiting for structure" />
|
||||
{:else if errorMessage}
|
||||
<ErrorInfo message={errorMessage} />
|
||||
|
@ -92,6 +92,7 @@
|
||||
|
||||
'img database': 'mdi mdi-database color-icon-gold',
|
||||
'img table': 'mdi mdi-table color-icon-blue',
|
||||
'img collection': 'mdi mdi-table color-icon-red',
|
||||
'img view': 'mdi mdi-table color-icon-magenta',
|
||||
'img procedure': 'mdi mdi-cog color-icon-blue',
|
||||
'img function': 'mdi mdi-function-variant',
|
||||
|
49
packages/web/src/tabs/CollectionDataTab.svelte
Normal file
49
packages/web/src/tabs/CollectionDataTab.svelte
Normal file
@ -0,0 +1,49 @@
|
||||
<script lang="ts" context="module">
|
||||
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
|
||||
export const allowAddToFavorites = props => true;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import App from '../App.svelte';
|
||||
import TableDataGrid from '../datagrid/TableDataGrid.svelte';
|
||||
import useGridConfig from '../utility/useGridConfig';
|
||||
import {
|
||||
createChangeSet,
|
||||
createGridCache,
|
||||
createGridConfig,
|
||||
TableFormViewDisplay,
|
||||
TableGridDisplay,
|
||||
} from 'dbgate-datalib';
|
||||
import { findEngineDriver } from 'dbgate-tools';
|
||||
import { writable } from 'svelte/store';
|
||||
import createUndoReducer from '../utility/createUndoReducer';
|
||||
import invalidateCommands from '../commands/invalidateCommands';
|
||||
|
||||
export let tabid;
|
||||
export let conid;
|
||||
export let database;
|
||||
export let schemaName;
|
||||
export let pureName;
|
||||
|
||||
const config = useGridConfig(tabid);
|
||||
const cache = writable(createGridCache());
|
||||
|
||||
const [changeSetStore, dispatchChangeSet] = createUndoReducer(createChangeSet());
|
||||
|
||||
$: {
|
||||
$changeSetStore;
|
||||
invalidateCommands();
|
||||
}
|
||||
</script>
|
||||
|
||||
<TableDataGrid
|
||||
{...$$props}
|
||||
config={$config}
|
||||
setConfig={config.update}
|
||||
cache={$cache}
|
||||
setCache={cache.update}
|
||||
changeSetState={$changeSetStore}
|
||||
focusOnVisible
|
||||
{changeSetStore}
|
||||
{dispatchChangeSet}
|
||||
/>
|
@ -1,4 +1,5 @@
|
||||
import * as TableDataTab from './TableDataTab.svelte';
|
||||
import * as CollectionDataTab from './CollectionDataTab.svelte';
|
||||
import * as ViewDataTab from './ViewDataTab.svelte';
|
||||
import * as TableStructureTab from './TableStructureTab.svelte';
|
||||
import * as QueryTab from './QueryTab.svelte';
|
||||
@ -15,6 +16,7 @@ import * as QueryDesignTab from './QueryDesignTab.svelte';
|
||||
|
||||
export default {
|
||||
TableDataTab,
|
||||
CollectionDataTab,
|
||||
ViewDataTab,
|
||||
TableStructureTab,
|
||||
QueryTab,
|
||||
|
@ -1,16 +1,24 @@
|
||||
<script lang="ts">
|
||||
<script lang="ts">
|
||||
import { findEngineDriver } from 'dbgate-tools';
|
||||
import { currentDatabase, extensions } from '../stores';
|
||||
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||
|
||||
import ConnectionList from './ConnectionList.svelte';
|
||||
import SqlObjectListWrapper from './SqlObjectListWrapper.svelte';
|
||||
import SqlObjectListWrapper from './SqlObjectListWrapper.svelte';
|
||||
|
||||
import WidgetColumnBar from './WidgetColumnBar.svelte';
|
||||
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
|
||||
|
||||
$: conid = $currentDatabase?.connection?._id;
|
||||
$: connection = useConnectionInfo({ conid });
|
||||
$: driver = findEngineDriver($connection, $extensions);
|
||||
</script>
|
||||
|
||||
<WidgetColumnBar>
|
||||
<WidgetColumnBarItem title="Connections" name="connections" height="50%">
|
||||
<ConnectionList />
|
||||
</WidgetColumnBarItem>
|
||||
<WidgetColumnBarItem title="Tables, views, functions" name="dbObjects">
|
||||
<SqlObjectListWrapper />
|
||||
<WidgetColumnBarItem title={driver?.dialect?.nosql ? 'Collections' : 'Tables, views, functions'} name="dbObjects">
|
||||
<SqlObjectListWrapper />
|
||||
</WidgetColumnBarItem>
|
||||
</WidgetColumnBar>
|
||||
|
@ -21,8 +21,10 @@
|
||||
$: objects = useDatabaseInfo({ conid, database });
|
||||
$: status = useDatabaseStatus({ conid, database });
|
||||
|
||||
// $: console.log('objects', $objects);
|
||||
|
||||
$: objectList = _.flatten(
|
||||
['tables', 'views', 'procedures', 'functions'].map(objectTypeField =>
|
||||
['tables', 'collections', 'views', 'procedures', 'functions'].map(objectTypeField =>
|
||||
_.sortBy(
|
||||
(($objects || {})[objectTypeField] || []).map(obj => ({ ...obj, objectTypeField })),
|
||||
['schemaName', 'pureName']
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import { currentDatabase } from '../stores';
|
||||
import ErrorInfo from '../elements/ErrorInfo.svelte';
|
||||
import ErrorInfo from '../elements/ErrorInfo.svelte';
|
||||
import SqlObjectList from './SqlObjectList.svelte';
|
||||
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user