Merge branch 'master' of github.com:dbgate/dbgate

This commit is contained in:
Jan Prochazka
2024-06-03 09:50:14 +02:00
58 changed files with 497 additions and 548 deletions

View File

@@ -26,10 +26,10 @@
"compare-versions": "^3.6.0",
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-query-splitter": "^4.9.3",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-datalib": "^5.0.0-alpha.1",
"debug": "^4.3.4",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
@@ -60,7 +60,7 @@
"tar": "^6.0.5"
},
"scripts": {
"start": "env-cmd -f .env.local node src/index.js --listen-api",
"start": "env-cmd -f .env node src/index.js --listen-api",
"start:portal": "env-cmd -f env/portal/.env node src/index.js --listen-api",
"start:singledb": "env-cmd -f env/singledb/.env node src/index.js --listen-api",
"start:auth": "env-cmd -f env/auth/.env node src/index.js --listen-api",
@@ -83,7 +83,6 @@
},
"optionalDependencies": {
"better-sqlite3": "9.6.0",
"msnodesqlv8": "^4.2.1",
"oracledb": "^5.5.0"
"msnodesqlv8": "^4.2.1"
}
}

View File

@@ -61,6 +61,7 @@ function getPortalCollections() {
useDatabaseUrl: !!process.env[`URL_${id}`],
databaseFile: process.env[`FILE_${id}`],
socketPath: process.env[`SOCKET_PATH_${id}`],
serviceName: process.env[`SERVICE_NAME_${id}`],
authType: process.env[`AUTH_TYPE_${id}`] || (process.env[`SOCKET_PATH_${id}`] ? 'socket' : undefined),
defaultDatabase:
process.env[`DATABASE_${id}`] ||

View File

@@ -31,7 +31,7 @@
"typescript": "^4.4.3"
},
"dependencies": {
"dbgate-query-splitter": "^4.9.3",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"debug": "^4.3.4",
"json-stable-stringify": "^1.0.1",

View File

@@ -180,8 +180,15 @@ export class DatabaseAnalyser {
// return this.createQueryCore('=OBJECT_ID_CONDITION', typeFields) != ' is not null';
// }
createQuery(template, typeFields) {
return this.createQueryCore(template, typeFields);
createQuery(template, typeFields, replacements = {}) {
return this.createQueryCore(this.processQueryReplacements(template, replacements), typeFields);
}
processQueryReplacements(query, replacements) {
for (const repl in replacements) {
query = query.replaceAll(repl, replacements[repl]);
}
return query;
}
createQueryCore(template, typeFields) {
@@ -302,8 +309,8 @@ export class DatabaseAnalyser {
return [..._compact(res), ...this.getDeletedObjects(snapshot)];
}
async analyserQuery(template, typeFields) {
const sql = this.createQuery(template, typeFields);
async analyserQuery(template, typeFields, replacements = {}) {
const sql = this.createQuery(template, typeFields, replacements);
if (!sql) {
return {
@@ -311,7 +318,9 @@ export class DatabaseAnalyser {
};
}
try {
return await this.driver.query(this.pool, sql);
const res = await this.driver.query(this.pool, sql);
this.logger.debug({ rows: res.rows.length, template }, `Loaded analyser query`);
return res;
} catch (err) {
logger.error({ err }, 'Error running analyser query');
return {

View File

@@ -199,14 +199,8 @@ export class SqlDumper implements AlterProcessor {
selectScopeIdentity(table: TableInfo) {}
columnDefinition(column: ColumnInfo, { includeDefault = true, includeNullable = true, includeCollate = true } = {}) {
if (column.computedExpression) {
this.put('^as %s', column.computedExpression);
if (column.isPersisted) this.put(' ^persisted');
return;
}
const type = column.dataType || this.dialect.fallbackDataType;
columnType(dataType: string) {
const type = dataType || this.dialect.fallbackDataType;
const typeWithValues = type.match(/([^(]+)(\(.+[^)]\))/);
if (typeWithValues?.length) {
@@ -217,6 +211,17 @@ export class SqlDumper implements AlterProcessor {
this.putRaw(SqlDumper.convertKeywordCase(type));
}
}
columnDefinition(column: ColumnInfo, { includeDefault = true, includeNullable = true, includeCollate = true } = {}) {
if (column.computedExpression) {
this.put('^as %s', column.computedExpression);
if (column.isPersisted) this.put(' ^persisted');
return;
}
this.columnType(column.dataType);
if (column.autoIncrement) {
this.autoIncrement();
}

View File

@@ -56,24 +56,42 @@ export function createBulkInsertStreamBase(driver: EngineDriver, stream, pool, n
const rows = writable.buffer;
writable.buffer = [];
const dmp = driver.createDumper();
if (driver.dialect.allowMultipleValuesInsert) {
const dmp = driver.createDumper();
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
let wasRow = false;
for (const row of rows) {
if (wasRow) dmp.putRaw(',\n');
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
wasRow = true;
}
dmp.putRaw(';');
// require('fs').writeFileSync('/home/jena/test.sql', dmp.s);
// console.log(dmp.s);
await driver.query(pool, dmp.s, { discardResult: true });
} else {
for (const row of rows) {
const dmp = driver.createDumper();
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
let wasRow = false;
for (const row of rows) {
if (wasRow) dmp.putRaw(',\n');
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
wasRow = true;
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
await driver.query(pool, dmp.s, { discardResult: true });
}
}
if (options.commitAfterInsert) {
const dmp = driver.createDumper();
dmp.commitTransaction();
await driver.query(pool, dmp.s, { discardResult: true });
}
dmp.putRaw(';');
// require('fs').writeFileSync('/home/jena/test.sql', dmp.s);
// console.log(dmp.s);
await driver.query(pool, dmp.s, { discardResult: true });
};
writable.sendIfFull = async () => {

View File

@@ -12,6 +12,7 @@ export interface SqlDialect {
defaultSchemaName?: string;
enableConstraintsPerTable?: boolean;
requireStandaloneSelectForScopeIdentity?: boolean;
allowMultipleValuesInsert?: boolean;
dropColumnDependencies?: string[];
changeColumnDependencies?: string[];

View File

@@ -24,6 +24,7 @@ export interface WriteTableOptions {
dropIfExists?: boolean;
truncate?: boolean;
createIfNotExists?: boolean;
commitAfterInsert?: boolean;
}
export interface EngineAuthType {

View File

@@ -24,7 +24,7 @@
"chartjs-adapter-moment": "^1.0.0",
"cross-env": "^7.0.3",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.9.3",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-types": "^5.0.0-alpha.1",

View File

@@ -123,6 +123,10 @@
{/if}
{/if}
{#if driver?.showConnectionField('serviceName', $values)}
<FormTextField label="Service name" name="serviceName" disabled={isConnected} />
{/if}
{#if driver?.showConnectionField('socketPath', $values)}
<FormTextField
label="Socket path"

View File

@@ -84,6 +84,7 @@
'defaultDatabase',
'singleDatabase',
'socketPath',
'serviceName',
];
const visibleProps = allProps.filter(x => driver?.showConnectionField(x, $values));
const omitProps = _.difference(allProps, visibleProps);

View File

@@ -24,6 +24,9 @@ function getConnectionLabelCore(connection, { allowExplicitDatabase = true } = {
if (connection.singleDatabase && connection.defaultDatabase) {
return `${connection.defaultDatabase}`;
}
if (connection.useDatabaseUrl) {
return `${connection.databaseUrl}`;
}
return '';
}