Remove QueryUtils.queryAll and fix test (#885)

This commit is contained in:
Steve Faulkner 2021-06-10 17:29:19 -07:00 committed by GitHub
parent b0bbeb188a
commit 0a1a2bf421
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 159 deletions

View File

@ -1,4 +1,3 @@
import { ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import * as _ from "underscore"; import * as _ from "underscore";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
@ -7,13 +6,11 @@ import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
import DocumentId from "../Explorer/Tree/DocumentId"; import DocumentId from "../Explorer/Tree/DocumentId";
import { userContext } from "../UserContext"; import { userContext } from "../UserContext";
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils"; import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
import * as QueryUtils from "../Utils/QueryUtils";
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants"; import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
import { createCollection } from "./dataAccess/createCollection"; import { createCollection } from "./dataAccess/createCollection";
import { createDocument } from "./dataAccess/createDocument"; import { createDocument } from "./dataAccess/createDocument";
import { deleteDocument } from "./dataAccess/deleteDocument"; import { deleteDocument } from "./dataAccess/deleteDocument";
import { queryDocuments } from "./dataAccess/queryDocuments"; import { queryDocuments } from "./dataAccess/queryDocuments";
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
import { handleError } from "./ErrorHandlingUtils"; import { handleError } from "./ErrorHandlingUtils";
export class QueriesClient { export class QueriesClient {
@ -100,45 +97,35 @@ export class QueriesClient {
const options: any = { enableCrossPartitionQuery: true }; const options: any = { enableCrossPartitionQuery: true };
const clearMessage = NotificationConsoleUtils.logConsoleProgress("Fetching saved queries"); const clearMessage = NotificationConsoleUtils.logConsoleProgress("Fetching saved queries");
const queryIterator: QueryIterator<ItemDefinition & Resource> = queryDocuments( const results = await queryDocuments(
SavedQueries.DatabaseName, SavedQueries.DatabaseName,
SavedQueries.CollectionName, SavedQueries.CollectionName,
this.fetchQueriesQuery(), this.fetchQueriesQuery(),
options options
); ).fetchAll();
const fetchQueries = async (firstItemIndex: number): Promise<ViewModels.QueryResults> =>
await queryDocumentsPage(queriesCollection.id(), queryIterator, firstItemIndex); let queries: DataModels.Query[] = _.map(results.resources, (document: DataModels.Query) => {
return QueryUtils.queryAllPages(fetchQueries) if (!document) {
.then( return undefined;
(results: ViewModels.QueryResults) => { }
let queries: DataModels.Query[] = _.map(results.documents, (document: DataModels.Query) => { const { id, resourceId, query, queryName } = document;
if (!document) { const parsedQuery: DataModels.Query = {
return undefined; resourceId: resourceId,
} queryName: queryName,
const { id, resourceId, query, queryName } = document; query: query,
const parsedQuery: DataModels.Query = { id: id,
resourceId: resourceId, };
queryName: queryName, try {
query: query, this.validateQuery(parsedQuery);
id: id, return parsedQuery;
}; } catch (error) {
try { return undefined;
this.validateQuery(parsedQuery); }
return parsedQuery; });
} catch (error) { queries = _.reject(queries, (parsedQuery: DataModels.Query) => !parsedQuery);
return undefined; NotificationConsoleUtils.logConsoleInfo("Successfully fetched saved queries");
} clearMessage();
}); return queries;
queries = _.reject(queries, (parsedQuery: DataModels.Query) => !parsedQuery);
NotificationConsoleUtils.logConsoleInfo("Successfully fetched saved queries");
return Promise.resolve(queries);
},
(error: any) => {
handleError(error, "getSavedQueries", "Failed to fetch saved queries");
return Promise.reject(error);
}
)
.finally(() => clearMessage());
} }
public async deleteQuery(query: DataModels.Query): Promise<void> { public async deleteQuery(query: DataModels.Query): Promise<void> {

View File

@ -91,97 +91,11 @@ describe("Query Utils", () => {
expect(queryStub.getCall(1).args[0]).toBe(0); expect(queryStub.getCall(1).args[0]).toBe(0);
}); });
it("should not perform multiple queries if the first page of results has items", (done) => { it("should not perform multiple queries if the first page of results has items", async () => {
const queryStub = sinon.stub().returns(Q.resolve(queryResultWithItemsInPage)); const queryStub = sinon.stub().returns(Q.resolve(queryResultWithItemsInPage));
QueryUtils.queryPagesUntilContentPresent(0, queryStub).finally(() => { await QueryUtils.queryPagesUntilContentPresent(0, queryStub);
expect(queryStub.callCount).toBe(1); expect(queryStub.callCount).toBe(1);
expect(queryStub.getCall(0).args[0]).toBe(0); expect(queryStub.getCall(0).args[0]).toBe(0);
done();
});
});
it("should not proceed with subsequent queries if the first one errors out", (done) => {
const queryStub = sinon.stub().returns(Q.reject("Error injected for testing purposes"));
QueryUtils.queryPagesUntilContentPresent(0, queryStub).finally(() => {
expect(queryStub.callCount).toBe(1);
expect(queryStub.getCall(0).args[0]).toBe(0);
done();
});
});
});
describe("queryAllPages()", () => {
const queryResultWithNoContinuation: ViewModels.QueryResults = {
documents: [{ a: "123" }],
activityId: "123",
requestCharge: 1,
hasMoreResults: false,
firstItemIndex: 1,
lastItemIndex: 1,
itemCount: 1,
};
const queryResultWithContinuation: ViewModels.QueryResults = {
documents: [{ b: "123" }],
activityId: "123",
requestCharge: 1,
hasMoreResults: true,
firstItemIndex: 0,
lastItemIndex: 0,
itemCount: 1,
};
it("should follow continuation token to fetch all pages", (done) => {
const queryStub = sinon
.stub()
.onFirstCall()
.returns(Q.resolve(queryResultWithContinuation))
.returns(Q.resolve(queryResultWithNoContinuation));
QueryUtils.queryAllPages(queryStub).then(
(results: ViewModels.QueryResults) => {
expect(queryStub.callCount).toBe(2);
expect(queryStub.getCall(0).args[0]).toBe(0);
expect(queryStub.getCall(1).args[0]).toBe(1);
expect(results.itemCount).toBe(
queryResultWithContinuation.documents.length + queryResultWithNoContinuation.documents.length
);
expect(results.requestCharge).toBe(
queryResultWithContinuation.requestCharge + queryResultWithNoContinuation.requestCharge
);
expect(results.documents).toEqual(
queryResultWithContinuation.documents.concat(queryResultWithNoContinuation.documents)
);
done();
},
(error: any) => {
fail(error);
}
);
});
it("should not perform subsequent fetches when result has no continuation", (done) => {
const queryStub = sinon.stub().returns(Q.resolve(queryResultWithNoContinuation));
QueryUtils.queryAllPages(queryStub).then(
(results: ViewModels.QueryResults) => {
expect(queryStub.callCount).toBe(1);
expect(queryStub.getCall(0).args[0]).toBe(0);
expect(results.itemCount).toBe(queryResultWithNoContinuation.documents.length);
expect(results.requestCharge).toBe(queryResultWithNoContinuation.requestCharge);
expect(results.documents).toEqual(queryResultWithNoContinuation.documents);
done();
},
(error: any) => {
fail(error);
}
);
});
it("should not proceed with subsequent fetches if the first one errors out", (done) => {
const queryStub = sinon.stub().returns(Q.reject("Error injected for testing purposes"));
QueryUtils.queryAllPages(queryStub).finally(() => {
expect(queryStub.callCount).toBe(1);
expect(queryStub.getCall(0).args[0]).toBe(0);
done();
});
}); });
}); });
}); });

