diff --git a/packages/api/src/shell/queryReader.js b/packages/api/src/shell/queryReader.js index 8231fbae8..72cb56d39 100644 --- a/packages/api/src/shell/queryReader.js +++ b/packages/api/src/shell/queryReader.js @@ -8,7 +8,7 @@ async function queryReader({ connection, sql }) { const driver = engines(connection); const pool = await driverConnect(driver, connection); console.log(`Connected.`); - return driver.readableStream(pool, sql); + return await driver.readableStream(pool, sql); } module.exports = queryReader; diff --git a/packages/api/src/utility/driverConnect.js b/packages/api/src/utility/driverConnect.js index 83221e7fd..2f4f4c9e9 100644 --- a/packages/api/src/utility/driverConnect.js +++ b/packages/api/src/utility/driverConnect.js @@ -2,12 +2,16 @@ const mssql = require('mssql'); const mysql = require('mysql'); const pg = require('pg'); const pgQueryStream = require('pg-query-stream'); +const fs = require('fs'); +const stream = require('stream'); const nativeModules = { mssql, mysql, pg, pgQueryStream, + fs, + stream, }; function driverConnect(driver, connection) { diff --git a/packages/engines/mssql/index.js b/packages/engines/mssql/index.js index 43ef95bad..62957871c 100644 --- a/packages/engines/mssql/index.js +++ b/packages/engines/mssql/index.js @@ -154,6 +154,27 @@ const driver = { return request; }, + async readableStream(pool, sql) { + const request = await pool.request(); + const { stream } = pool._nativeModules; + + const pass = new stream.PassThrough({ + objectMode: true, + highWaterMark: 100, + }); + + request.stream = true; + request.on('row', (row) => pass.write(row)); + request.on('error', (err) => { + console.error(err); + pass.end(); + }); + request.on('done', () => pass.end()); + + request.query(sql); + + return pass; + }, async getVersion(pool) { const { version } = (await this.query(pool, 'SELECT @@VERSION AS version')).rows[0]; return { version }; diff --git a/packages/engines/mysql/index.js b/packages/engines/mysql/index.js index 2f1b18920..b2058bb5c 100644 --- a/packages/engines/mysql/index.js +++ b/packages/engines/mysql/index.js @@ -84,7 +84,7 @@ const driver = { return query; }, - readableStream(connection, sql) { + async readableStream(connection, sql) { const query = connection.query(sql); return query.stream({ highWaterMark: 100 }); }, diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 3108c327b..16e459e76 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -17,7 +17,7 @@ export interface EngineDriver { connect(nativeModules, { server, port, user, password, database }): any; query(pool: any, sql: string): Promise; stream(pool: any, sql: string, options: StreamOptions); - readableStream(pool: any, sql: string): stream.Readable; + readableStream(pool: any, sql: string): Promise; getVersion(pool: any): Promise<{ version: string }>; listDatabases( pool: any diff --git a/packages/web/src/appobj/databaseObjectAppObject.js b/packages/web/src/appobj/databaseObjectAppObject.js index 3a8529d31..8d21f1062 100644 --- a/packages/web/src/appobj/databaseObjectAppObject.js +++ b/packages/web/src/appobj/databaseObjectAppObject.js @@ -5,7 +5,8 @@ import { DropDownMenuItem } from '../modals/DropDownMenu'; import { openNewTab } from '../utility/common'; import { getConnectionInfo } from '../utility/metadataLoaders'; import fullDisplayName from '../utility/fullDisplayName'; -import { filterName } from '@dbgate/datalib'; +import { filterName, fullNameToString } from '@dbgate/datalib'; +import ImportExportModal from '../modals/ImportExportModal'; const icons = { tables: 'table2.svg', @@ -28,6 +29,10 @@ const menus = { label: 'Show CREATE TABLE script', sqlTemplate: 'CREATE TABLE', }, + { + label: 'Export', + isExport: true, + }, ], views: [ { @@ -38,6 +43,10 @@ const menus = { label: 'Show CREATE VIEW script', sqlTemplate: 'CREATE OBJECT', }, + { + label: 'Export', + isExport: true, + }, ], procedures: [ { @@ -90,14 +99,28 @@ async function openObjectDetail( }); } -function Menu({ data, makeAppObj, setOpenedTabs }) { +function Menu({ data, makeAppObj, setOpenedTabs, showModal }) { return ( <> {menus[data.objectTypeField].map((menu) => ( { - openObjectDetail(setOpenedTabs, menu.tab, menu.sqlTemplate, data); + if (menu.isExport) { + showModal((modalState) => ( + + )); + } else { + openObjectDetail(setOpenedTabs, menu.tab, menu.sqlTemplate, data); + } }} > {menu.label}