- {#if tableFormOptions}
+ {#if tableInfo && (tableFormOptions || isCreateTable)}
{#key resetCounter}
x.name)
- )}
+ fieldDefinitions={tableFormOptions ?? []}
+ pureNameTitle={isCreateTable ? 'Table name' : null}
+ schemaList={isCreateTable && dbInfo?.schemas?.length >= 0 ? dbInfo?.schemas : null}
+ values={_.pick(tableInfo, ['schemaName', 'pureName', ...(tableFormOptions ?? []).map(x => x.name)])}
onChangeValues={vals => {
if (!_.isEmpty(vals)) {
setTableInfo(tbl => ({ ...tbl, ...vals }));
diff --git a/packages/web/src/tableeditor/newTable.ts b/packages/web/src/tableeditor/newTable.ts
new file mode 100644
index 000000000..1048abd0f
--- /dev/null
+++ b/packages/web/src/tableeditor/newTable.ts
@@ -0,0 +1,48 @@
+import _ from 'lodash';
+import openNewTab from '../utility/openNewTab';
+import { findEngineDriver, getConnectionLabel } from 'dbgate-tools';
+import { getAppliedCurrentSchema, getExtensions } from '../stores';
+
+export default function newTable(connection, database) {
+ const tooltip = `${getConnectionLabel(connection)}\n${database}`;
+ const driver = findEngineDriver(connection, getExtensions());
+ openNewTab(
+ {
+ title: 'Table #',
+ tooltip,
+ icon: 'img table-structure',
+ tabComponent: 'TableStructureTab',
+ props: {
+ conid: connection._id,
+ database,
+ },
+ },
+ {
+ editor: {
+ current: {
+ pureName: 'new_table',
+ schemaName: getAppliedCurrentSchema() ?? driver?.dialect?.defaultSchemaName,
+ columns: [
+ {
+ columnName: 'id',
+ dataType: 'int',
+ isNullable: false,
+ isPrimaryKey: true,
+ isAutoIncrement: true,
+ },
+ ],
+ primaryKey: {
+ columns: [
+ {
+ columnName: 'id',
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ forceNewTab: true,
+ }
+ );
+}
diff --git a/packages/web/src/tabs/TableStructureTab.svelte b/packages/web/src/tabs/TableStructureTab.svelte
index c3717745b..631664862 100644
--- a/packages/web/src/tabs/TableStructureTab.svelte
+++ b/packages/web/src/tabs/TableStructureTab.svelte
@@ -22,7 +22,7 @@
toolbar: true,
isRelatedToTab: true,
icon: 'icon close',
- testEnabled: () => getCurrentEditor()?.canSave(),
+ testEnabled: () => getCurrentEditor()?.canResetChanges(),
onClick: () => getCurrentEditor().reset(),
});
@@ -39,10 +39,6 @@
import _ from 'lodash';
import registerCommand from '../commands/registerCommand';
- import ColumnLabel from '../elements/ColumnLabel.svelte';
- import ConstraintLabel from '../elements/ConstraintLabel.svelte';
- import ForeignKeyObjectListControl from '../elements/ForeignKeyObjectListControl.svelte';
-
import { extensions } from '../stores';
import useEditorData from '../query/useEditorData';
import TableEditor from '../tableeditor/TableEditor.svelte';
@@ -53,15 +49,13 @@
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { showSnackbarSuccess } from '../utility/snackbar';
- import InputTextModal from '../modals/InputTextModal.svelte';
- import { changeTab } from '../utility/common';
- import StatusBarTabItem from '../widgets/StatusBarTabItem.svelte';
import openNewTab from '../utility/openNewTab';
import { apiCall } from '../utility/api';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
import ToolStripButton from '../buttons/ToolStripButton.svelte';
import hasPermission from '../utility/hasPermission';
+ import { changeTab } from '../utility/common';
export let tabid;
export let conid;
@@ -90,30 +84,11 @@
return objectTypeField == 'tables' && !!$editorValue && !$connection?.isReadOnly;
}
- export function save() {
- if ($editorValue.base) {
- doSave(null);
- } else {
- showModal(InputTextModal, {
- header: 'Set table name',
- value: savedName || 'newTable',
- label: 'Table name',
- onConfirm: name => {
- savedName = name;
- setEditorData(tbl => ({
- base: tbl.base,
- current: {
- ...tbl.current,
- pureName: name,
- },
- }));
- doSave(name);
- },
- });
- }
+ export function canResetChanges() {
+ return canSave() && !!$editorValue.base;
}
- function doSave(createTableName) {
+ export function save() {
const { sql, recreates } = getAlterTableScript(
$editorValue.base,
extendTableInfo(fillConstraintNames($editorValue.current, driver.dialect)),
@@ -127,32 +102,30 @@
sql,
recreates,
onConfirm: () => {
- handleConfirmSql(sql, createTableName);
+ handleConfirmSql(sql);
},
engine: driver.engine,
});
}
- async function handleConfirmSql(sql, createTableName) {
+ async function handleConfirmSql(sql) {
const resp = await apiCall('database-connections/run-script', { conid, database, sql, useTransaction: true });
const { errorMessage } = resp || {};
if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
} else {
- if (createTableName) {
- changeTab(tabid, tab => ({
- ...tab,
- title: createTableName,
- props: {
- ...tab.props,
- pureName: createTableName,
- },
- }));
- }
-
await apiCall('database-connections/sync-model', { conid, database });
showSnackbarSuccess('Saved to database');
+ const isCreateTable = $editorValue?.base == null;
+ const tableName = _.pick($editorValue.current, ['pureName', 'schemaName']);
clearEditorData();
+ if (isCreateTable) {
+ changeTab(tabid, tab => ({
+ ...tab,
+ title: tableName.pureName,
+ props: { ...tab.props, ...tableName },
+ }));
+ }
}
}
@@ -175,6 +148,7 @@
dbInfo={$dbInfo}
{driver}
{resetCounter}
+ isCreateTable={objectTypeField == 'tables' && !$editorValue?.base}
setTableInfo={objectTypeField == 'tables' && !$connection?.isReadOnly && hasPermission(`dbops/model/edit`)
? tableInfoUpdater =>
setEditorData(tbl =>
@@ -191,7 +165,10 @@
: null}
/>
-
+
diff --git a/packages/web/src/utility/openNewTab.ts b/packages/web/src/utility/openNewTab.ts
index 687002dce..fd40141e9 100644
--- a/packages/web/src/utility/openNewTab.ts
+++ b/packages/web/src/utility/openNewTab.ts
@@ -15,7 +15,7 @@ function findFreeNumber(numbers: number[]) {
// return res;
}
-export default async function openNewTab(newTab, initialData = undefined, options = undefined) {
+export default async function openNewTab(newTab, initialData: any = undefined, options: any = undefined) {
const oldTabs = getOpenedTabs();
const activeTab = getActiveTab();
diff --git a/packages/web/src/widgets/SchemaSelector.svelte b/packages/web/src/widgets/SchemaSelector.svelte
new file mode 100644
index 000000000..6f4350f6c
--- /dev/null
+++ b/packages/web/src/widgets/SchemaSelector.svelte
@@ -0,0 +1,139 @@
+
+
+{#if schemaList.length > 0}
+
+
Schema:
+
({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })),
+ // ...schemaList.filter(x => countBySchema[x]).map(x => ({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })),
+ // ...schemaList.filter(x => !countBySchema[x]).map(x => ({ label: `${x} (${countBySchema[x] ?? 0})`, value: x })),
+ ]}
+ value={selectedSchema ?? $appliedCurrentSchema ?? ''}
+ on:change={e => {
+ selectedSchema = e.detail;
+ localStorage.setItem(valueStorageKey, e.detail);
+ }}
+ selectClass="schema-select"
+ />
+
+ {#if selectedSchema != null}
+ {
+ selectedSchema = null;
+ }}
+ title="Reset to default"
+ >
+
+
+ {/if}
+
+
+
+
+
+
+
+{/if}
+
+
diff --git a/packages/web/src/widgets/SqlObjectList.svelte b/packages/web/src/widgets/SqlObjectList.svelte
index f53bde637..203f8eeeb 100644
--- a/packages/web/src/widgets/SqlObjectList.svelte
+++ b/packages/web/src/widgets/SqlObjectList.svelte
@@ -35,11 +35,14 @@
import runCommand from '../commands/runCommand';
import { apiCall } from '../utility/api';
import { filterAppsForDatabase } from '../utility/appTools';
+ import SchemaSelector from './SchemaSelector.svelte';
+ import { appliedCurrentSchema } from '../stores';
export let conid;
export let database;
let filter = '';
+ let selectedSchema = null;
$: objects = useDatabaseInfo({ conid, database });
$: status = useDatabaseStatus({ conid, database });
@@ -99,6 +102,12 @@
);
return res;
}
+
+ $: flatFilteredList = objectList.filter(data => {
+ const matcher = databaseObjectAppObject.createMatcher(data);
+ if (matcher && !matcher(filter)) return false;
+ return true;
+ });
{#if $status && $status.name == 'error'}
@@ -130,16 +139,27 @@
-
+
+
+
{#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects}
{:else}
({ ...x, conid, database }))}
+ list={objectList
+ .filter(x => ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true))
+ .map(x => ({ ...x, conid, database }))}
module={databaseObjectAppObject}
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
subItemsComponent={SubColumnParamList}
@@ -147,7 +167,11 @@
data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'}
expandIconFunc={chevronExpandIcon}
{filter}
- passProps={{ showPinnedInsteadOfUnpin: true, connection: $connection }}
+ passProps={{
+ showPinnedInsteadOfUnpin: true,
+ connection: $connection,
+ hideSchemaName: !!$appliedCurrentSchema,
+ }}
/>
{/if}
diff --git a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
index 3942b03c4..757933915 100644
--- a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
+++ b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
@@ -79,6 +79,12 @@ class MsSqlAnalyser extends DatabaseAnalyser {
this.singleObjectId = resId.rows[0].id;
}
+ async readSchemaList() {
+ const schemaRows = await this.analyserQuery('getSchemas');
+ const schemas = schemaRows.rows;
+ return schemas;
+ }
+
async _runAnalysis() {
this.feedback({ analysingMessage: 'Loading tables' });
const tablesRows = await this.analyserQuery('tables', ['tables']);
@@ -88,8 +94,6 @@ class MsSqlAnalyser extends DatabaseAnalyser {
const pkColumnsRows = await this.analyserQuery('primaryKeys', ['tables']);
this.feedback({ analysingMessage: 'Loading foreign keys' });
const fkColumnsRows = await this.analyserQuery('foreignKeys', ['tables']);
- this.feedback({ analysingMessage: 'Loading schemas' });
- const schemaRows = await this.analyserQuery('getSchemas');
this.feedback({ analysingMessage: 'Loading indexes' });
const indexesRows = await this.analyserQuery('indexes', ['tables']);
this.feedback({ analysingMessage: 'Loading index columns' });
@@ -99,17 +103,10 @@ class MsSqlAnalyser extends DatabaseAnalyser {
this.feedback({ analysingMessage: 'Loading table sizes' });
const tableSizes = await this.analyserQuery('tableSizes');
- const schemas = schemaRows.rows;
-
const tableSizesDict = _.mapValues(_.keyBy(tableSizes.rows, 'objectId'), 'tableRowCount');
this.feedback({ analysingMessage: 'Loading SQL code' });
- const sqlCodeRows = await this.analyserQuery('loadSqlCode', [
- 'views',
- 'procedures',
- 'functions',
- 'triggers',
- ]);
+ const sqlCodeRows = await this.analyserQuery('loadSqlCode', ['views', 'procedures', 'functions', 'triggers']);
const getCreateSql = row =>
sqlCodeRows.rows
.filter(x => x.pureName == row.pureName && x.schemaName == row.schemaName)
@@ -182,7 +179,6 @@ class MsSqlAnalyser extends DatabaseAnalyser {
views,
procedures,
functions,
- schemas,
defaultSchema: defaultSchemaRows.rows[0] ? defaultSchemaRows.rows[0].name : undefined,
};
}
diff --git a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js
index f5153af8e..bca81994e 100644
--- a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js
+++ b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js
@@ -312,6 +312,17 @@ class Analyser extends DatabaseAnalyser {
return res;
}
+ async readSchemaList() {
+ const schemaRows = await this.analyserQuery('getSchemas');
+
+ const schemas = schemaRows.rows.map(x => ({
+ schemaName: x.schema_name,
+ objectId: `schemas:${x.schema_name}`,
+ }));
+
+ return schemas;
+ }
+
async _getFastSnapshot() {
const tableModificationsQueryData = this.driver.dialect.stringAgg
? await this.analyserQuery('tableModifications')
diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/getSchemas.js b/plugins/dbgate-plugin-postgres/src/backend/sql/getSchemas.js
new file mode 100644
index 000000000..88f8972db
--- /dev/null
+++ b/plugins/dbgate-plugin-postgres/src/backend/sql/getSchemas.js
@@ -0,0 +1 @@
+module.exports = `select oid as "object_id", nspname as "schema_name" from pg_catalog.pg_namespace`;
diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js
index 53a858ab5..9fb45a93b 100644
--- a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js
+++ b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js
@@ -12,6 +12,7 @@ const matviewColumns = require('./matviewColumns');
const indexes = require('./indexes');
const indexcols = require('./indexcols');
const uniqueNames = require('./uniqueNames');
+const getSchemas = require('./getSchemas');
const geometryColumns = require('./geometryColumns');
const geographyColumns = require('./geographyColumns');
@@ -39,4 +40,5 @@ module.exports = {
uniqueNames,
geometryColumns,
geographyColumns,
+ getSchemas,
};