diff --git a/global.d.ts b/global.d.ts index 1377e9f7..93dc6175 100644 --- a/global.d.ts +++ b/global.d.ts @@ -24,4 +24,10 @@ interface SQLParm { IS_NULLABLE: "Y" | "N", DEFAULT?: string, LONG_COMMENT?: string +} + +interface StatementInfo { + content: string, + type: "statement"|"json"|"csv"|"cl"|"sql", + open?: boolean } \ No newline at end of file diff --git a/package.json b/package.json index b8acb8c5..bc97b69c 100644 --- a/package.json +++ b/package.json @@ -131,13 +131,13 @@ { "command": "vscode-db2i.generateSQL", "title": "Generate SQL", - "category": "Db2 for i", - "icon": "$(add)" + "category": "Db2 for i" }, { - "command": "vscode-db2i.generateSelect", - "title": "Generate SELECT", - "category": "Db2 for i" + "command": "vscode-db2i.getResultSet", + "title": "View contents", + "category": "Db2 for i", + "icon": "$(output)" }, { "command": "vscode-db2i.setCurrentSchema", @@ -195,9 +195,9 @@ "group": "db2@1" }, { - "command": "vscode-db2i.generateSelect", + "command": "vscode-db2i.getResultSet", "when": "viewItem == table || viewItem == view || viewItem == alias", - "group": "db2@1" + "group": "inline" }, { "command": "vscode-db2i.generateSQL", diff --git a/src/language/results/html.js b/src/language/results/html.js index d5659293..2962b86a 100644 --- a/src/language/results/html.js +++ b/src/language/results/html.js @@ -68,6 +68,103 @@ exports.getLoadingHTML = () => { `; } +/** + * + * @param {string} basicSelect + * @returns {string} + */ +exports.generateScroller = (basicSelect) => { + return /*html*/ ` + + +
+ ${head} + + + +Execute statement.
+ + + `; +} + /** * * @param {object[]} rows diff --git a/src/language/results/index.js b/src/language/results/index.js index 47049bd3..ae8fd77a 100644 --- a/src/language/results/index.js +++ b/src/language/results/index.js @@ -28,6 +28,31 @@ class ResultSetPanelProvider { }; webviewView.webview.html = html.getLoadingHTML(); + this._view.webview.onDidReceiveMessage(async (message) => { + if (message.query && message.limit && message.offset >= 0) { + const instance = await getInstance(); + const content = instance.getContent(); + const config = instance.getConfig(); + + const statement = [ + `SET CURRENT SCHEMA = '${config.currentLibrary.toUpperCase()}'`, + `${message.query} LIMIT ${message.limit} OFFSET ${message.offset}`, + ].join(`;\n`); + + let data = []; + try { + data = await content.runSQL(statement); + } catch (e) { + this.setError(e.message); + data = []; + } + + this._view.webview.postMessage({ + command: `rows`, + rows: data, + }); + } + }); } async focus() { @@ -56,15 +81,25 @@ class ResultSetPanelProvider { /** * @param {object[]} results */ - setResults(results) { - this.focus(); + async setResults(results) { + await this.focus(); this.loadingState = false; const content = html.generateResults(results); this._view.webview.html = content; } + async setScrolling(basicSelect) { + await this.focus(); + + this._view.webview.html = html.generateScroller(basicSelect); + + this._view.webview.postMessage({ + command: `fetch` + }); + } + setError(error) { - // TODO: error + // TODO: pretty error this._view.webview.html = `${error}
`; } } @@ -78,125 +113,147 @@ exports.initialise = (context) => { context.subscriptions.push( vscode.window.registerWebviewViewProvider(`vscode-db2i.resultset`, resultSetProvider), - vscode.commands.registerCommand(`vscode-db2i.runEditorStatement`, async () => { - const instance = getInstance(); - const config = instance.getConfig(); - const content = instance.getContent(); - const editor = vscode.window.activeTextEditor; - - if (editor.document.languageId === `sql`) { - const statement = this.parseStatement(editor); - - if (statement.content.trim().length > 0) { - try { - if (statement.type === `cl`) { - const commandResult = await vscode.commands.executeCommand(`code-for-ibmi.runCommand`, { - command: statement.content, - environment: `ile` - }); - - if (commandResult.code === 0 || commandResult.code === null) { - vscode.window.showInformationMessage(`Command executed successfuly.`); - } else { - vscode.window.showErrorMessage(`Command failed to run.`); - } + vscode.commands.registerCommand(`vscode-db2i.runEditorStatement`, + /** + * @param {StatementInfo} [options] + */ + async (options) => { + const instance = getInstance(); + const config = instance.getConfig(); + const content = instance.getContent(); + const editor = vscode.window.activeTextEditor; + + if (options || (editor && editor.document.languageId === `sql`)) { + /** @type {StatementInfo} */ + const statement = options || this.parseStatement(editor); + + if (statement.open) { + const textDoc = await vscode.workspace.openTextDocument({language: `sql`, content: statement.content}); + await vscode.window.showTextDocument(textDoc); + } - let output = ``; - if (commandResult.stderr.length > 0) output += `${commandResult.stderr}\n\n`; - if (commandResult.stdout.length > 0) output += `${commandResult.stdout}\n\n`; + if (statement.content.trim().length > 0) { + try { + if (statement.type === `cl`) { + const commandResult = await vscode.commands.executeCommand(`code-for-ibmi.runCommand`, { + command: statement.content, + environment: `ile` + }); - const textDoc = await vscode.workspace.openTextDocument({language: `txt`, content: output}); - await vscode.window.showTextDocument(textDoc, { - preserveFocus: true, - preview: true - }); + if (commandResult.code === 0 || commandResult.code === null) { + vscode.window.showInformationMessage(`Command executed successfuly.`); + } else { + vscode.window.showErrorMessage(`Command failed to run.`); + } - } else { - statement.content = [ - `SET CURRENT SCHEMA = '${config.currentLibrary.toUpperCase()}'`, - statement.content - ].join(`;\n`); + let output = ``; + if (commandResult.stderr.length > 0) output += `${commandResult.stderr}\n\n`; + if (commandResult.stdout.length > 0) output += `${commandResult.stdout}\n\n`; - if (statement.type === `statement`) { - resultSetProvider.setLoadingText(`Executing statement...`); - } + const textDoc = await vscode.workspace.openTextDocument({language: `txt`, content: output}); + await vscode.window.showTextDocument(textDoc, { + preserveFocus: true, + preview: true + }); + + } else { + if (statement.type === `statement` && this.isBasicStatement(statement.content)) { + // If it's a basic statement, we can let it scroll! + resultSetProvider.setScrolling(statement.content); - const data = await content.runSQL(statement.content); - - if (data.length > 0) { - switch (statement.type) { - case `statement`: - resultSetProvider.setResults(data); - break; - - case `csv`: - case `json`: - case `sql`: - let content = ``; - switch (statement.type) { - case `csv`: content = csv.stringify(data, { - header: true, - quoted_string: true, - }); break; - case `json`: content = JSON.stringify(data, null, 2); break; - - case `sql`: - const keys = Object.keys(data[0]); - - const insertStatement = [ - `insert into TABLE (`, - ` ${keys.join(`, `)}`, - `) values `, - data.map( - row => ` (${keys.map(key => { - if (row[key] === null) return `null`; - if (typeof row[key] === `string`) return `'${row[key].replace(/'/g, `''`)}'`; - return row[key]; - }).join(`, `)})` - ).join(`,\n`), - ]; - content = insertStatement.join(`\n`); - break; + } else { + // Otherwise... it's a bit complicated. + statement.content = [ + `SET CURRENT SCHEMA = '${config.currentLibrary.toUpperCase()}'`, + statement.content + ].join(`;\n`); + + if (statement.type === `statement`) { + resultSetProvider.setLoadingText(`Executing statement...`); } - const textDoc = await vscode.workspace.openTextDocument({language: statement.type, content}); - await vscode.window.showTextDocument(textDoc); - break; + const data = await content.runSQL(statement.content); + + if (data.length > 0) { + switch (statement.type) { + case `statement`: + resultSetProvider.setResults(data); + break; + + case `csv`: + case `json`: + case `sql`: + let content = ``; + switch (statement.type) { + case `csv`: content = csv.stringify(data, { + header: true, + quoted_string: true, + }); break; + case `json`: content = JSON.stringify(data, null, 2); break; + + case `sql`: + const keys = Object.keys(data[0]); + + const insertStatement = [ + `insert into TABLE (`, + ` ${keys.join(`, `)}`, + `) values `, + data.map( + row => ` (${keys.map(key => { + if (row[key] === null) return `null`; + if (typeof row[key] === `string`) return `'${row[key].replace(/'/g, `''`)}'`; + return row[key]; + }).join(`, `)})` + ).join(`,\n`), + ]; + content = insertStatement.join(`\n`); + break; + } + + const textDoc = await vscode.workspace.openTextDocument({language: statement.type, content}); + await vscode.window.showTextDocument(textDoc); + break; + } + + } else { + if (statement.type === `statement`) { + resultSetProvider.setError(`Query executed with no data returned.`); + } else { + vscode.window.showInformationMessage(`Query executed with no data returned.`); + } + } } + } + } catch (e) { + let errorText; + if (typeof e === `string`) { + errorText = e.length > 0 ? e : `An error occurred when executing the statement.`; } else { - if (statement.type === `statement`) { - resultSetProvider.setError(`Query executed with no data returned.`); - } else { - vscode.window.showInformationMessage(`Query executed with no data returned.`); - } + errorText = e.message || `Error running SQL statement.`; } - } - } catch (e) { - let errorText; - if (typeof e === `string`) { - errorText = e.length > 0 ? e : `An error occurred when executing the statement.`; - } else { - errorText = e.message || `Error running SQL statement.`; - } - - if (statement.type === `statement`) { - resultSetProvider.setError(errorText); - } else { - vscode.window.showErrorMessage(errorText); + if (statement.type === `statement`) { + resultSetProvider.setError(errorText); + } else { + vscode.window.showErrorMessage(errorText); + } } } } - } - }), + }), ) } +exports.isBasicStatement = (statement) => { + const basicStatement = statement.trim().toUpperCase(); + + return basicStatement.startsWith(`SELECT`) && !basicStatement.includes(`LIMIT`); +} /** * @param {vscode.TextEditor} editor - * @returns {{type: "statement"|"cl"|"json"|"csv"|"sql", content: string}} Statement + * @returns {StatementInfo} Statement */ exports.parseStatement = (editor) => { const document = editor.document; diff --git a/src/views/schemaBrowser.js b/src/views/schemaBrowser.js index 09c69b02..7a4acc17 100644 --- a/src/views/schemaBrowser.js +++ b/src/views/schemaBrowser.js @@ -107,11 +107,14 @@ module.exports = class schemaBrowser { } }), - vscode.commands.registerCommand(`vscode-db2i.generateSelect`, async (object) => { + vscode.commands.registerCommand(`vscode-db2i.getResultSet`, async (object) => { if (object && object instanceof SQLObject) { - const content = `SELECT * FROM ${object.schema}.${object.name} as a;`; - const textDoc = await vscode.workspace.openTextDocument({language: `sql`, content}); - await vscode.window.showTextDocument(textDoc); + const content = `SELECT * FROM ${object.schema}.${object.name} as a`; + vscode.commands.executeCommand(`vscode-db2i.runEditorStatement`, { + content, + type: `statement`, + open: true, + }); } }),