mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 09:36:01 +00:00
258 lines
6.9 KiB
TypeScript
258 lines
6.9 KiB
TypeScript
import _compact from 'lodash/compact';
|
|
import _isString from 'lodash/isString';
|
|
import { SqlDumper } from './SqlDumper';
|
|
import { splitQuery } from 'dbgate-query-splitter';
|
|
import { dumpSqlSelect, Select } from 'dbgate-sqltree';
|
|
import { EngineDriver, QueryResult, RunScriptOptions } from 'dbgate-types';
|
|
import { detectSqlFilterBehaviour } from './detectSqlFilterBehaviour';
|
|
import { getLogger } from './getLogger';
|
|
import { getLimitedQuery } from './stringTools';
|
|
|
|
const logger = getLogger('driverBase');
|
|
|
|
const dialect = {
|
|
limitSelect: true,
|
|
rangeSelect: true,
|
|
topRecords: false,
|
|
offsetFetchRangeSyntax: true,
|
|
stringEscapeChar: "'",
|
|
fallbackDataType: 'nvarchar(max)',
|
|
quoteIdentifier(s) {
|
|
return s;
|
|
},
|
|
columnProperties: {
|
|
isSparse: false,
|
|
isPersisted: false,
|
|
},
|
|
defaultSchemaName: null,
|
|
};
|
|
|
|
export async function runCommandOnDriver(
|
|
pool,
|
|
driver: EngineDriver,
|
|
cmd: (dmp: SqlDumper) => void | string
|
|
): Promise<void> {
|
|
const dmp = driver.createDumper();
|
|
if (_isString(cmd)) {
|
|
dmp.put(cmd);
|
|
} else {
|
|
cmd(dmp as any);
|
|
}
|
|
// console.log('CMD:', dmp.s);
|
|
await driver.query(pool, dmp.s, { discardResult: true });
|
|
}
|
|
|
|
export async function runQueryOnDriver(
|
|
pool,
|
|
driver: EngineDriver,
|
|
cmd: (dmp: SqlDumper) => void
|
|
): Promise<QueryResult> {
|
|
const dmp = driver.createDumper();
|
|
if (_isString(cmd)) {
|
|
dmp.put(cmd);
|
|
} else {
|
|
cmd(dmp as any);
|
|
}
|
|
// console.log('QUERY:', dmp.s);
|
|
return await driver.query(pool, dmp.s);
|
|
}
|
|
|
|
export function formatQueryWithoutParams(driver: EngineDriver, sql: string) {
|
|
const dmp = driver.createDumper();
|
|
dmp.put(sql);
|
|
return dmp.s;
|
|
}
|
|
|
|
export async function runQueryFmt(driver, conn, query, ...args) {
|
|
const dmp = driver.createDumper();
|
|
dmp.put(query, ...args);
|
|
await driver.query(conn, dmp.s);
|
|
}
|
|
|
|
export const driverBase = {
|
|
analyserClass: null,
|
|
dumperClass: SqlDumper,
|
|
dialect,
|
|
databaseEngineTypes: ['sql'],
|
|
supportedCreateDatabase: true,
|
|
|
|
async analyseFull(pool, version) {
|
|
const analyser = new this.analyserClass(pool, this, version);
|
|
return analyser.fullAnalysis();
|
|
},
|
|
async analyseSingleObject(pool, name, typeField = 'tables') {
|
|
const analyser = new this.analyserClass(pool, this);
|
|
return analyser.singleObjectAnalysis(name, typeField);
|
|
},
|
|
analyseSingleTable(pool, name) {
|
|
return this.analyseSingleObject(pool, name, 'tables');
|
|
},
|
|
async analyseIncremental(pool, structure, version) {
|
|
const analyser = new this.analyserClass(pool, this, version);
|
|
return analyser.incrementalAnalysis(structure);
|
|
},
|
|
createDumper(options = null): SqlDumper {
|
|
return new this.dumperClass(this, options);
|
|
},
|
|
async script(pool, sql, options: RunScriptOptions) {
|
|
if (options?.useTransaction && this.supportsTransactions) {
|
|
runCommandOnDriver(pool, this, dmp => dmp.beginTransaction());
|
|
}
|
|
for (const sqlItem of splitQuery(sql, this.getQuerySplitterOptions('script'))) {
|
|
try {
|
|
if (options?.logScriptItems) {
|
|
logger.info({ sql: getLimitedQuery(sqlItem as string) }, 'Execute script item');
|
|
}
|
|
await this.query(pool, sqlItem, { discardResult: true, ...options?.queryOptions });
|
|
} catch (err) {
|
|
if (options?.useTransaction && this.supportsTransactions) {
|
|
runCommandOnDriver(pool, this, dmp => dmp.rollbackTransaction());
|
|
}
|
|
throw err;
|
|
}
|
|
}
|
|
if (options?.useTransaction && this.supportsTransactions) {
|
|
runCommandOnDriver(pool, this, dmp => dmp.commitTransaction());
|
|
}
|
|
},
|
|
async operation(pool, operation, options: RunScriptOptions) {
|
|
const { type } = operation;
|
|
switch (type) {
|
|
case 'createSchema':
|
|
await runCommandOnDriver(pool, this, dmp => dmp.createSchema(operation.schemaName));
|
|
break;
|
|
case 'dropSchema':
|
|
await runCommandOnDriver(pool, this, dmp => dmp.dropSchema(operation.schemaName));
|
|
break;
|
|
default:
|
|
throw new Error(`Operation type ${type} not supported`);
|
|
}
|
|
},
|
|
getNewObjectTemplates() {
|
|
if (this.databaseEngineTypes.includes('sql')) {
|
|
return [{ label: 'New view', sql: 'CREATE VIEW myview\nAS\nSELECT * FROM table1' }];
|
|
}
|
|
return [];
|
|
},
|
|
async loadFieldValues(pool, name, columnName, search, dataType) {
|
|
const dmp = this.createDumper();
|
|
|
|
let expr;
|
|
if (this.dialect.createColumnViewExpression) {
|
|
expr = this.dialect.createColumnViewExpression(columnName, dataType, { name }, 'value');
|
|
}
|
|
if (!expr) {
|
|
expr = {
|
|
exprType: 'column',
|
|
columnName,
|
|
alias: 'value',
|
|
};
|
|
}
|
|
|
|
const select: Select = {
|
|
commandType: 'select',
|
|
distinct: true,
|
|
|
|
from: {
|
|
name,
|
|
},
|
|
columns: [expr],
|
|
orderBy: [
|
|
{
|
|
exprType: 'column',
|
|
columnName,
|
|
direction: 'ASC',
|
|
},
|
|
],
|
|
};
|
|
|
|
if (this.dialect.topRecords) {
|
|
select.topRecords = 100;
|
|
} else {
|
|
select.range = { offset: 0, limit: 100 };
|
|
}
|
|
|
|
if (search) {
|
|
const tokens = _compact(search.split(' ').map(x => x.trim()));
|
|
if (tokens.length > 0) {
|
|
// @ts-ignore
|
|
select.where = {
|
|
conditionType: 'and',
|
|
conditions: tokens.map(token => ({
|
|
conditionType: 'like',
|
|
left: {
|
|
exprType: 'column',
|
|
columnName,
|
|
},
|
|
right: {
|
|
exprType: 'value',
|
|
value: `%${token}%`,
|
|
},
|
|
})),
|
|
};
|
|
}
|
|
}
|
|
|
|
// @ts-ignore
|
|
dumpSqlSelect(dmp, select);
|
|
|
|
const resp = await this.query(pool, dmp.s);
|
|
return resp.rows;
|
|
},
|
|
readJsonQuery(pool, select, structure) {
|
|
const dmp = this.createDumper();
|
|
dumpSqlSelect(dmp, select);
|
|
return this.readQuery(pool, dmp.s, structure);
|
|
},
|
|
showConnectionField: (field, values) => false,
|
|
showConnectionTab: field => true,
|
|
getAccessTokenFromAuth: async (connection, req) => null,
|
|
getFilterBehaviour(dataType: string, standardFilterBehaviours) {
|
|
return detectSqlFilterBehaviour(dataType);
|
|
},
|
|
|
|
getCollectionExportQueryScript(collection: string, condition: any, sort: any) {
|
|
return null;
|
|
},
|
|
getCollectionExportQueryJson(collection: string, condition: any, sort: any) {
|
|
return null;
|
|
},
|
|
getScriptTemplates(objectTypeField) {
|
|
return [];
|
|
},
|
|
getScriptTemplateContent(scriptTemplate, props) {
|
|
return null;
|
|
},
|
|
|
|
dataEditorTypesBehaviour: {
|
|
parseSqlNull: true,
|
|
parseHexAsBuffer: true,
|
|
},
|
|
|
|
createSaveChangeSetScript(changeSet, dbinfo, defaultCreator) {
|
|
return defaultCreator(changeSet, dbinfo);
|
|
},
|
|
|
|
adaptDataType(dataType: string) {
|
|
return dataType;
|
|
},
|
|
|
|
adaptTableInfo(table) {
|
|
return {
|
|
...table,
|
|
columns: table.columns?.map(col => ({
|
|
...col,
|
|
dataType: this.adaptDataType(col.dataType),
|
|
})),
|
|
};
|
|
},
|
|
|
|
async listSchemas(pool) {
|
|
return null;
|
|
},
|
|
|
|
async writeQueryFromStream(dbhan, sql) {
|
|
return null;
|
|
},
|
|
};
|