
commit
8298c10732
24 changed files with 3252 additions and 0 deletions
-
4.gitignore
-
28.vscode/launch.json
-
9.vscode/settings.json
-
20.vscode/tasks.json
-
8.vscodeignore
-
7CHANGELOG.md
-
65README.md
-
2713package-lock.json
-
63package.json
-
5src/common/constants.ts
-
11src/common/outputChannel.ts
-
16src/common/utility.ts
-
20src/extension.ts
-
8src/model/INode.ts
-
11src/model/connection.ts
-
37src/model/connectionNode.ts
-
38src/model/databaseNode.ts
-
17src/model/infoNode.ts
-
43src/model/tableNode.ts
-
51src/mysqlTreeDataProvider.ts
-
22src/test/extension.test.ts
-
22src/test/index.ts
-
16tsconfig.json
-
18tslint.json
@ -0,0 +1,4 @@ |
|||
out |
|||
node_modules |
|||
.vscode-test/ |
|||
.vsix |
@ -0,0 +1,28 @@ |
|||
// A launch configuration that compiles the extension and then opens it inside a new window |
|||
{ |
|||
"version": "0.1.0", |
|||
"configurations": [ |
|||
{ |
|||
"name": "Extension", |
|||
"type": "extensionHost", |
|||
"request": "launch", |
|||
"runtimeExecutable": "${execPath}", |
|||
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ], |
|||
"stopOnEntry": false, |
|||
"sourceMaps": true, |
|||
"outFiles": [ "${workspaceRoot}/out/**/*.js" ], |
|||
"preLaunchTask": "npm: watch" |
|||
}, |
|||
{ |
|||
"name": "Extension Tests", |
|||
"type": "extensionHost", |
|||
"request": "launch", |
|||
"runtimeExecutable": "${execPath}", |
|||
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], |
|||
"stopOnEntry": false, |
|||
"sourceMaps": true, |
|||
"outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], |
|||
"preLaunchTask": "npm: watch" |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,9 @@ |
|||
// Place your settings in this file to overwrite default and user settings. |
|||
{ |
|||
"files.exclude": { |
|||
"out": false // set this to true to hide the "out" folder with the compiled JS files |
|||
}, |
|||
"search.exclude": { |
|||
"out": true // set this to false to include "out" folder in search results |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
// See https://go.microsoft.com/fwlink/?LinkId=733558 |
|||
// for the documentation about the tasks.json format |
|||
{ |
|||
"version": "2.0.0", |
|||
"tasks": [ |
|||
{ |
|||
"type": "npm", |
|||
"script": "watch", |
|||
"problemMatcher": "$tsc-watch", |
|||
"isBackground": true, |
|||
"presentation": { |
|||
"reveal": "never" |
|||
}, |
|||
"group": { |
|||
"kind": "build", |
|||
"isDefault": true |
|||
} |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,8 @@ |
|||
.vscode/** |
|||
.vscode-test/** |
|||
out/test/** |
|||
out/**/*.map |
|||
src/** |
|||
.gitignore |
|||
tsconfig.json |
|||
vsc-extension-quickstart.md |
@ -0,0 +1,7 @@ |
|||
# Change Log |
|||
All notable changes to the "mysql" extension will be documented in this file. |
|||
|
|||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. |
|||
|
|||
## [Unreleased] |
|||
- Initial release |
@ -0,0 +1,65 @@ |
|||
# mysql README |
|||
|
|||
This is the README for your extension "mysql". After writing up a brief description, we recommend including the following sections. |
|||
|
|||
## Features |
|||
|
|||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. |
|||
|
|||
For example if there is an image subfolder under your extension project workspace: |
|||
|
|||
\!\[feature X\]\(images/feature-x.png\) |
|||
|
|||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. |
|||
|
|||
## Requirements |
|||
|
|||
If you have any requirements or dependencies, add a section describing those and how to install and configure them. |
|||
|
|||
## Extension Settings |
|||
|
|||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. |
|||
|
|||
For example: |
|||
|
|||
This extension contributes the following settings: |
|||
|
|||
* `myExtension.enable`: enable/disable this extension |
|||
* `myExtension.thing`: set to `blah` to do something |
|||
|
|||
## Known Issues |
|||
|
|||
Calling out known issues can help limit users opening duplicate issues against your extension. |
|||
|
|||
## Release Notes |
|||
|
|||
Users appreciate release notes as you update your extension. |
|||
|
|||
### 1.0.0 |
|||
|
|||
Initial release of ... |
|||
|
|||
### 1.0.1 |
|||
|
|||
Fixed issue #. |
|||
|
|||
### 1.1.0 |
|||
|
|||
Added features X, Y, and Z. |
|||
|
|||
----------------------------------------------------------------------------------------------------------- |
|||
|
|||
## Working with Markdown |
|||
|
|||
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: |
|||
|
|||
* Split the editor (`Cmd+\` on OSX or `Ctrl+\` on Windows and Linux) |
|||
* Toggle preview (`Shift+CMD+V` on OSX or `Shift+Ctrl+V` on Windows and Linux) |
|||
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (OSX) to see a list of Markdown snippets |
|||
|
|||
### For more information |
|||
|
|||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) |
|||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) |
|||
|
|||
**Enjoy!** |
2713
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,63 @@ |
|||
{ |
|||
"name": "vscode-mysql", |
|||
"displayName": "MySQL", |
|||
"description": "MySQL for VS Code", |
|||
"version": "0.0.1", |
|||
"publisher": "formulahendry", |
|||
"engines": { |
|||
"vscode": "^1.18.0" |
|||
}, |
|||
"categories": [ |
|||
"Other" |
|||
], |
|||
"activationEvents": [ |
|||
"onView:mysql", |
|||
"onCommand:mysql.add" |
|||
], |
|||
"main": "./out/extension", |
|||
"contributes": { |
|||
"views": { |
|||
"explorer": [{ |
|||
"id": "mysql", |
|||
"name": "MySQL" |
|||
}] |
|||
}, |
|||
"commands": [{ |
|||
"command": "mysql.add", |
|||
"title": "Add" |
|||
}, |
|||
{ |
|||
"command": "mysql.selectTop1000", |
|||
"title": "Select Top 1000" |
|||
} |
|||
], |
|||
"menus": { |
|||
"view/title": [{ |
|||
"command": "mysql.add", |
|||
"when": "view == mysql", |
|||
"group": "navigation@1" |
|||
}], |
|||
"view/item/context": [{ |
|||
"command": "mysql.selectTop1000", |
|||
"when": "view == mysql && viewItem == table" |
|||
}] |
|||
} |
|||
}, |
|||
"scripts": { |
|||
"vscode:prepublish": "npm run compile", |
|||
"compile": "tsc -p ./", |
|||
"watch": "tsc -watch -p ./", |
|||
"postinstall": "node ./node_modules/vscode/bin/install", |
|||
"test": "npm run compile && node ./node_modules/vscode/bin/test" |
|||
}, |
|||
"devDependencies": { |
|||
"@types/mocha": "^2.2.42", |
|||
"@types/node": "^7.0.43", |
|||
"tslint": "^5.8.0", |
|||
"typescript": "^2.6.1", |
|||
"vscode": "^1.1.6" |
|||
}, |
|||
"dependencies": { |
|||
"mysql": "^2.15.0" |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
"user strict"; |
|||
|
|||
export class Constants { |
|||
public static GlobalStateMySQLConectionsKey = "mysql.connections"; |
|||
} |
@ -0,0 +1,11 @@ |
|||
"user strict"; |
|||
import * as vscode from "vscode"; |
|||
|
|||
export class OutputChannel { |
|||
public static appendLine(value: string) { |
|||
OutputChannel.outputChannel.show(); |
|||
OutputChannel.outputChannel.appendLine(value); |
|||
} |
|||
|
|||
private static outputChannel = vscode.window.createOutputChannel("MySQL"); |
|||
} |
@ -0,0 +1,16 @@ |
|||
"use strict"; |
|||
import * as vscode from "vscode"; |
|||
|
|||
export class Utility { |
|||
public static queryPromise<T>(connection, sql: string): Promise<T> { |
|||
return new Promise((resolve, reject) => { |
|||
connection.query(sql, (err, rows) => { |
|||
if (err) { |
|||
reject("MySQL Error: " + err.stack); |
|||
return; |
|||
} |
|||
resolve(rows); |
|||
}); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
"use strict"; |
|||
import * as vscode from "vscode"; |
|||
import { TableNode } from "./model/tableNode"; |
|||
import { MySQLTreeDataProvider } from "./mysqlTreeDataProvider"; |
|||
|
|||
export function activate(context: vscode.ExtensionContext) { |
|||
const mysqlTreeDataProvider = new MySQLTreeDataProvider(context); |
|||
context.subscriptions.push(vscode.window.registerTreeDataProvider("mysql", mysqlTreeDataProvider)); |
|||
|
|||
context.subscriptions.push(vscode.commands.registerCommand("mysql.add", () => { |
|||
mysqlTreeDataProvider.addConnection(); |
|||
})); |
|||
|
|||
context.subscriptions.push(vscode.commands.registerCommand("mysql.selectTop1000", (tableNode: TableNode) => { |
|||
tableNode.selectTop1000(); |
|||
})); |
|||
} |
|||
|
|||
export function deactivate() { |
|||
} |
@ -0,0 +1,8 @@ |
|||
import * as vscode from "vscode"; |
|||
|
|||
export interface INode { |
|||
|
|||
getTreeItem(): Promise<vscode.TreeItem> | vscode.TreeItem; |
|||
|
|||
getChildren(): Promise<INode[]> | INode[]; |
|||
} |
@ -0,0 +1,11 @@ |
|||
export interface IConnection { |
|||
readonly host: string; |
|||
readonly user: string; |
|||
readonly password: string; |
|||
} |
|||
|
|||
interface IConnection2 { |
|||
readonly host: string; |
|||
readonly user: string; |
|||
readonly password: string; |
|||
} |
@ -0,0 +1,37 @@ |
|||
import * as mysql from "mysql"; |
|||
import * as path from "path"; |
|||
import * as vscode from "vscode"; |
|||
import { Utility } from "../common/utility"; |
|||
import { DatabaseNode } from "./databaseNode"; |
|||
import { InfoNode } from "./infoNode"; |
|||
import { INode } from "./INode"; |
|||
|
|||
export class ConnectionNode implements INode { |
|||
constructor(private readonly host: string, private readonly user: string, private readonly password: string) { |
|||
} |
|||
|
|||
public getTreeItem(): vscode.TreeItem { |
|||
return { |
|||
label: this.host, |
|||
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, |
|||
contextValue: "connection", |
|||
}; |
|||
} |
|||
|
|||
public async getChildren(): Promise<INode[]> { |
|||
const connection = mysql.createConnection({ |
|||
host: this.host, |
|||
user: this.user, |
|||
password: this.password, |
|||
}); |
|||
return Utility.queryPromise<any[]>(connection, "SHOW DATABASES") |
|||
.then((databases) => { |
|||
return databases.map<DatabaseNode>((database) => { |
|||
return new DatabaseNode(this.host, this.user, this.password, database.Database); |
|||
}); |
|||
}) |
|||
.catch((err) => { |
|||
return [new InfoNode(err)]; |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
import * as mysql from "mysql"; |
|||
import * as path from "path"; |
|||
import * as vscode from "vscode"; |
|||
import { Utility } from "../common/utility"; |
|||
import { InfoNode } from "./infoNode"; |
|||
import { INode } from "./INode"; |
|||
import { TableNode } from "./tableNode"; |
|||
|
|||
export class DatabaseNode implements INode { |
|||
constructor(private readonly host: string, private readonly user: string, private readonly password: string, private readonly database: string) { |
|||
} |
|||
|
|||
public getTreeItem(): vscode.TreeItem { |
|||
return { |
|||
label: this.database, |
|||
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, |
|||
contextValue: "database", |
|||
}; |
|||
} |
|||
|
|||
public async getChildren(): Promise<INode[]> { |
|||
const connection = mysql.createConnection({ |
|||
host: this.host, |
|||
user: this.user, |
|||
password: this.password, |
|||
database: this.database, |
|||
}); |
|||
return Utility.queryPromise<any[]>(connection, `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${this.database}' LIMIT 50`) |
|||
.then((tables) => { |
|||
return tables.map<TableNode>((table) => { |
|||
return new TableNode(this.host, this.user, this.password, this.database, table.TABLE_NAME); |
|||
}); |
|||
}) |
|||
.catch((err) => { |
|||
return [new InfoNode(err)]; |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
import * as vscode from "vscode"; |
|||
import { INode } from "./INode"; |
|||
|
|||
export class InfoNode implements INode { |
|||
constructor(private readonly label: string) { |
|||
} |
|||
|
|||
public getTreeItem(): vscode.TreeItem { |
|||
return { |
|||
label: this.label, |
|||
}; |
|||
} |
|||
|
|||
public getChildren(): INode[] { |
|||
return []; |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
import * as mysql from "mysql"; |
|||
import * as path from "path"; |
|||
import * as vscode from "vscode"; |
|||
import { OutputChannel } from "../common/outputChannel"; |
|||
import { Utility } from "../common/utility"; |
|||
import { INode } from "./INode"; |
|||
|
|||
export class TableNode implements INode { |
|||
constructor(private readonly host: string, private readonly user: string, private readonly password: string, private readonly database: string, private readonly table: string) { |
|||
} |
|||
|
|||
public getTreeItem(): vscode.TreeItem { |
|||
return { |
|||
label: this.table, |
|||
collapsibleState: vscode.TreeItemCollapsibleState.None, |
|||
contextValue: "table", |
|||
}; |
|||
} |
|||
|
|||
public async getChildren(): Promise<INode[]> { |
|||
return []; |
|||
} |
|||
|
|||
public async selectTop1000() { |
|||
const sql = `SELECT * FROM ${this.database}.${this.table};`; |
|||
const textDocument = await vscode.workspace.openTextDocument({ content: sql, language: "sql" }); |
|||
vscode.window.showTextDocument(textDocument); |
|||
|
|||
const connection = mysql.createConnection({ |
|||
host: this.host, |
|||
user: this.user, |
|||
password: this.password, |
|||
database: this.database, |
|||
}); |
|||
Utility.queryPromise<any[]>(connection, sql) |
|||
.then((result) => { |
|||
OutputChannel.appendLine(JSON.stringify(result, null, 2)); |
|||
}) |
|||
.catch((err) => { |
|||
vscode.window.showErrorMessage(err); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,51 @@ |
|||
import * as path from "path"; |
|||
import * as vscode from "vscode"; |
|||
import { Constants } from "./common/constants"; |
|||
import { IConnection } from "./model/connection"; |
|||
import { ConnectionNode } from "./model/connectionNode"; |
|||
import { INode } from "./model/INode"; |
|||
|
|||
export class MySQLTreeDataProvider implements vscode.TreeDataProvider<INode> { |
|||
public _onDidChangeTreeData: vscode.EventEmitter<INode> = new vscode.EventEmitter<INode>(); |
|||
public readonly onDidChangeTreeData: vscode.Event<INode> = this._onDidChangeTreeData.event; |
|||
|
|||
constructor(private context: vscode.ExtensionContext) { |
|||
} |
|||
|
|||
public getTreeItem(element: INode): Promise<vscode.TreeItem> | vscode.TreeItem { |
|||
return element.getTreeItem(); |
|||
} |
|||
|
|||
public getChildren(element?: INode): Thenable<INode[]> | INode[] { |
|||
if (!element) { |
|||
return this.getConnectionNodes(); |
|||
} |
|||
|
|||
return element.getChildren(); |
|||
} |
|||
|
|||
public async addConnection() { |
|||
let connections = this.context.globalState.get<IConnection[]>(Constants.GlobalStateMySQLConectionsKey); |
|||
if (!connections) { |
|||
connections = []; |
|||
} |
|||
connections.push({ |
|||
host: "abc", |
|||
user: "mysqluser@hendry-mysql", |
|||
password: "", |
|||
}); |
|||
await this.context.globalState.update(Constants.GlobalStateMySQLConectionsKey, connections); |
|||
this.refresh(); |
|||
} |
|||
|
|||
private refresh(element?: INode): void { |
|||
this._onDidChangeTreeData.fire(element); |
|||
} |
|||
|
|||
private getConnectionNodes(): ConnectionNode[] { |
|||
const connections = this.context.globalState.get<IConnection[]>(Constants.GlobalStateMySQLConectionsKey); |
|||
return connections.map<ConnectionNode>((connection) => { |
|||
return new ConnectionNode(connection.host, connection.user, connection.password); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
//
|
|||
// Note: This example test is leveraging the Mocha test framework.
|
|||
// Please refer to their documentation on https://mochajs.org/ for help.
|
|||
//
|
|||
|
|||
// The module 'assert' provides assertion methods from node
|
|||
import * as assert from 'assert'; |
|||
|
|||
// You can import and use all API from the 'vscode' module
|
|||
// as well as import your extension to test it
|
|||
import * as vscode from 'vscode'; |
|||
import * as myExtension from '../extension'; |
|||
|
|||
// Defines a Mocha test suite to group tests of similar kind together
|
|||
suite("Extension Tests", () => { |
|||
|
|||
// Defines a Mocha unit test
|
|||
test("Something 1", () => { |
|||
assert.equal(-1, [1, 2, 3].indexOf(5)); |
|||
assert.equal(-1, [1, 2, 3].indexOf(0)); |
|||
}); |
|||
}); |
@ -0,0 +1,22 @@ |
|||
//
|
|||
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
|
|||
//
|
|||
// This file is providing the test runner to use when running extension tests.
|
|||
// By default the test runner in use is Mocha based.
|
|||
//
|
|||
// You can provide your own test runner if you want to override it by exporting
|
|||
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
|
|||
// host can call to run the tests. The test runner is expected to use console.log
|
|||
// to report the results back to the caller. When the tests are finished, return
|
|||
// a possible error to the callback or null if none.
|
|||
|
|||
import * as testRunner from 'vscode/lib/testrunner'; |
|||
|
|||
// You can directly control Mocha options by uncommenting the following lines
|
|||
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
|
|||
testRunner.configure({ |
|||
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
|
|||
useColors: true // colored output from test results
|
|||
}); |
|||
|
|||
module.exports = testRunner; |
@ -0,0 +1,16 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"module": "commonjs", |
|||
"target": "es6", |
|||
"outDir": "out", |
|||
"lib": [ |
|||
"es6" |
|||
], |
|||
"sourceMap": true, |
|||
"rootDir": "src" |
|||
}, |
|||
"exclude": [ |
|||
"node_modules", |
|||
".vscode-test" |
|||
] |
|||
} |
@ -0,0 +1,18 @@ |
|||
{ |
|||
"extends": "tslint:recommended", |
|||
"rules": { |
|||
"variable-name": [ |
|||
true, |
|||
"ban-keywords", |
|||
"check-format", |
|||
"allow-pascal-case", |
|||
"allow-leading-underscore" |
|||
], |
|||
"max-line-length": [ |
|||
true, |
|||
200 |
|||
], |
|||
"no-empty": false, |
|||
"object-literal-sort-keys": false |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue