Skip to content
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

Merge Development to main #419

Merged
merged 22 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
56572d7
Da 377 webview resets bug fix (#386)
lokesh-couchbase May 23, 2024
81e1f36
DA-380 Add KV Type document filtering (#385)
lokesh-couchbase May 23, 2024
76b0efc
DA-442 add named parameter support (#387)
lokesh-couchbase May 28, 2024
c801a21
DA-450 basic workbench keyword recommendation (#389)
lokesh-couchbase May 29, 2024
4c02da3
bump package version
lokesh-couchbase May 29, 2024
15a3398
Da 451 release bug fix (#391)
lokesh-couchbase May 29, 2024
ecc2487
DA-459 add n1ql file support (#394)
lokesh-couchbase Jun 5, 2024
e60f755
Merge Branch Main into development (#396)
lokesh-couchbase Jun 12, 2024
818cb5b
bump version and remove unwanted line in code
lokesh-couchbase Jun 12, 2024
83236a2
resolve merge conflicts
lokesh-couchbase Jun 12, 2024
04d3397
resolve merge conflicts
lokesh-couchbase Jun 12, 2024
5ca51b7
Add UI Support for DynamoDB to Couchbase (#403)
prajwal-pai77 Jul 1, 2024
4697ffe
merge main to development
prajwal-pai77 Jul 1, 2024
762aa47
Da 395 add fts Support workbench, autocomplete and validation (#407)
prajwal-pai77 Jul 19, 2024
127a96d
merge main to dev
prajwal-pai77 Jul 19, 2024
38948bf
Add document autoComplete feature (#410)
prajwal-pai77 Aug 22, 2024
83b7a3f
Fix query named params bug to support data type (#413)
prajwal-pai77 Aug 22, 2024
ac4a33c
Update get services to check all nodes (#418)
prajwal-pai77 Aug 22, 2024
6b58894
Da 412 fix query data table view (#417)
prajwal-pai77 Aug 22, 2024
fff73e6
Update package version
prajwal-pai77 Aug 22, 2024
5517ff3
merge main into dev
prajwal-pai77 Aug 22, 2024
be60168
Switch CI to release
prajwal-pai77 Aug 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
echo "PATH=${WORKING_DIRECTORY}/cmake-3.27.9-linux-x86_64/bin:$PATH" >> $GITHUB_ENV
- name: general
run: npm i && npm run rebuild
- run: npx vsce package --target ${{ env.target }} --pre-release
- run: npx vsce package --target ${{ env.target }}
- uses: actions/upload-artifact@v4
with:
name: ${{ env.target }}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-couchbase",
"displayName": "Couchbase",
"description": "",
"version": "2.1.0",
"version": "2.1.2",
"engines": {
"vscode": "^1.63.1"
},
Expand Down Expand Up @@ -468,7 +468,7 @@
},
{
"command": "vscode-couchbase.openQueryWorkbench",
"title": "New Workbench",
"title": "New Query Workbench",
"category": "Couchbase",
"icon": "images/create.svg"
},
Expand Down
190 changes: 190 additions & 0 deletions src/commands/documents/contributor/autoCompleteContributor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as vscode from 'vscode';
import * as jsonc from 'jsonc-parser';
import { fieldsContributor } from '../../fts/SearchWorkbench/contributor/fieldsContributor';
import { extractDocumentInfo } from '../../../util/common';

export class JsonAttributeCompletionProvider implements vscode.CompletionItemProvider {
private fieldCache: Record<string, { type: string, value: any }>;

constructor(document: vscode.TextDocument, cache: any) {
const documentInfo = extractDocumentInfo(document.uri.path);
const schemaCache = cache.getCache(documentInfo.bucket);
const fields = fieldsContributor.extractFieldsFromCollection(
schemaCache,
documentInfo.scope,
documentInfo.collection,
);
this.fieldCache = fields.reduce((cache: any, currentField: any) => ({
...cache,
...this.flattenCache(currentField)
}), {});
}

private flattenCache(obj: any): Record<string, { type: string, value: any }> {
let result: Record<string, { type: string, value: any }> = {};
for (const key in obj) {
const value = obj[key];
result[key] = value;

if (value.type === 'array' && typeof value.value === 'object') {
this.extractArrayFields(value.value, result);
} else if (typeof value === 'object' && value !== null && value.type === 'object') {
Object.assign(result, this.flattenCache(value.value));
}
}
return result;
}

private extractArrayFields(obj: any, result: Record<string, { type: string, value: any }>) {
for (const key in obj) {
const value = obj[key];
if (typeof value === 'object' && value !== null && value.type) {
result[key] = value;
if (value.type === 'object' && typeof value.value === 'object') {
this.extractArrayFields(value.value, result);
}
} else {
result[key] = value;
}
}
}


public provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
): vscode.ProviderResult<vscode.CompletionItem[]> {
const text = document.getText();
const rootNode = jsonc.parseTree(text);
const offset = document.offsetAt(position);
if (!rootNode) {
return [];
}
const currentNode = jsonc.findNodeAtOffset(rootNode, offset, true);
if (!currentNode) {
return [];
}
const isKey = this.isKey(document, position);
if (!isKey) {
return []
}
let existingKeys = new Set<string>();
const currentNodeKeys = this.collectKeysFromCurrentNode(currentNode);
currentNodeKeys.forEach(key => existingKeys.add(key));
return this.suggestAttributes(existingKeys, position, document);
}



private collectKeysFromCurrentNode(currentNode: jsonc.Node): Set<string> {
let keys = new Set<string>();
if (currentNode.type === "string") {
if (currentNode.parent && currentNode.parent.parent) {
const propertyNode = currentNode.parent.parent;
if (propertyNode.children) {
propertyNode.children.forEach(child => {
if (child.type === 'property' && child.children && child.children[0].type === 'string') {
keys.add(child.children[0].value);
}
});
}
}
} else if (currentNode && currentNode.type === 'object' && currentNode.children) {
currentNode.children.forEach(child => {
if (child.type === 'property' && child.children && child.children[0].type === 'string') {
keys.add(child.children[0].value);
}
});
}
return keys;
}


private suggestAttributes(existingKeys: Set<string>, position: vscode.Position, document: vscode.TextDocument): vscode.CompletionItem[] {
let suggestions: vscode.CompletionItem[] = [];
const isWithinQuotes = this.isWithinQuotes(document, position)

Object.keys(this.fieldCache).forEach(key => {
if (this.shouldSuggestKey(key, existingKeys)) {
const suggestionKey = key;

let itemText = suggestionKey;
let insertText = suggestionKey;

if (!isWithinQuotes) {
itemText = `"${suggestionKey}"`;
insertText = `"${suggestionKey}": `;
}

const item = new vscode.CompletionItem(itemText, vscode.CompletionItemKind.Field);
item.insertText = insertText;
suggestions.push(item);
}
});
return suggestions;
}

private shouldSuggestKey(key: string, existingKeys: Set<string>): boolean {
if (existingKeys.has(key)) {
return false;
}
return true;
}

isKey(document: vscode.TextDocument, position: vscode.Position): boolean {
const lineText = document
.lineAt(position.line)
.text.substring(0, position.character);

if (/^\s*[\{,]\s*$/.test(lineText)) {
return true;
}

let depth = 0;
for (let i = position.character - 1; i >= 0; i--) {
const char = lineText[i];
switch (char) {
case ":":
if (depth === 0) return false;
break;
case "{":
case "[":
depth++;
break;
case "}":
case "]":
depth--;
break;
}
}

return true;
}

private isWithinQuotes(
document: vscode.TextDocument,
position: vscode.Position,
): boolean {
const lineText = document.lineAt(position.line).text;
const charPos = position.character;

let quoteOpen = false;
let quoteClose = false;

for (let i = charPos - 1; i >= 0; i--) {
if (lineText[i] === '"' && (i === 0 || lineText[i - 1] !== "\\")) {
quoteOpen = true;
break;
}
}

for (let i = charPos; i < lineText.length; i++) {
if (lineText[i] === '"' && (i === 0 || lineText[i - 1] !== "\\")) {
quoteClose = true;
break;
}
}

return quoteOpen && quoteClose;
}
}
27 changes: 27 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import { validateDocument } from "./commands/fts/SearchWorkbench/validators/vali
import { AutocompleteVisitor } from "./commands/fts/SearchWorkbench/contributor/autoCompleteVisitor";
import { CbsJsonHoverProvider } from "./commands/fts/SearchWorkbench/documentation/documentationProvider";
import { deleteIndex } from "./util/ftsIndexUtils";
import { JsonAttributeCompletionProvider } from "./commands/documents/contributor/autoCompleteContributor";

export function activate(context: vscode.ExtensionContext) {
Global.setState(context.globalState);
Expand Down Expand Up @@ -149,6 +150,32 @@ const provider = vscode.languages.registerCompletionItemProvider(

context.subscriptions.push(provider);

const autoCompleteProviderForDocuments = vscode.languages.registerCompletionItemProvider(
{ language: 'json' },
{
async provideCompletionItems(document, position, token, context) {
const autoComplete = new JsonAttributeCompletionProvider(document,cacheService);
const suggestions = await autoComplete.provideCompletionItems(document,position);
if (suggestions?.length === 0) {
return [new vscode.CompletionItem('', vscode.CompletionItemKind.Text)].map(item => {
item.sortText = '\u0000';
item.preselect = true;
item.keepWhitespace = true;
item.insertText = '';
item.range = new vscode.Range(position, position);
return item;
});
}
return suggestions;
}
},
'\"'
);



context.subscriptions.push(autoCompleteProviderForDocuments);

const disposable = vscode.window.onDidChangeTextEditorSelection(async (e) => {
if (e.kind === vscode.TextEditorSelectionChangeKind.Command) {
const activeEditor = vscode.window.activeTextEditor;
Expand Down
9 changes: 8 additions & 1 deletion src/reactViews/app/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { QueryStatsProps } from "custom/query-stats/query-stats.types";
import { VisualExplainPlan } from "components/visual-explain-plan";
import { Plan } from "types/plan";
import { SupportedThemes } from "components/editor/editor.types";
import { getIdentifiedData } from "components/data-table/data-table.utils";

const container = document.getElementById("root");
const root = createRoot(container);
Expand Down Expand Up @@ -44,6 +45,12 @@ export const App: React.FC = () => {
break;
}
});

const tableValue = React.useMemo(() => {
const result = queryResult && queryResult.length < 1 ? [{ '': [] }] : queryResult;
return result ? getIdentifiedData(result) : result;
}, [queryResult]);

return (
<div className="h-screen">
<QueryStats {...queryStatus} />
Expand All @@ -57,7 +64,7 @@ export const App: React.FC = () => {
theme={theme}
language="json"
/>}
{!isSearch && currentTab === QueryTabs.Table && <DataTable data={queryResult} dataFallback={[FALLBACK_MESSAGE]} />}
{!isSearch && currentTab === QueryTabs.Table && <DataTable data={tableValue} dataFallback={[FALLBACK_MESSAGE]} />}
{!isSearch && currentTab === QueryTabs.PLAN && <VisualExplainPlan plan={explainPlan} hideControls={false} />}
</div>
</div>
Expand Down
Loading
Loading