Skip to content

Commit

Permalink
Support Secondary index for list and filter docs + minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
prajwal-pai77 committed Apr 22, 2024
1 parent 3de6f59 commit a543332
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 12 deletions.
22 changes: 14 additions & 8 deletions src/commands/documents/filterDocuments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@ import * as vscode from "vscode";
import { Memory } from "../../util/util";
import { IFilterDocuments } from "../../types/IFilterDocuments";
import { logger } from "../../logger/logger";
import { ParsingFailureError } from "couchbase";
import { ParsingFailureError, PlanningFailureError } from "couchbase";

export const filterDocuments = async (node: CollectionNode) => {
// Check if indexes are present for collection
const query = `
SELECT COUNT(*) AS indexCount FROM system:indexes
WHERE bucket_id="${node.bucketName}" AND scope_id="${node.scopeName}" AND keyspace_id="${node.collectionName}" AND is_primary=true
WHERE bucket_id="${node.bucketName}" AND scope_id="${node.scopeName}" AND keyspace_id="${node.collectionName}"
`;
// Execute the query
const primaryIndexExists = await node.connection.cluster
const indexExists = await node.connection.cluster
?.query(query)
.then((result) => {
const rows = result.rows;
if (!(rows.length > 0 && rows[0].indexCount > 0)) {
// Primary Index Doesn't Exists
// Index Doesn't Exists
vscode.window.showErrorMessage(
"Primary index doesn't exists for this document, Please create one before setting document filter"
"Filters can only be applied to collections that have at least one index."
);
logger.error(
"Error setting document filter: Primary index doesn't exists"
"Error setting document filter: index doesn't exist"
);
return false;
}
Expand All @@ -32,7 +32,7 @@ export const filterDocuments = async (node: CollectionNode) => {
logger.error("Error checking primary index: " + err);
return false;
});
if (!primaryIndexExists) {
if (!indexExists) {
return;
}

Expand Down Expand Up @@ -74,7 +74,13 @@ export const filterDocuments = async (node: CollectionNode) => {
vscode.window.showErrorMessage(
"Parsing Failed: Incorrect filter definition"
);
} else {
}
else if (err instanceof PlanningFailureError) {
vscode.window.showErrorMessage(
"Planning Failed: Incorrect filter definition, check if the query is correct"
);
}
else {
logger.error(err);
}
return;
Expand Down
52 changes: 48 additions & 4 deletions src/model/CollectionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,46 @@ export default class CollectionNode implements INode {
);
}

public async getIndexedField(): Promise<string | null> {
const idxs = await this.connection?.cluster?.queryIndexes().getAllIndexes(this.bucketName, { scopeName: this.scopeName, collectionName: this.collectionName });
let filter: string | null = null;
if (!idxs) {
return null;
}

for (const idx of idxs) {
if (idx.isPrimary) {
return "meta().id";
} else {
const result = this.getValidIndexKey(idx.indexKey);
if (result) {
if (!idx.condition && result[1]) {
return result[0];
} else {
filter = result[0];
}
}
}
}

return filter;
}

private getValidIndexKey(array: any[]): [string, boolean] | null {
for (let i = 0; i < array.length; i++) {
let key: string = array[i];
if (!key.includes("(")) {
if (key.endsWith(" DESC") || key.endsWith(" ASC")) {
key = key.replace(" ASC", "").replace(" DESC", "").trim();
}
key = key.replace(/`/g, "");

return [key, i === 0];
}
}
return null;
}

public async getTreeItem(): Promise<vscode.TreeItem> {
return {
label: `${this.collectionName} (${abbreviateCount(this.documentCount)})`,
Expand Down Expand Up @@ -117,8 +157,8 @@ export default class CollectionNode implements INode {
}
// TODO: default limit could be managed as user settings / preference
let result;
// A primary index is required for database querying. If one is present, a result will be obtained.
// If not, the user will be prompted to create a primary index before querying.
// An index is required for database querying. If one is present, a result will be obtained.
// If not, the user will be prompted to create a index before querying.
let docFilter = Memory.state.get<IFilterDocuments>(
`filterDocuments-${this.connection.connectionIdentifier}-${this.bucketName}-${this.scopeName}-${this.collectionName}`
);
Expand All @@ -133,9 +173,13 @@ export default class CollectionNode implements INode {
}
else {
try {
// selects the attribute that needs to be used according to the index
const idxField = await this.getIndexedField();
if (idxField === null) {
throw new PlanningFailureError();
}
result = await connection?.cluster?.query(
`SELECT RAW META().id FROM \`${this.bucketName}\`.\`${this.scopeName
}\`.\`${this.collectionName}\` ${filter.length > 0 ? "WHERE " + filter : ""
`SELECT RAW META().id FROM \`${this.bucketName}\`.\`${this.scopeName}\`.\`${this.collectionName}\` ${'WHERE ' + idxField + ' IS NOT MISSING'} ${filter.length > 0 ? "AND " + filter : ""
} LIMIT ${this.limit}`
);
} catch (err) {
Expand Down

0 comments on commit a543332

Please sign in to comment.