mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-27 16:06:23 +00:00
WIP
This commit is contained in:
@@ -213,13 +213,12 @@ async function handleRunOperation({ msgid, operation, useTransaction }, skipRead
|
||||
}
|
||||
}
|
||||
|
||||
async function handleQueryData({ msgid, sql }, skipReadonlyCheck = false) {
|
||||
async function handleQueryData({ msgid, sql, range }, skipReadonlyCheck = false) {
|
||||
await waitConnected();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
try {
|
||||
if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
|
||||
// console.log(sql);
|
||||
const res = await driver.query(dbhan, sql);
|
||||
const res = await driver.query(dbhan, sql, { range });
|
||||
process.send({ msgtype: 'response', msgid, ...res });
|
||||
} catch (err) {
|
||||
process.send({
|
||||
@@ -234,7 +233,7 @@ async function handleSqlSelect({ msgid, select }) {
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
const dmp = driver.createDumper();
|
||||
dumpSqlSelect(dmp, select);
|
||||
return handleQueryData({ msgid, sql: dmp.s }, true);
|
||||
return handleQueryData({ msgid, sql: dmp.s, range: select.range }, true);
|
||||
}
|
||||
|
||||
async function handleDriverDataCore(msgid, callMethod, { logName }) {
|
||||
@@ -340,6 +339,7 @@ async function handleSqlPreview({ msgid, objects, options }) {
|
||||
}, 500);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.send({
|
||||
msgtype: 'response',
|
||||
msgid,
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
AllowIdentityInsert,
|
||||
Expression,
|
||||
} from 'dbgate-sqltree';
|
||||
import type { NamedObjectInfo, DatabaseInfo, TableInfo } from 'dbgate-types';
|
||||
import type { NamedObjectInfo, DatabaseInfo, TableInfo, SqlDialect } from 'dbgate-types';
|
||||
import { JsonDataObjectUpdateCommand } from 'dbgate-tools';
|
||||
|
||||
export interface ChangeSetItem {
|
||||
@@ -252,7 +252,8 @@ function extractFields(item: ChangeSetItem, allowNulls = true, allowedDocumentCo
|
||||
|
||||
function changeSetInsertToSql(
|
||||
item: ChangeSetItem,
|
||||
dbinfo: DatabaseInfo = null
|
||||
dbinfo: DatabaseInfo = null,
|
||||
dialect: SqlDialect = null
|
||||
): [AllowIdentityInsert, Insert, AllowIdentityInsert] {
|
||||
const table = dbinfo?.tables?.find(x => x.schemaName == item.schemaName && x.pureName == item.pureName);
|
||||
const fields = extractFields(
|
||||
@@ -299,19 +300,39 @@ function changeSetInsertToSql(
|
||||
];
|
||||
}
|
||||
|
||||
export function extractChangeSetCondition(item: ChangeSetItem, alias?: string): Condition {
|
||||
export function extractChangeSetCondition(
|
||||
item: ChangeSetItem,
|
||||
alias?: string,
|
||||
table?: TableInfo,
|
||||
dialect?: SqlDialect
|
||||
): Condition {
|
||||
function getShouldUseRawRightValue(columnName: string) {
|
||||
if (!table || !dialect || !dialect.rawUuids) return false;
|
||||
|
||||
const column = table.columns.find(x => x.columnName == columnName);
|
||||
if (!column) return false;
|
||||
|
||||
if (column.dataType !== 'uuid') return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getColumnCondition(columnName: string): Condition {
|
||||
const shouldUseRawRightValue = getShouldUseRawRightValue(columnName);
|
||||
|
||||
const value = item.condition[columnName];
|
||||
const expr: Expression = {
|
||||
exprType: 'column',
|
||||
columnName,
|
||||
source: {
|
||||
name: {
|
||||
pureName: item.pureName,
|
||||
schemaName: item.schemaName,
|
||||
},
|
||||
alias,
|
||||
},
|
||||
source: dialect?.omitTableBeforeColumn
|
||||
? undefined
|
||||
: {
|
||||
name: {
|
||||
pureName: item.pureName,
|
||||
schemaName: item.schemaName,
|
||||
},
|
||||
alias,
|
||||
},
|
||||
};
|
||||
if (value == null) {
|
||||
return {
|
||||
@@ -323,10 +344,15 @@ export function extractChangeSetCondition(item: ChangeSetItem, alias?: string):
|
||||
conditionType: 'binary',
|
||||
operator: '=',
|
||||
left: expr,
|
||||
right: {
|
||||
exprType: 'value',
|
||||
value,
|
||||
},
|
||||
right: shouldUseRawRightValue
|
||||
? {
|
||||
exprType: 'raw',
|
||||
sql: value,
|
||||
}
|
||||
: {
|
||||
exprType: 'value',
|
||||
value,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -366,7 +392,7 @@ function compileSimpleChangeSetCondition(fields: { [column: string]: string }):
|
||||
};
|
||||
}
|
||||
|
||||
function changeSetUpdateToSql(item: ChangeSetItem, dbinfo: DatabaseInfo = null): Update {
|
||||
function changeSetUpdateToSql(item: ChangeSetItem, dbinfo: DatabaseInfo = null, dialect: SqlDialect = null): Update {
|
||||
const table = dbinfo?.tables?.find(x => x.schemaName == item.schemaName && x.pureName == item.pureName);
|
||||
|
||||
const autoIncCol = table?.columns?.find(x => x.autoIncrement);
|
||||
@@ -384,11 +410,13 @@ function changeSetUpdateToSql(item: ChangeSetItem, dbinfo: DatabaseInfo = null):
|
||||
true,
|
||||
table?.columns?.map(x => x.columnName).filter(x => x != autoIncCol?.columnName)
|
||||
),
|
||||
where: extractChangeSetCondition(item),
|
||||
where: extractChangeSetCondition(item, undefined, table, dialect),
|
||||
};
|
||||
}
|
||||
|
||||
function changeSetDeleteToSql(item: ChangeSetItem): Delete {
|
||||
function changeSetDeleteToSql(item: ChangeSetItem, dbinfo: DatabaseInfo = null, dialect: SqlDialect = null): Delete {
|
||||
const table = dbinfo?.tables?.find(x => x.schemaName == item.schemaName && x.pureName == item.pureName);
|
||||
|
||||
return {
|
||||
from: {
|
||||
name: {
|
||||
@@ -397,16 +425,16 @@ function changeSetDeleteToSql(item: ChangeSetItem): Delete {
|
||||
},
|
||||
},
|
||||
commandType: 'delete',
|
||||
where: extractChangeSetCondition(item),
|
||||
where: extractChangeSetCondition(item, undefined, table, dialect),
|
||||
};
|
||||
}
|
||||
|
||||
export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Command[] {
|
||||
export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo, dialect: SqlDialect): Command[] {
|
||||
return _.compact(
|
||||
_.flatten([
|
||||
...(changeSet.inserts.map(item => changeSetInsertToSql(item, dbinfo)) as any),
|
||||
...changeSet.updates.map(item => changeSetUpdateToSql(item, dbinfo)),
|
||||
...changeSet.deletes.map(changeSetDeleteToSql),
|
||||
...(changeSet.inserts.map(item => changeSetInsertToSql(item, dbinfo, dialect)) as any),
|
||||
...changeSet.updates.map(item => changeSetUpdateToSql(item, dbinfo, dialect)),
|
||||
...changeSet.deletes.map(item => changeSetDeleteToSql(item, dbinfo, dialect)),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) {
|
||||
if (cmd.range) {
|
||||
if (dmp.dialect.offsetFetchRangeSyntax) {
|
||||
dmp.put('^offset %s ^rows ^fetch ^next %s ^rows ^only', cmd.range.offset, cmd.range.limit);
|
||||
} else if (dmp.dialect.offsetNotSupported) {
|
||||
dmp.put('^limit %s', cmd.range.limit + cmd.range.offset);
|
||||
} else {
|
||||
dmp.put('^limit %s ^offset %s ', cmd.range.limit, cmd.range.offset);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export function createBulkInsertStreamBase(driver: EngineDriver, stream, dbhan,
|
||||
objectMode: true,
|
||||
});
|
||||
|
||||
writable.fullNameQuoted = fullNameQuoted;
|
||||
writable.buffer = [];
|
||||
writable.structure = null;
|
||||
writable.columnNames = null;
|
||||
|
||||
8
packages/types/dialect.d.ts
vendored
8
packages/types/dialect.d.ts
vendored
@@ -1,3 +1,5 @@
|
||||
import { ColumnInfo } from './dbinfo';
|
||||
|
||||
export interface SqlDialect {
|
||||
rangeSelect?: boolean;
|
||||
limitSelect?: boolean;
|
||||
@@ -6,6 +8,7 @@ export interface SqlDialect {
|
||||
topRecords?: boolean;
|
||||
stringEscapeChar: string;
|
||||
offsetFetchRangeSyntax?: boolean;
|
||||
offsetNotSupported?: boolean;
|
||||
quoteIdentifier(s: string): string;
|
||||
fallbackDataType?: string;
|
||||
explicitDropConstraint?: boolean;
|
||||
@@ -14,6 +17,7 @@ export interface SqlDialect {
|
||||
enableConstraintsPerTable?: boolean;
|
||||
requireStandaloneSelectForScopeIdentity?: boolean;
|
||||
allowMultipleValuesInsert?: boolean;
|
||||
rawUuids?: boolean;
|
||||
|
||||
dropColumnDependencies?: string[];
|
||||
changeColumnDependencies?: string[];
|
||||
@@ -45,6 +49,10 @@ export interface SqlDialect {
|
||||
omitUniqueConstraints?: boolean;
|
||||
omitIndexes?: boolean;
|
||||
omitTableAliases?: boolean;
|
||||
omitTableBeforeColumn?: boolean;
|
||||
disableAutoIncrement?: boolean;
|
||||
disableNonPrimaryKeyRename?: boolean;
|
||||
defaultNewTableColumns?: ColumnInfo[];
|
||||
sortingKeys?: boolean;
|
||||
|
||||
// syntax for create column: ALTER TABLE table ADD COLUMN column
|
||||
|
||||
4
packages/types/engines.d.ts
vendored
4
packages/types/engines.d.ts
vendored
@@ -32,6 +32,7 @@ export interface RunScriptOptions {
|
||||
export interface QueryOptions {
|
||||
discardResult?: boolean;
|
||||
importSqlDump?: boolean;
|
||||
range?: { offset: number; limit: number };
|
||||
}
|
||||
|
||||
export interface WriteTableOptions {
|
||||
@@ -180,6 +181,7 @@ export interface EngineDriver<TClient = any> extends FilterBehaviourProvider {
|
||||
beforeConnectionSave?: (values: any) => any;
|
||||
databaseUrlPlaceholder?: string;
|
||||
defaultAuthTypeName?: string;
|
||||
defaultLocalDataCenter?: string;
|
||||
defaultSocketPath?: string;
|
||||
authTypeLabel?: string;
|
||||
importExportArgs?: any[];
|
||||
@@ -251,7 +253,7 @@ export interface EngineDriver<TClient = any> extends FilterBehaviourProvider {
|
||||
createSaveChangeSetScript(
|
||||
changeSet: any,
|
||||
dbinfo: DatabaseInfo,
|
||||
defaultCreator: (changeSet: any, dbinfo: DatabaseInfo) => any
|
||||
defaultCreator: (changeSet: any, dbinfo: DatabaseInfo, dialect: SqlDialect) => any
|
||||
): any[];
|
||||
// adapts table info from different source (import, other database) to be suitable for this database
|
||||
adaptTableInfo(table: TableInfo): TableInfo;
|
||||
|
||||
@@ -21,11 +21,15 @@
|
||||
import { renameDatabaseObjectDialog, alterDatabaseDialog } from '../utility/alterDatabaseTools';
|
||||
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import { DEFAULT_OBJECT_SEARCH_SETTINGS } from '../stores';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
import { DEFAULT_OBJECT_SEARCH_SETTINGS, extensions } from '../stores';
|
||||
import { filterName, findEngineDriver } from 'dbgate-tools';
|
||||
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||
|
||||
export let data;
|
||||
|
||||
$: connection = useConnectionInfo({ conid: data.conid });
|
||||
$: driver = findEngineDriver($connection, $extensions);
|
||||
|
||||
function handleRenameColumn() {
|
||||
renameDatabaseObjectDialog(data.conid, data.database, data.columnName, (db, newName) => {
|
||||
const tbl = db.tables.find(x => x.schemaName == data.schemaName && x.pureName == data.pureName);
|
||||
@@ -42,11 +46,20 @@
|
||||
}
|
||||
|
||||
function createMenu() {
|
||||
return [
|
||||
{ text: 'Rename column', onClick: handleRenameColumn },
|
||||
const isPrimaryKey = !!data.primaryKey?.columns?.some(i => i.columnName == data.columnName);
|
||||
|
||||
const menu = [];
|
||||
|
||||
if (!driver.dialect.disableNonPrimaryKeyRename || isPrimaryKey) {
|
||||
menu.push({ text: 'Rename column', onClick: handleRenameColumn });
|
||||
}
|
||||
|
||||
menu.push(
|
||||
{ text: 'Drop column', onClick: handleDropColumn },
|
||||
{ text: 'Copy name', onClick: () => navigator.clipboard.writeText(data.columnName) },
|
||||
];
|
||||
{ text: 'Copy name', onClick: () => navigator.clipboard.writeText(data.columnName) }
|
||||
);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
function getExtInfo(data) {
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
let initialized = false;
|
||||
let error = null;
|
||||
let truncated = false;
|
||||
$: console.log(error);
|
||||
|
||||
$: dbinfo = useDatabaseInfo({ conid, database });
|
||||
|
||||
@@ -97,6 +98,7 @@
|
||||
return;
|
||||
}
|
||||
const { sql, isTruncated, isError, errorMessage } = response || {};
|
||||
console.log(response);
|
||||
|
||||
truncated = isTruncated;
|
||||
if (isError) {
|
||||
|
||||
@@ -135,6 +135,16 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if driver?.showConnectionField('localDataCenter', $values, showConnectionFieldArgs)}
|
||||
<FormTextField
|
||||
label="Local DataCenter"
|
||||
name="localDataCenter"
|
||||
data-testid="ConnectionDriverFields_localDataCenter"
|
||||
placeholder={driver?.defaultLocalDataCenter}
|
||||
disabled={isConnected || disabledFields.includes('localDataCenter')}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs)}
|
||||
{#key $authTypes}
|
||||
<FormSelectField
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
<FormCheckboxField name="notNull" label="NOT NULL" disabled={isReadOnly} />
|
||||
{/if}
|
||||
<FormCheckboxField name="isPrimaryKey" label="Is Primary Key" disabled={isReadOnly} />
|
||||
<FormCheckboxField name="autoIncrement" label="Is Autoincrement" disabled={isReadOnly} />
|
||||
{#if !driver?.dialect?.disableAutoIncrement}
|
||||
<FormCheckboxField name="autoIncrement" label="Is Autoincrement" disabled={isReadOnly} />
|
||||
{/if}
|
||||
<FormTextField
|
||||
name="defaultValue"
|
||||
label="Default value. Please use valid SQL expression, eg. 'Hello World' for string value, '' for empty string"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
export let dialect;
|
||||
export let disabled = false;
|
||||
console.log(dialect);
|
||||
</script>
|
||||
|
||||
<FormDropDownTextField name="dataType" label="Data type" menu={createDataTypesMenu} {disabled} />
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function newTable(connection, database) {
|
||||
current: {
|
||||
pureName: 'new_table',
|
||||
schemaName: getAppliedCurrentSchema() ?? driver?.dialect?.defaultSchemaName,
|
||||
columns: [
|
||||
columns: driver.dialect?.defaultNewTableColumns ?? [
|
||||
{
|
||||
columnName: 'id',
|
||||
dataType: 'int',
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
$: engine = $values.engine;
|
||||
$: driver = $extensions.drivers.find(x => x.engine == engine);
|
||||
$: config = useConfig();
|
||||
$: console.log('#values', $values);
|
||||
|
||||
const testIdRef = createRef(0);
|
||||
|
||||
@@ -110,6 +111,7 @@
|
||||
'port',
|
||||
'user',
|
||||
'password',
|
||||
'localDataCenter',
|
||||
'defaultDatabase',
|
||||
'singleDatabase',
|
||||
'socketPath',
|
||||
|
||||
Reference in New Issue
Block a user