Skip to content

Commit

Permalink
Big Fixes from suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
prajwal-pai77 committed Jul 18, 2024
1 parent 8241aa0 commit cfc0dd9
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 69 deletions.
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,11 @@
"title": "Delete Cluster Connection",
"category": "Couchbase"
},
{
"command": "vscode-couchbase.deleteSearchIndex",
"title": "Delete Search Index",
"category": "Couchbase"
},
{
"command": "vscode-couchbase.useClusterConnection",
"title": "Connect to Cluster",
Expand Down Expand Up @@ -851,6 +856,10 @@
"command": "vscode-couchbase.openSearchWorkbench",
"when": "false"
},
{
"command": "vscode-couchbase.deleteSearchIndex",
"when": "false"
},
{
"command": "vscode-couchbase.deleteClusterConnection",
"when": "false"
Expand Down Expand Up @@ -1033,11 +1042,21 @@
"when": "view == couchbase && viewItem == active_connection && !isKVCluster",
"group": "workbench@1"
},
{
"command": "vscode-couchbase.openSearchWorkbench",
"when": "view == couchbase && viewItem == active_connection && !isKVCluster && isSearchEnabled",
"group": "workbench@1"
},
{
"command": "vscode-couchbase.openSearchWorkbench",
"when": "view == couchbase && viewItem == searchIndex && !isKVCluster && isSearchEnabled",
"group": "workbench@1"
},
{
"command": "vscode-couchbase.deleteSearchIndex",
"when": "view == couchbase && viewItem == searchIndex && !isKVCluster && isSearchEnabled",
"group": "workbench@2"
},
{
"submenu": "vscode-couchbase.toolsMenu",
"when": "view == couchbase && viewItem == active_connection"
Expand Down
1 change: 1 addition & 0 deletions src/commands/extensionCommands/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export namespace Commands {
export const openQueryNotebook: string = "vscode-couchbase.openQueryNotebook";
export const openQueryWorkbench: string = "vscode-couchbase.openQueryWorkbench";
export const openSearchWorkbench: string = "vscode-couchbase.openSearchWorkbench";
export const deleteSearchIndex: string = "vscode-couchbase.deleteSearchIndex";
export const getSampleProjects: string = "vscode-couchbase.openSampleProjects";
export const loadMore: string = "vscode-couchbase.loadMore";
export const showOutputConsole: string = "vscode-couchbase.showOutputConsole";
Expand Down
15 changes: 9 additions & 6 deletions src/commands/fts/SearchWorkbench/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@ export default class UntitledSearchJsonDocumentService {


public async openSearchJsonTextDocument(searchIndexNode: SearchIndexNode, memFs: MemFS): Promise<vscode.TextEditor> {
const uri = vscode.Uri.parse(`couchbase:/search-workbench-${searchIndexNode.searchIndexName}-${this.untitledCount}.cbs.json`);
const uri = vscode.Uri.parse(`couchbase:/search-workbench-${searchIndexNode.indexName}-${this.untitledCount}.cbs.json`);
this.untitledCount++;
const defaultJsonContent = `{
"query": {
"query": "your_query_here"
},
"fields": ["*"]
const defaultJsonContent =
`{
"query": {
"query": "your_query_here"
},
"fields": [
"*"
]
}`;
let documentContent = Buffer.from(defaultJsonContent);
memFs.writeFile(uri, documentContent, {
Expand Down
86 changes: 67 additions & 19 deletions src/commands/fts/SearchWorkbench/searchWorkbench.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from 'vscode';
import { getActiveConnection } from '../../../util/connections';
import { WorkbenchWebviewProvider } from '../../../workbench/workbenchWebviewProvider';
import { CouchbaseError, QueryOptions, QueryProfileMode, QueryStatus } from "couchbase";
import { QueryStatus } from "couchbase";
import { ISearchQueryContext } from '../../../types/ISearchQueryContext';
import { CouchbaseRestAPI } from '../../../util/apis/CouchbaseRestAPI';
import { MemFS } from "../../../util/fileSystemProvider";
Expand Down Expand Up @@ -34,6 +34,33 @@ export class SearchWorkbench {
// Get the active text editor
const activeTextEditor = vscode.window.activeTextEditor;
if (activeTextEditor && activeTextEditor.document.languageId === "json" && activeTextEditor.document.fileName.endsWith(".cbs.json")) {
try {
JSON.parse(activeTextEditor.document.getText())
}
catch (err) {
// Invalid JSON case
let errorArray = []
errorArray.push({
code: 0,
msg: "The query is not a valid JSON",
query: false,
});
const queryStatusProps = {
queryStatus: QueryStatus.Fatal,
rtt: "-",
elapsed: "-",
executionTime: "-",
numDocs: "-",
size: "-",
};
workbenchWebviewProvider.setQueryResult(
JSON.stringify(errorArray),
queryStatusProps,
null,
true
);
return;
}

activeTextEditor.document.save();
const indexQueryPayload = activeTextEditor.selection.isEmpty ? activeTextEditor.document.getText() : activeTextEditor.document.getText(activeTextEditor.selection);
Expand All @@ -47,30 +74,52 @@ export class SearchWorkbench {
await workbenchWebviewProvider.sendQueryResult(JSON.stringify([{ "status": "Executing statement" }]), { queryStatus: QueryStatus.Running }, null);
const explainPlan = JSON.stringify("");
const couchbbaseRestAPI = new CouchbaseRestAPI(connection);
const searchIndexesManager = connection?.cluster?.searchIndexes();
const ftsIndexes = await searchIndexesManager?.getAllIndexes();
const bucketIndexes = ftsIndexes?.filter(index => index.name === queryContext?.indexName);
if (bucketIndexes?.length == 0) {
// Index was deleted/ Not found
let editorId = activeTextEditor.document.uri.toString();
let editorContext = this.editorToContext.get(editorId);
if (editorContext) {
editorContext.statusBarItem.text = `$(group-by-ref-type) No Search Query Context Set`;
throw new Error("Search Index not found");
}
}
const start = Date.now();
const searchQueryResult = await couchbbaseRestAPI.runSearchIndexes(queryContext?.indexName, indexQueryPayload);
const end = Date.now()
const rtt = end - start
const resultJson = JSON.stringify(searchQueryResult);
const resultSize = new TextEncoder().encode(resultJson).length;
const queryStatusProps = {
queryStatus: searchQueryResult?.status.successful === 1 ? "success" : "fatal",
rtt: rtt.toString() + " MS",
elapsed: (searchQueryResult?.took / 1000).toString() + " MS",
numDocs: searchQueryResult?.total_hits.toString() + " docs",
size: resultSize ? (resultSize > 1000 ? (resultSize / 1000).toFixed(2) + " KB" : resultSize + " Bytes") : ""
};
workbenchWebviewProvider.setQueryResult(
JSON.stringify(searchQueryResult?.hits),
{},
queryStatusProps,
explainPlan,
true
);
} catch (err) {
} catch (err: any) {
const errorArray = [];
if (err instanceof CouchbaseError) {
const { first_error_code, first_error_message, statement } =
err.cause as any;
if (
first_error_code !== undefined ||
first_error_message !== undefined ||
statement !== undefined
) {
if (err.response && err.response.data) {
if (err.response.status === 400) {
errorArray.push({
code: first_error_code,
msg: first_error_message,
query: statement,
code: err.response.status,
msg: err.response.data.error || 'Bad request',
query: (err.config && err.config.url) ? err.config.url : 'No URL',
});
} else {
errorArray.push(err);
errorArray.push({
code: err.response.status,
msg: err.message,
query: err.config && err.config.url
});
}
} else {
errorArray.push(err);
Expand All @@ -90,18 +139,17 @@ export class SearchWorkbench {
true
);
}

}

}
openSearchWorkbench(searchIndexNode: SearchIndexNode, memFs: MemFS) {
try {
return this._untitledSearchJsonDocumentService.newQuery(searchIndexNode, memFs);
} catch (error) {
logger.error("Error while opening Search WorkBench:" + error);
throw error;
throw error;
}
}


}
25 changes: 19 additions & 6 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import { handleSearchContextStatusbar } from "./handlers/handleSearchQueryContex
import { validateDocument } from "./commands/fts/SearchWorkbench/validators/validationUtil";
import { AutocompleteVisitor } from "./commands/fts/SearchWorkbench/contributor/autoCompleteVisitor";
import { CbsJsonHoverProvider } from "./commands/fts/SearchWorkbench/documentation/documentationProvider";
import { deleteIndex } from "./util/ftsIndexUtils";

export function activate(context: vscode.ExtensionContext) {
Global.setState(context.globalState);
Expand Down Expand Up @@ -369,6 +370,16 @@ context.subscriptions.push(disposable);
)
);

subscriptions.push(
vscode.commands.registerCommand(
Commands.deleteSearchIndex,
async (searchIndexNode: SearchIndexNode) => {
await deleteIndex(searchIndexNode);
clusterConnectionTreeProvider.refresh();
}
)
);

subscriptions.push(
vscode.commands.registerCommand(
Commands.openIndexInfo,
Expand Down Expand Up @@ -769,17 +780,19 @@ context.subscriptions.push(disposable);

searchWorkbench.openSearchWorkbench(searchIndexNode, memFs);

const editorChangeSubscription = vscode.window.onDidChangeActiveTextEditor(async (editor) => {
if (editor && editor.document.languageId === "json" && editor.document.fileName.endsWith(".cbs.json")) {
await handleSearchContextStatusbar(editor, searchIndexNode, searchWorkbench, globalStatusBarItem);
}
});
context.subscriptions.push(editorChangeSubscription);

});
context.subscriptions.push(openSearchWorkbenchCommand);


subscriptions.push(
vscode.window.onDidChangeActiveTextEditor(async (editor) => {
if (editor && editor.document.languageId === "json" && editor.document.fileName.endsWith(".cbs.json")) {
await handleSearchContextStatusbar(editor, currentSearchIndexNode, searchWorkbench, globalStatusBarItem);
}
})
);


context.subscriptions.push(
vscode.workspace.registerNotebookSerializer(
Expand Down
2 changes: 1 addition & 1 deletion src/model/CollectionDirectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class CollectionDirectory implements INode {
public getTreeItem(): vscode.TreeItem {
return {
label: `Collections`,
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
contextValue: "collectionDirectory",
};
}
Expand Down
8 changes: 3 additions & 5 deletions src/model/SearchDirectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,16 @@ export class SearchDirectory implements INode {

return []
}
const searchIndexesManager = connection?.cluster?.searchIndexes();
const ftsIndexes = await searchIndexesManager?.getAllIndexes();
const bucketIndexes = ftsIndexes?.filter(index => index.sourceName === this.bucketName);
const searchIndexesManager = connection?.cluster?.bucket(this.bucketName).scope(this.scopeName).searchIndexes();
const bucketIndexes = await searchIndexesManager?.getAllIndexes();
if (bucketIndexes === undefined) {
return [];
}
const searchIndexChildren: INode[] = bucketIndexes.map((searchIndex) =>
new SearchIndexNode(
searchIndex.name,
this.bucketName,
this.scopeName,
searchIndex.name
`${this.bucketName}.${this.scopeName}.${searchIndex.name}`
)


Expand Down
3 changes: 1 addition & 2 deletions src/model/SearchIndexNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import * as path from "path";

export default class SearchIndexNode implements INode {
constructor(
public readonly searchIndexName: string,
public readonly bucketName: string,
public readonly scopeName: string,
public readonly indexName: string,
) { }
public async getTreeItem(): Promise<vscode.TreeItem> {
return {
label: `${this.searchIndexName}`,
label: `${this.indexName}`,
collapsibleState: vscode.TreeItemCollapsibleState.None,
contextValue: "searchIndex",
command: {
Expand Down
28 changes: 14 additions & 14 deletions src/pages/queryContext/queryContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as vscode from 'vscode';
import { logger } from "../../logger/logger";
import { Bucket, BucketSettings } from "couchbase";
import { QueryWorkbench } from "../../workbench/queryWorkbench";
import { showQueryContextStatusbar } from "../../util/queryContextUtils";
import { showQueryContextStatusbar, showSearchContextStatusbar } from "../../util/queryContextUtils";
import { getActiveConnection } from "../../util/connections";
import { SearchWorkbench } from "../../commands/fts/SearchWorkbench/searchWorkbench";
import SearchIndexNode from "../../model/SearchIndexNode";
Expand Down Expand Up @@ -124,7 +124,7 @@ export async function fetchSearchContext(searchIndexNode: SearchIndexNode, workb
label: bucket.name,
iconPath: new vscode.ThemeIcon("database")
})), {
placeHolder: 'Query Context: Select a bucket',
placeHolder: 'Search Query Context: Select a bucket',
canPickMany: false
});

Expand All @@ -133,7 +133,7 @@ export async function fetchSearchContext(searchIndexNode: SearchIndexNode, workb
return;
}

const bucketNameSelected = selectedItem.label;
let bucketNameSelected = selectedItem.label;

// Fetching search indexes specific to the selected bucket
const searchIndexesManager = connection?.cluster?.searchIndexes();
Expand All @@ -158,22 +158,22 @@ export async function fetchSearchContext(searchIndexNode: SearchIndexNode, workb
return;
}

const editorId = activeEditor.document.uri.toString();
let editorId = activeEditor.document.uri.toString();
let editorContext = workbench.editorToContext.get(editorId);

let displayBucketName = bucketNameSelected.length > 15 ? `${bucketNameSelected.substring(0, 13)}...` : bucketNameSelected;
let displayIndexName = indexNameSelected.label.length > 15 ? `${indexNameSelected.label.substring(0, 13)}...` : indexNameSelected.label;

// Setting new context
workbench.editorToContext.set(editorId, {
editorContext = {
bucketName: bucketNameSelected,
indexName: indexNameSelected.label,
statusBarItem: globalStatusBarItem,
searchNode: searchIndexNode
});

// Update the status bar directly
let displayBucketName = bucketNameSelected.length > 15 ? `${bucketNameSelected.substring(0, 13)}...` : bucketNameSelected;
let displayIndexName = indexNameSelected.label.length > 15 ? `${indexNameSelected.label.substring(0, 13)}...` : indexNameSelected.label;
globalStatusBarItem.text = `$(group-by-ref-type) ${displayBucketName} > ${displayIndexName}`;
globalStatusBarItem.tooltip = "Search Query Context";
globalStatusBarItem.command = Commands.searchContext;
};
workbench.editorToContext.set(editorId, editorContext);
editorContext.statusBarItem.text = `$(group-by-ref-type) ${displayBucketName} > ${displayIndexName}`;
editorContext.statusBarItem.tooltip = "Search Query Context";
editorContext.statusBarItem.command = Commands.searchContext;

} catch (err) {
logger.error(`Failed to open and set query context: ${err}`);
Expand Down
24 changes: 24 additions & 0 deletions src/util/ftsIndexUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as vscode from "vscode";
import SearchIndexNode from "../model/SearchIndexNode";
import { getActiveConnection } from "./connections";
import { logger } from "../logger/logger";

export async function deleteIndex(searchIndexNode: SearchIndexNode) {
const connection = getActiveConnection()
if (!connection) {
return;
}

let answer = await vscode.window.showInformationMessage(`Are you sure you want to DELETE the index: ${searchIndexNode.indexName}?`, ...["Yes", "No"]);
if (answer !== "Yes") {
return;
}

try {
const searchIndexesManager = connection?.cluster?.searchIndexes();
searchIndexesManager?.dropIndex(searchIndexNode.indexName)
} catch (err) {
logger.error("An error occurred while trying to delete the index" + searchIndexNode.indexName + err)
await vscode.window.showInformationMessage(`Could not delete the index. Please check the logs.`)
}
}
Loading

0 comments on commit cfc0dd9

Please sign in to comment.