View File

@ -81,34 +81,3 @@ export const queryPagesUntilContentPresent = async (
return await doRequest(firstItemIndex); return await doRequest(firstItemIndex);
}; };
export const queryAllPages = async (
queryItems: (itemIndex: number) => Promise<ViewModels.QueryResults>
): Promise<ViewModels.QueryResults> => {
const queryResults: ViewModels.QueryResults = {
documents: [],
activityId: undefined,
hasMoreResults: false,
itemCount: 0,
firstItemIndex: 0,
lastItemIndex: 0,
requestCharge: 0,
roundTrips: 0,
};
const doRequest = async (itemIndex: number): Promise<ViewModels.QueryResults> => {
const results = await queryItems(itemIndex);
const { requestCharge, hasMoreResults, itemCount, lastItemIndex, documents } = results;
queryResults.roundTrips = queryResults.roundTrips + 1;
queryResults.requestCharge = Number(queryResults.requestCharge) + Number(requestCharge);
queryResults.hasMoreResults = hasMoreResults;
queryResults.itemCount = queryResults.itemCount + itemCount;
queryResults.lastItemIndex = lastItemIndex;
queryResults.documents = queryResults.documents.concat(documents);
if (queryResults.hasMoreResults) {
return doRequest(queryResults.lastItemIndex + 1);
}
return queryResults;
};
return doRequest(0);
};