-
Notifications
You must be signed in to change notification settings - Fork 59
Edit database connections #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
fc471e7
10e0ebc
a7dff3d
4c7fc22
69dab38
2472efd
9e90c2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,13 @@ | |
| import * as asciitable from "asciitable"; | ||
| import * as fs from "fs"; | ||
| import * as mysql from "mysql"; | ||
| import * as uuidv1 from "uuid/v1"; | ||
| import * as vscode from "vscode"; | ||
| import { IConnection } from "../model/connection"; | ||
| import { ConnectionNode } from "../model/connectionNode"; | ||
| import { MySQLTreeDataProvider } from "../mysqlTreeDataProvider"; | ||
| import { AppInsightsClient } from "./appInsightsClient"; | ||
| import { Constants } from "./constants"; | ||
| import { Global } from "./global"; | ||
| import { OutputChannel } from "./outputChannel"; | ||
|
|
||
|
|
@@ -47,7 +51,7 @@ export class Utility { | |
| sql = sql ? sql : vscode.window.activeTextEditor.document.getText(); | ||
| connectionOptions = connectionOptions ? connectionOptions : Global.activeConnection; | ||
| connectionOptions.multipleStatements = true; | ||
| const connection = Utility.createConnection(connectionOptions); | ||
| const connection = Utility.createMySQLConnection(connectionOptions); | ||
|
|
||
| OutputChannel.appendLine("[Start] Executing MySQL query..."); | ||
| connection.query(sql, (err, rows) => { | ||
|
|
@@ -82,7 +86,7 @@ export class Utility { | |
| return vscode.window.showTextDocument(textDocument); | ||
| } | ||
|
|
||
| public static createConnection(connectionOptions: IConnection): any { | ||
| public static createMySQLConnection(connectionOptions: IConnection): any { | ||
| const newConnectionOptions: any = Object.assign({}, connectionOptions); | ||
| if (connectionOptions.certPath && fs.existsSync(connectionOptions.certPath)) { | ||
| newConnectionOptions.ssl = { | ||
|
|
@@ -92,6 +96,78 @@ export class Utility { | |
| return mysql.createConnection(newConnectionOptions); | ||
| } | ||
|
|
||
| public static async editConnection(connectionNode: ConnectionNode, context: vscode.ExtensionContext, mysqlTreeDataProvider: MySQLTreeDataProvider) { | ||
| if (connectionNode) { | ||
| connectionNode.editConnection(context, mysqlTreeDataProvider); | ||
| } else { | ||
| const selectedConnection = await Utility.pickConnection(context); | ||
| if (selectedConnection !== undefined) { | ||
| const dummyNode = new ConnectionNode(selectedConnection.id, selectedConnection.host, selectedConnection.user, selectedConnection.password, | ||
| selectedConnection.port, selectedConnection.certPath); | ||
|
|
||
| dummyNode.editConnection(context, mysqlTreeDataProvider); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static async deleteConnection(connectionNode: ConnectionNode, context: vscode.ExtensionContext, mysqlTreeDataProvider: MySQLTreeDataProvider) { | ||
| if (connectionNode) { | ||
| connectionNode.deleteConnection(context, mysqlTreeDataProvider); | ||
| } else { | ||
| const selectedConnection = await Utility.pickConnection(context); | ||
| if (selectedConnection !== undefined) { | ||
| const dummyNode = new ConnectionNode(selectedConnection.id, selectedConnection.host, selectedConnection.user, selectedConnection.password, | ||
| selectedConnection.port, selectedConnection.certPath); | ||
|
|
||
| dummyNode.deleteConnection(context, mysqlTreeDataProvider); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static async createConnectionFromInput(context: vscode.ExtensionContext, copyFrom?: IConnection): Promise<IConnection> { | ||
| const host = await vscode.window.showInputBox({ prompt: "The hostname of the database", placeHolder: "host", ignoreFocusOut: true, value: copyFrom !== undefined ? copyFrom.host : ""}); | ||
| if (!host) { | ||
| return; | ||
| } | ||
|
|
||
| const user = await vscode.window.showInputBox({ prompt: "The MySQL user to authenticate as", placeHolder: "user", ignoreFocusOut: true, value: copyFrom !== undefined ? copyFrom.user : "" }); | ||
| if (!user) { | ||
| return; | ||
| } | ||
|
|
||
| const pw = copyFrom !== undefined ? await Global.keytar.getPassword(Constants.ExtensionId, copyFrom.id) : ""; | ||
| const password = await vscode.window.showInputBox({ prompt: "The password of the MySQL user", placeHolder: "password", | ||
| ignoreFocusOut: true, password: true, | ||
| value: pw }); | ||
| if (password === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| const port = await vscode.window.showInputBox({ prompt: "The port number to connect to", placeHolder: "port", ignoreFocusOut: true, value: copyFrom !== undefined ? copyFrom.port : "" }); | ||
| if (!port) { | ||
| return; | ||
| } | ||
|
|
||
| const certPath = await vscode.window.showInputBox({ prompt: "[Optional] SSL certificate path. Leave empty to ignore", placeHolder: "certificate file path", ignoreFocusOut: true, | ||
| value: copyFrom !== undefined ? copyFrom.certPath : "" }); | ||
| if (certPath === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| const connection: IConnection = { | ||
| host, | ||
| user, | ||
| password, | ||
| port, | ||
| certPath, | ||
| }; | ||
|
|
||
| const id = copyFrom ? copyFrom.id : uuidv1(); | ||
| connection.id = id; | ||
|
|
||
| return connection; | ||
| } | ||
|
|
||
| private static async hasActiveConnection(): Promise<boolean> { | ||
| let count = 5; | ||
| while (!Global.activeConnection && count > 0) { | ||
|
|
@@ -106,4 +182,32 @@ export class Utility { | |
| setTimeout(resolve, ms); | ||
| }); | ||
| } | ||
|
|
||
| private static async pickConnection(context: vscode.ExtensionContext): Promise<IConnection> { | ||
| let selectedConnection; | ||
|
|
||
| const connections = context.globalState.get<{ [key: string]: IConnection }>(Constants.GlobalStateMySQLConectionsKey); | ||
| const items: vscode.QuickPickItem[] = []; | ||
|
|
||
| if (connections) { | ||
| for (const id of Object.keys(connections)) { | ||
| const item = connections[id]; | ||
| items.push({ | ||
| label: item.host, | ||
| description: item.user}); | ||
| } | ||
| } | ||
|
|
||
| await vscode.window.showQuickPick(items).then(async (selection) => { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use: |
||
| // the user canceled the selection | ||
| if (!selection) { | ||
| return selectedConnection; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could be just |
||
| } | ||
|
|
||
| const selectedConnectionId = Object.keys(connections)[items.indexOf(selection)]; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if there are two connections have the same host and user?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You would still get the correct selection from the pick menu.. but you wont be able to differ from the two when the menu is shown.. how would you enable anyone to see the difference between two connections with the same host and user? showing the internal id of the connection wont be to much use for the user.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we could still get the correct selection from the pick menu, then it will be OK. No extra change needed. |
||
| selectedConnection = connections[selectedConnectionId]; | ||
| selectedConnection.id = selectedConnectionId; | ||
| }); | ||
| return selectedConnection; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ export class ConnectionNode implements INode { | |
| } | ||
|
|
||
| public async getChildren(): Promise<INode[]> { | ||
| const connection = Utility.createConnection({ | ||
| const connection = Utility.createMySQLConnection({ | ||
| host: this.host, | ||
| user: this.user, | ||
| password: this.password, | ||
|
|
@@ -61,6 +61,15 @@ export class ConnectionNode implements INode { | |
| } | ||
|
|
||
| public async deleteConnection(context: vscode.ExtensionContext, mysqlTreeDataProvider: MySQLTreeDataProvider) { | ||
| const options: vscode.MessageOptions = { | ||
| modal: true, | ||
| }; | ||
| const answer = await vscode.window.showWarningMessage(`Are you sure you want to delete ${this.host}?`, options, "Delete connection"); | ||
|
|
||
| if (answer === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| AppInsightsClient.sendEvent("deleteConnection"); | ||
| const connections = context.globalState.get<{ [key: string]: IConnection }>(Constants.GlobalStateMySQLConectionsKey); | ||
| delete connections[this.id]; | ||
|
|
@@ -70,4 +79,37 @@ export class ConnectionNode implements INode { | |
|
|
||
| mysqlTreeDataProvider.refresh(); | ||
| } | ||
|
|
||
| public async editConnection(context: vscode.ExtensionContext, mysqlTreeDataProvider: MySQLTreeDataProvider) { | ||
| AppInsightsClient.sendEvent("editConncetion.start"); | ||
|
|
||
| const copyFrom: IConnection = { | ||
| id: this.id, | ||
| host: this.host, | ||
| user: this.user, | ||
| password: this.password, | ||
| port: this.port, | ||
| certPath: this.certPath, | ||
| }; | ||
| const editConnection = await Utility.createConnectionFromInput(context, copyFrom); | ||
|
|
||
| if (editConnection !== undefined) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is similar to addConnection. Please help merge them.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Merge them into a addOrEditConnection method?
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could wrap these similar code snippet into a method into https://github.com/formulahendry/vscode-mysql/blob/master/src/common/utility.ts
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (We still keep editConnection in connectionNode and addConnection in mysqlTreeDataProvider, and call shared method in utility) |
||
| let connections = await context.globalState.get<{ [key: string]: IConnection }>(Constants.GlobalStateMySQLConectionsKey); | ||
|
|
||
| if (!connections) { | ||
| connections = {}; | ||
| } | ||
|
|
||
| connections[editConnection.id] = editConnection; | ||
|
|
||
| if (editConnection.password) { | ||
| await Global.keytar.setPassword(Constants.ExtensionId, editConnection.id, editConnection.password); | ||
| } | ||
|
|
||
| await context.globalState.update(Constants.GlobalStateMySQLConectionsKey, connections); | ||
| mysqlTreeDataProvider.refresh(); | ||
| } | ||
|
|
||
| AppInsightsClient.sendEvent("editConncetion.end"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,7 @@ export class TableNode implements INode { | |
| } | ||
|
|
||
| public async getChildren(): Promise<INode[]> { | ||
| const connection = Utility.createConnection({ | ||
| const connection = Utility.createMySQLConnection({ | ||
| host: this.host, | ||
| user: this.user, | ||
| password: this.password, | ||
|
|
@@ -62,4 +62,31 @@ export class TableNode implements INode { | |
|
|
||
| Utility.runQuery(sql, connection); | ||
| } | ||
|
|
||
| public async dropTable() { | ||
| const options: vscode.MessageOptions = { | ||
| modal: true, | ||
| }; | ||
| const answer = await vscode.window.showWarningMessage(`Are you sure you want to drop table ${this.table}?`, options, "Drop table"); | ||
|
|
||
| if (answer === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| AppInsightsClient.sendEvent("drop table"); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dropTable |
||
| const sql = `DROP TABLE ${this.database}.${this.table}`; | ||
| Utility.createSQLTextDocument(sql); | ||
|
|
||
| const connection = { | ||
| host: this.host, | ||
| user: this.user, | ||
| password: this.password, | ||
| port: this.port, | ||
| database: this.database, | ||
| certPath: this.certPath, | ||
| }; | ||
| Global.activeConnection = connection; | ||
|
|
||
| Utility.runQuery(sql, connection); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about refreshing the table list after deletion is successful?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do i refresh the databaseNode from inside the tableNode class? I want to call:
How can i get the "parent" databaseNode for a tableNode?
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could pass
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright ill look into that |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this before
mysql.deleteConnection