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.resourceLink = resourceLink;
|
||||||
this.queryExecutionContext = this._createQueryExecutionContext();
|
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();
|
this.reset();
|
||||||
while (this.queryExecutionContext.hasMoreResults()) {
|
while (this.queryExecutionContext.hasMoreResults()) {
|
||||||
const result = await this.queryExecutionContext.nextItem();
|
const result = await this.queryExecutionContext.nextItem();
|
||||||
|
|
|
@ -117,10 +117,10 @@ describe("NodeJS CRUD Tests", function() {
|
||||||
assert.equal(docs[2].id, resources.doc3.id);
|
assert.equal(docs[2].id, resources.doc3.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryIteratorForEachTest = async function() {
|
const queryIteratorAsyncIteratorTest = async function() {
|
||||||
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
for await (const { result: doc } of queryIterator.forEach()) {
|
for await (const { result: doc } of queryIterator.getAsyncIterator()) {
|
||||||
counter++;
|
counter++;
|
||||||
if (counter === 1) {
|
if (counter === 1) {
|
||||||
assert.equal(doc.id, resources.doc1.id, "first document should be doc1");
|
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");
|
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 queryIteratorNextAndMoreTest = async function() {
|
||||||
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
const queryIterator = resources.container.items.readAll({ maxItemCount: 2 });
|
||||||
assert.equal(queryIterator.hasMoreResults(), true);
|
assert.equal(queryIterator.hasMoreResults(), true);
|
||||||
|
@ -186,7 +202,11 @@ describe("NodeJS CRUD Tests", function() {
|
||||||
await queryIteratorToArrayTest();
|
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();
|
await queryIteratorForEachTest();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ describe.skip("NodeJS Aggregate Query Tests", async function() {
|
||||||
const results: any[] = [];
|
const results: any[] = [];
|
||||||
let callbackSingnalledEnd = false;
|
let callbackSingnalledEnd = false;
|
||||||
// forEach uses callbacks still, so just wrap in a promise
|
// 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!
|
// 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");
|
assert.equal(callbackSingnalledEnd, false, "forEach called callback after the first false returned");
|
||||||
results.push(item);
|
results.push(item);
|
||||||
|
|
|
@ -231,7 +231,7 @@ describe("Cross Partition", function() {
|
||||||
const results: any[] = [];
|
const results: any[] = [];
|
||||||
let callbackSingnalledEnd = false;
|
let callbackSingnalledEnd = false;
|
||||||
// forEach uses callbacks still, so just wrap in a promise
|
// 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!
|
// 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");
|
assert.equal(callbackSingnalledEnd, false, "forEach called callback after the first false returned");
|
||||||
results.push(item);
|
results.push(item);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче