diff --git a/packages/api/src/shell/executeQuery.js b/packages/api/src/shell/executeQuery.js new file mode 100644 index 000000000..3ee97c19f --- /dev/null +++ b/packages/api/src/shell/executeQuery.js @@ -0,0 +1,19 @@ +const goSplit = require('../utility/goSplit'); +const requireEngineDriver = require('../utility/requireEngineDriver'); + +async function executeQuery({ connection, sql }) { + console.log(`Execute query ${sql}`); + + const driver = requireEngineDriver(connection); + const pool = await driver.connect(connection); + console.log(`Connected.`); + + for (const sqlItem of goSplit(sql)) { + console.log('Executing query', sqlItem); + await driver.query(pool, sqlItem); + } + + console.log(`Query finished`); +} + +module.exports = executeQuery; diff --git a/packages/api/src/shell/index.js b/packages/api/src/shell/index.js index 135af5ab8..77826c045 100644 --- a/packages/api/src/shell/index.js +++ b/packages/api/src/shell/index.js @@ -15,6 +15,8 @@ const finalizer = require('./finalizer'); const registerPlugins = require('./registerPlugins'); const requirePlugin = require('./requirePlugin'); const download = require('./download'); +const executeQuery = require('./executeQuery'); +const loadFile = require('./loadFile'); const dbgateApi = { queryReader, @@ -32,7 +34,8 @@ const dbgateApi = { collectorWriter, finalizer, registerPlugins, - download, + executeQuery, + loadFile, }; requirePlugin.initialize(dbgateApi); diff --git a/packages/api/src/shell/loadFile.js b/packages/api/src/shell/loadFile.js new file mode 100644 index 000000000..8bc31977e --- /dev/null +++ b/packages/api/src/shell/loadFile.js @@ -0,0 +1,10 @@ +const fs = require('fs-extra'); +const path = require('path'); +const { filesdir } = require('../utility/directories'); + +async function loadFile(file) { + const text = await fs.readFile(path.join(filesdir(), file), { encoding: 'utf-8' }); + return text; +} + +module.exports = loadFile; diff --git a/packages/tools/src/packageTools.ts b/packages/tools/src/packageTools.ts index 6fd1d5639..54b5a5930 100644 --- a/packages/tools/src/packageTools.ts +++ b/packages/tools/src/packageTools.ts @@ -18,6 +18,15 @@ export function extractShellApiPlugins(functionName, props): string[] { return res; } +export function extractPackageName(name): string { + if (!name) return null; + const nsMatch = name.match(/^([^@]+)@([^@]+)/); + if (nsMatch) { + return nsMatch[2]; + } + return null; +} + export function extractShellApiFunctionName(functionName) { const nsMatch = functionName.match(/^([^@]+)@([^@]+)/); if (nsMatch) { diff --git a/packages/web/src/appobj/SavedFileAppObject.js b/packages/web/src/appobj/SavedFileAppObject.js index 63da73193..39343027d 100644 --- a/packages/web/src/appobj/SavedFileAppObject.js +++ b/packages/web/src/appobj/SavedFileAppObject.js @@ -5,20 +5,23 @@ import { DropDownMenuItem } from '../modals/DropDownMenu'; import { AppObjectCore } from './AppObjectCore'; import useNewQuery from '../query/useNewQuery'; import { openNewTab } from '../utility/common'; -import { useSetOpenedTabs } from '../utility/globalState'; +import { useCurrentDatabase, useSetOpenedTabs } from '../utility/globalState'; +import ScriptWriter from '../impexp/ScriptWriter'; +import { extractPackageName } from 'dbgate-tools'; -function Menu({ data }) { +function Menu({ data, menuExt = null }) { const handleDelete = () => { axios.post('files/delete', data); }; return ( <> Delete + {menuExt} ); } -export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad }) { +export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad, menuExt = null }) { const { file, folder } = data; const onClick = async () => { @@ -26,12 +29,48 @@ export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad onLoad(resp.data); }; - return ; + return ( + : Menu} + /> + ); } export function SavedSqlFileAppObject({ data, commonProps }) { const { file, folder } = data; const newQuery = useNewQuery(); + const currentDatabase = useCurrentDatabase(); + const setOpenedTabs = useSetOpenedTabs(); + + const connection = _.get(currentDatabase, 'connection'); + const database = _.get(currentDatabase, 'name'); + + const handleGenerateExecute = () => { + const script = new ScriptWriter(); + const conn = { + ..._.omit(connection, ['displayName', '_id']), + database, + }; + script.put(`const sql = await dbgateApi.loadFile('${folder}/${file}');`) + script.put(`await dbgateApi.executeQuery({ sql, connection: ${JSON.stringify(conn)} });`) + // @ts-ignore + script.requirePackage(extractPackageName(conn.engine)); + + openNewTab( + setOpenedTabs, + { + title: 'Shell', + icon: 'img shell', + tabComponent: 'ShellTab', + }, + script.getScript() + ); + }; return ( Generate shell execute + ) : null + } onLoad={(data) => { newQuery({ title: file, diff --git a/packages/web/src/impexp/ScriptWriter.js b/packages/web/src/impexp/ScriptWriter.js index a20a48b85..68e987c87 100644 --- a/packages/web/src/impexp/ScriptWriter.js +++ b/packages/web/src/impexp/ScriptWriter.js @@ -2,7 +2,7 @@ import _ from 'lodash'; import { extractShellApiFunctionName, extractShellApiPlugins } from 'dbgate-tools'; export default class ScriptWriter { - constructor(varCount) { + constructor(varCount = '0') { this.s = ''; this.packageNames = []; // this.engines = []; @@ -24,6 +24,10 @@ export default class ScriptWriter { this.packageNames.push(...extractShellApiPlugins(functionName, props)); } + requirePackage(packageName) { + this.packageNames.push(packageName); + } + copyStream(sourceVar, targetVar) { this.put(`await dbgateApi.copyStream(${sourceVar}, ${targetVar});`); } @@ -32,7 +36,7 @@ export default class ScriptWriter { this.put(`// ${s}`); } - getScript(extensions, schedule) { + getScript(schedule = null) { const packageNames = this.packageNames; let prefix = _.uniq(packageNames) .map((packageName) => `// @require ${packageName}\n`) diff --git a/packages/web/src/impexp/createImpExpScript.js b/packages/web/src/impexp/createImpExpScript.js index 87c161665..7938ee216 100644 --- a/packages/web/src/impexp/createImpExpScript.js +++ b/packages/web/src/impexp/createImpExpScript.js @@ -182,7 +182,7 @@ export default async function createImpExpScript(extensions, values, addEditorIn script.comment('@ImportExportConfigurator'); script.comment(JSON.stringify(values)); } - return script.getScript(extensions, values.schedule); + return script.getScript(values.schedule); } export function getActionOptions(extensions, source, values, targetDbinfo) {