Update forEach/Adds AsyncIterator (#87)
Switches the forEach implementation to be AsyncIterator instead. Additionally, it changes the forEach implementation to accept a callback fixes https://github.com/Azure/azure-cosmos-js/issues/73 fixes https://github.com/Azure/azure-cosmos-js/issues/71
This commit is contained in:
Родитель
a908af7cba
Коммит
5b5f33a824
|
@ -35,10 +35,67 @@ export class QueryIterator<T> {
|
|||
this.resourceLink = resourceLink;
|
||||
this.queryExecutionContext = this._createQueryExecutionContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function once per feed element.
|
||||
* Calls a specified callback for each item returned from the query.
|
||||
* Runs serially; each callback blocks the next.
|
||||
*
|
||||
* @param callback Specified callback.
|
||||
* First param is the result,
|
||||
* second param (optional) is the current headers object state,
|
||||
* third param (optional) is current index.
|
||||
* No more callbacks will be called if one of them results false.
|
||||
*
|
||||
* @returns Promise<void> - you should await or .catch the Promise in case there are any errors
|
||||
*
|
||||
* @example Iterate over all databases
|
||||
* ```typescript
|
||||
* await client.databases.readAll().forEach((db, headers, index) => {
|
||||
* console.log(`Got ${db.id} from forEach`);
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
public async *forEach(): AsyncIterable<Response<T>> {
|
||||
public async forEach(callback: (result: T, headers?: IHeaders, index?: number) => boolean | void): Promise<void> {
|
||||
this.reset();
|
||||
let index = 0;
|
||||
while (this.queryExecutionContext.hasMoreResults()) {
|
||||
const result = await this.queryExecutionContext.nextItem();
|
||||
if (result.result === undefined) {
|
||||
return;
|
||||
}
|
||||
if (callback(result.result, result.headers, index) === false) {
|
||||
return;
|
||||
} else {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an async iterator that will yield results until completion.
|
||||
*
|
||||
* NOTE: AsyncIterators are a very new feature and you might need to
|
||||
* use polyfils/etc. in order to use them in your code.
|
||||
*
|
||||
* If you're using TypeScript, you can use the following polyfill as long
|
||||
* as you target ES6 or higher and are running on Node 6 or higher.
|
||||
*
|
||||
* ```typescript
|
||||
* if (!Symbol || !Symbol.asyncIterator) {
|
||||
* (Symbol as any).asyncIterator = Symbol.for("Symbol.asyncIterator");
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see QueryIterator.forEach for very similar functionality.
|
||||
*
|
||||
* @example Iterate over all databases
|
||||
* ```typescript
|
||||
* for await(const {result: db} in client.databases.readAll().getAsyncIterator()) {
|
||||
* console.log(`Got ${db.id} from AsyncIterator`);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public async *getAsyncIterator(): AsyncIterable<Response<T>> {
|
||||
this.reset();
|
||||
while (this.queryExecutionContext.hasMoreResults()) {
|
||||
const result = await this.queryExecutionContext.nextItem();
|
||||
|
|
|
@ -117,10 +117,10 @@ describe("NodeJS CRUD Tests", function() {
|
|||
assert.equal(docs[2].id, resources.doc3.id);
|
||||
};
|
||||
|
||||
const queryIteratorForEachTest = async function() {
|
||||
const queryIteratorAsyncIteratorTest = async function() {
|
||||
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
||||
let counter = 0;
|
||||
for await (const { result: doc } of queryIterator.forEach()) {
|
||||
for await (const { result: doc } of queryIterator.getAsyncIterator()) {
|
||||
counter++;
|
||||
if (counter === 1) {
|
||||
assert.equal(doc.id, resources.doc1.id, "first document should be doc1");
|
||||
|
@ -133,6 +133,22 @@ describe("NodeJS CRUD Tests", function() {
|
|||
assert(counter === 3, "iterator should have run 3 times");
|
||||
};
|
||||
|
||||
const queryIteratorForEachTest = async function() {
|
||||
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
||||
let counter = 0;
|
||||
await queryIterator.forEach((item, headers, index) => {
|
||||
counter++;
|
||||
if (index === 0) {
|
||||
assert.equal(item.id, resources.doc1.id, "first document should be doc1");
|
||||
} else if (index === 1) {
|
||||
assert.equal(item.id, resources.doc2.id, "second document should be doc2");
|
||||
} else if (index === 2) {
|
||||
assert.equal(item.id, resources.doc3.id, "third document should be doc3");
|
||||
}
|
||||
});
|
||||
assert(counter === 3, "iterator should have run 3 times");
|
||||
};
|
||||
|
||||
const queryIteratorNextAndMoreTest = async function() {
|
||||
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
||||
assert.equal(queryIterator.hasMoreResults(), true);
|
||||
|
@ -186,7 +202,11 @@ describe("NodeJS CRUD Tests", function() {
|
|||
await queryIteratorToArrayTest();
|
||||
});
|
||||
|
||||
it("nativeApi validate queryIterator iterator forEach name based", async function() {
|
||||
it("validate queryIterator asyncIterator", async function() {
|
||||
await queryIteratorAsyncIteratorTest();
|
||||
});
|
||||
|
||||
it("validate queryIterator forEach", async function() {
|
||||
await queryIteratorForEachTest();
|
||||
});
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ describe.skip("NodeJS Aggregate Query Tests", async function() {
|
|||
const results: any[] = [];
|
||||
let callbackSingnalledEnd = false;
|
||||
// forEach uses callbacks still, so just wrap in a promise
|
||||
for await (const { result: item } of queryIterator.forEach()) {
|
||||
for await (const { result: item } of queryIterator.getAsyncIterator()) {
|
||||
// if the previous invocation returned false, forEach must avoid invoking the callback again!
|
||||
assert.equal(callbackSingnalledEnd, false, "forEach called callback after the first false returned");
|
||||
results.push(item);
|
||||
|
|
|
@ -231,7 +231,7 @@ describe("Cross Partition", function() {
|
|||
const results: any[] = [];
|
||||
let callbackSingnalledEnd = false;
|
||||
// forEach uses callbacks still, so just wrap in a promise
|
||||
for await (const { result: item } of queryIterator.forEach()) {
|
||||
for await (const { result: item } of queryIterator.getAsyncIterator()) {
|
||||
// if the previous invocation returned false, forEach must avoid invoking the callback again!
|
||||
assert.equal(callbackSingnalledEnd, false, "forEach called callback after the first false returned");
|
||||
results.push(item);
|
||||
|
|
Загрузка…
Ссылка в новой задаче