Skip to content

Commit

Permalink
Merge commit '93754fe80c0d498d0f13b9ea494ae5649043cf09'
Browse files Browse the repository at this point in the history
  • Loading branch information
ernstc committed Aug 23, 2024
2 parents ab9331a + 93754fe commit 1b0e2d2
Show file tree
Hide file tree
Showing 13 changed files with 1,975 additions and 367 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Please leave a ⭐ as motivation if this tool is helpful for you!

## Features

* Supports Microsoft SQL Server, MySQL.
* Start inspecting data from the server explorer or from the query editor.
* Shows the list of tables and views of the database.
* Shows the list of columns of the selected table or view.
Expand All @@ -23,6 +22,9 @@ Please leave a ⭐ as motivation if this tool is helpful for you!
* Live monitoring mode for periodically refreshing the views.
* Each selectable element can be copied with CTRL+C.
* All distinct values and counts for a column, can be copied in the clipboard. You can then paste the values in Excel for further analysis, for instance.
* Support for **Microsoft SQL Server**.
* Support for **MySQL** by installing the extension `Microsoft.azuredatastudio-mysql`.
* Support for **PostgresSQL** by installing the extension `Microsoft.azuredatastudio-postgresql`.

### Inspecting data from the server explorer

Expand Down
1,515 changes: 1,246 additions & 269 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "sql-data-inspector",
"displayName": "SQL Data Inspector",
"description": "This extension makes it easy to inspect data with just a few clicks.",
"version": "0.8.0",
"version": "0.8.0-postgres",
"publisher": "ernstc",
"license": "MIT",
"icon": "images/icon.png",
Expand Down Expand Up @@ -39,6 +39,11 @@
"command": "sql-data-inspector.inspect-data",
"when": "connectionProvider == MySQL && nodeType && nodeType == Database",
"group": "data"
},
{
"command": "sql-data-inspector.inspect-data",
"when": "connectionProvider == PGSQL && nodeType && nodeType == Database",
"group": "data"
}
],
"editor/context": [
Expand Down Expand Up @@ -138,18 +143,18 @@
"@typescript-eslint/eslint-plugin": "^7.5.0",
"@typescript-eslint/parser": "^7.5.0",
"@vscode/test-electron": "^2.3.9",
"@vscode/vsce": "^2.24.0",
"@vscode/vsce": "^2.29.0",
"ansi-regex": "6.0.1",
"eslint": "^8.57.0",
"glob": "^8.1.0",
"markdown-it": "^14.1.0",
"mkdirp": "^3.0.1",
"mocha": "^10.4.0",
"ncp": "^2.0.0",
"rimraf": "^5.0.5",
"rimraf": "^5.0.8",
"ts-loader": "^9.5.1",
"typescript": "^5.4.3",
"webpack": "^5.91.0",
"typescript": "^5.5.3",
"webpack": "^5.92.1",
"webpack-cli": "^5.1.4"
}
}
24 changes: 22 additions & 2 deletions src/connection-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,32 @@ export class ConnectionContext {
public fqname: FQName;
public repository?: IDbRepository;

private connectionProfile?: azdata.IConnectionProfile
private connectionUri?: string;
private queryProvider?: azdata.QueryProvider;

public constructor(fqname: FQName, connection: azdata.connection.Connection) {
this.fqname = fqname;
this.connection = connection;
this.connectionId = connection.connectionId;
}

public async getConnectionUri() {
if (this.connectionUri === undefined) {
this.connectionUri = await azdata.connection.getUriForConnection(this.connectionId);
}
return this.connectionUri;
}

public async runQueryAndReturn(query: string) {
if (this.queryProvider === undefined) {
this.queryProvider = azdata.dataprotocol.getProvider(this.connection.providerName, azdata.DataProviderType.QueryProvider);
}
const connectionUri = await this.getConnectionUri();
const result = await this.queryProvider.runQueryAndReturn(connectionUri, query);
return result;
}

// static factory method for Explorer context
public static async ExplorerContext(iConnProfile: azdata.IConnectionProfile, fqname: FQName) {
let activeConnections = await azdata.connection.getActiveConnections();
Expand All @@ -35,14 +55,13 @@ export class ConnectionContext {
}

// static factory method for Editor context
public static async EditerContext(connProfile: azdata.connection.ConnectionProfile, fqname: FQName) {
public static async EditorContext(connProfile: azdata.connection.ConnectionProfile, fqname: FQName) {
let connection = await this.getConnection(connProfile.connectionId, fqname.databaseName);
return new this(fqname, connection);
}

public static async getConnection(connectionId: string, databaseName?: string) {
let activeConnections = await azdata.connection.getActiveConnections();
//const iConnProfile = { ...connectionProfile, providerName: connectionProfile.providerId, id: '' };

let connection: azdata.connection.Connection | undefined = activeConnections.filter(c => c.connectionId === connectionId)[0];

Expand All @@ -64,6 +83,7 @@ export class ConnectionContext {
let activeConnections = await azdata.connection.getActiveConnections();
return activeConnections.filter(c => c.connectionId === connection.connectionId)[0];
}
connectionProvider.disconnect(connectionUri);
}

public static getSelectedEditorText() {
Expand Down
111 changes: 80 additions & 31 deletions src/controllers/visualization.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { VscodeSettings } from "../vscodeSettings";

interface IIncomingMessage {
command: string;
commandSessionId: string;
item?: any;
viewModel?: ViewModel;
index?: number;
Expand Down Expand Up @@ -61,7 +62,7 @@ const postMessage = (webview: azdata.DashboardWebview | vscode.Webview, message:

const renderWebviewContent = async (webview: vscode.Webview, connectionContext: ConnectionContext) => {
webview.html = loadWebView();
if (/*connectionContext.connection?.options.database &&*/ connectionContext.connectionId) {
if (connectionContext.connectionId) {

let vscodeSettings = VscodeSettings.getInstance();
let viewModel = new ViewModel();
Expand Down Expand Up @@ -96,29 +97,29 @@ const renderWebviewContent = async (webview: vscode.Webview, connectionContext:
await loadObjects(repository, webview, viewModel);
// also load the columns and rows when starting with a selected table
if (connectionContext.fqname.tableName !== undefined) {
await loadColumns(repository, webview, viewModel);
await loadRows(repository, webview, viewModel);
await loadColumns(data.commandSessionId, repository, webview, viewModel);
await loadRows(data.commandSessionId, repository, webview, viewModel);
}
break;
}
case 'loadColumns': {
await loadColumns(repository, webview, viewModel);
await loadColumns(data.commandSessionId, repository, webview, viewModel);
break;
}
case 'reorderColumns': {
await reorderColumns(repository, webview, viewModel);
await reorderColumns(data.commandSessionId, repository, webview, viewModel);
break;
}
case 'loadValues': {
await loadValues(repository, webview, viewModel);
await loadValues(data.commandSessionId, repository, webview, viewModel);
break;
}
case 'loadRows': {
await loadRows(repository, webview, viewModel);
await loadRows(data.commandSessionId, repository, webview, viewModel);
break;
}
case 'loadRowsCount': {
await loadRowsCount(repository, webview, viewModel, data.index!);
await loadRowsCount(data.commandSessionId, repository, webview, viewModel, data.index!);
break;
}
case 'copyText': {
Expand Down Expand Up @@ -162,7 +163,7 @@ const renderWebviewContent = async (webview: vscode.Webview, connectionContext:
}
}
viewModel.rowsPageIndex = pageIndex;
await loadRows(repository, webview, viewModel);
await loadRows(data.commandSessionId, repository, webview, viewModel);
}
}
}
Expand Down Expand Up @@ -291,7 +292,9 @@ const loadObjects = async (repository: IDbRepository, webview: azdata.DashboardW
status: Status.GettingObjectsData,
});

viewModel.objects = await repository.getDbObjects();
const results = await repository.getDbObjects('');

viewModel.objects = results.data;
viewModel.objectsSchema = [...new Set(viewModel.objects.map(t => t.Schema))];
viewModel.columns = undefined;
viewModel.values = undefined;
Expand Down Expand Up @@ -337,17 +340,6 @@ const loadObjects = async (repository: IDbRepository, webview: azdata.DashboardW
&& viewModel.filterObjectsSchema !== '*') {
viewModel.objects = viewModel.objects.filter(t => t.Schema === viewModel.filterObjectsSchema);

//viewModel.columns = undefined;
//viewModel.values = undefined;
//viewModel.rowsColumnsName = undefined;
//viewModel.rows = undefined
//viewModel.rowsCount = undefined;
//viewModel.selectedTableIndex = undefined;
//viewModel.selectedColumnIndex = undefined;
//viewModel.selectedValueIndex = undefined;
//viewModel.selectedRowRowIndex = undefined;
//viewModel.selectedRowColumnIndex = undefined;

postMessage(webview, {
status: Status.RenderingData,
objects: viewModel.objects,
Expand All @@ -370,10 +362,24 @@ const loadObjects = async (repository: IDbRepository, webview: azdata.DashboardW
};


const loadColumns = async (repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
var loadColumnsSessionId: string;

const loadColumns = async (sessionId: string, repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
const object = viewModel.selectedObject!;

viewModel.columns = await repository.getDbColumns(object, viewModel.sortColumnNames);
loadColumnsSessionId = sessionId;

const results = await repository.getDbColumns(sessionId, object, viewModel.sortColumnNames);
if (
results.sessionId !== loadColumnsSessionId
|| viewModel.selectedObject?.Name !== object.Name
|| viewModel.selectedObject?.Schema !== object.Schema
) {
return;
}

viewModel.columns = results.data;
viewModel.columnsRelativeToObject = object;
viewModel.values = undefined;
viewModel.selectedColumnIndex = undefined;
viewModel.selectedValueIndex = undefined;
Expand All @@ -387,14 +393,21 @@ const loadColumns = async (repository: IDbRepository, webview: azdata.DashboardW
};


const reorderColumns = async (repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
const reorderColumns = async (sessionId: string, repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
const object = viewModel.selectedObject!;

const selectedColumnName = (viewModel.columns != undefined && viewModel.selectedColumnIndex != undefined) ?
viewModel.columns![viewModel.selectedColumnIndex!].Name :
undefined;

viewModel.columns = await repository.getDbColumns(object, viewModel.sortColumnNames);
loadColumnsSessionId = sessionId;

const results = await repository.getDbColumns(sessionId, object, viewModel.sortColumnNames);
if (results.sessionId !== loadColumnsSessionId) {
return;
}

viewModel.columns = results.data;

viewModel.selectedColumnIndex = selectedColumnName != undefined ?
viewModel.columns.findIndex(c => c.Name === selectedColumnName) :
Expand All @@ -410,17 +423,27 @@ const reorderColumns = async (repository: IDbRepository, webview: azdata.Dashboa
};


const loadValues = async (repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
var loadValuesSessionId: string;

const loadValues = async (sessionId: string, repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
const object = viewModel.selectedObject!;
const column = viewModel.selectedColumn!;

viewModel.values = await repository.getDbColumnValuesWithCount(
loadValuesSessionId = sessionId;

const results = await repository.getDbColumnValuesWithCount(
sessionId,
object, column,
viewModel.filter!,
viewModel.sortAscendingColumnValues,
viewModel.sortAscendingColumnValuesCount
);

if (results.sessionId !== loadValuesSessionId) {
return;
}

viewModel.values = results.data;
viewModel.selectedValueIndex = undefined;

postMessage(webview, {
Expand All @@ -434,14 +457,24 @@ const loadValues = async (repository: IDbRepository, webview: azdata.DashboardWe
};


const loadRows = async (repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
var loadRowsSessionId: string;

const loadRows = async (sessionId: string, repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel) => {
if (viewModel.selectedObject === undefined) {
await setViewModel(webview, viewModel);
return;
}

const object = viewModel.selectedObject;

if (
viewModel.columnsRelativeToObject?.Name !== object.Name
|| viewModel.columnsRelativeToObject?.Schema !== object.Schema
)
{
return;
}

let orderByColumns: string[] | undefined;
let sortAscending: boolean[] | undefined;

Expand All @@ -462,7 +495,14 @@ const loadRows = async (repository: IDbRepository, webview: azdata.DashboardWebv
sortAscending = primaryKey?.map(p => true);
}

const dbRows = await repository.getDbTableRows(object, viewModel.columns, viewModel.filter!, orderByColumns, sortAscending, viewModel.rowsPageIndex, viewModel.rowsPageSize);
loadRowsSessionId = sessionId;

const results = await repository.getDbTableRows(sessionId, object, viewModel.columns, viewModel.filter!, orderByColumns, sortAscending, viewModel.rowsPageIndex, viewModel.rowsPageSize);
if (results.sessionId !== loadRowsSessionId) {
return;
}

const dbRows = results.data;
object.Count = dbRows.count.toString();
let columnsName: string[] = [];

Expand Down Expand Up @@ -501,13 +541,22 @@ const loadRows = async (repository: IDbRepository, webview: azdata.DashboardWebv
};


const loadRowsCount = async (repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel, index: number) => {
var loadRowsCountSessionId: string;

const loadRowsCount = async (sessionId: string, repository: IDbRepository, webview: azdata.DashboardWebview | vscode.Webview, viewModel: ViewModel, index: number) => {
const object = viewModel.objects ? viewModel.objects[index] : undefined;
if (object === undefined) {
return;
}

const dbRowsCount = await repository.getDbTableRowsCount(object, viewModel.filter!);
loadRowsCountSessionId = sessionId;

const results = await repository.getDbTableRowsCount(sessionId, object, viewModel.filter!);
if (results.sessionId !== loadRowsCountSessionId) {
return;
}

const dbRowsCount = results.data;
object.Count = dbRowsCount.count.toString();

postMessage(webview, {
Expand Down
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const loadVisualizationFromEditor = async (context: azdata.ObjectExplorerContext
}

// Get the active connection information
let connectionContext = await ConnectionContext.EditerContext(connProfile, fqname);
let connectionContext = await ConnectionContext.EditorContext(connProfile, fqname);

// Create and show a new webview
const panel = vscode.window.createWebviewPanel(
Expand Down
1 change: 1 addition & 0 deletions src/models/view.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class ViewModel {
objects?: DatabaseObject[];
objectsSchema?: string[];
columns?: DatabaseColumn[];
columnsRelativeToObject?: DatabaseObject;
values?: DatabaseColumnValue[];
rows?: DatabaseTableRow[];
rowsCount?: number;
Expand Down
Loading

0 comments on commit 1b0e2d2

Please sign in to comment.