This commit is contained in:
Nybkox
2025-01-23 15:46:15 +01:00
parent 645a1d35e8
commit bcf89b1f09
33 changed files with 832 additions and 87 deletions

View File

@@ -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,

View File

@@ -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)),
])
);
}

View File

@@ -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);
}

View File

@@ -14,6 +14,7 @@ export function createBulkInsertStreamBase(driver: EngineDriver, stream, dbhan,
objectMode: true,
});
writable.fullNameQuoted = fullNameQuoted;
writable.buffer = [];
writable.structure = null;
writable.columnNames = null;

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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"

View File

@@ -15,6 +15,7 @@
export let dialect;
export let disabled = false;
console.log(dialect);
</script>
<FormDropDownTextField name="dataType" label="Data type" menu={createDataTypesMenu} {disabled} />

View File

@@ -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',

View File

@@ -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',