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

feat: add support for Partition API #1320

Merged
merged 6 commits into from Oct 13, 2020
Merged

Conversation

schmidt-sebastian
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian commented Oct 1, 2020

This adds support for the Partition API.

Port of googleapis/java-firestore#202

@schmidt-sebastian schmidt-sebastian requested review from a team as code owners October 1, 2020 18:29
@schmidt-sebastian schmidt-sebastian marked this pull request as draft October 1, 2020 18:29
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Oct 1, 2020
@product-auto-label product-auto-label bot added the api: firestore Issues related to the googleapis/nodejs-firestore API. label Oct 2, 2020
@schmidt-sebastian schmidt-sebastian changed the title WIP: Partition API feat: add support for Partition API Oct 2, 2020
@schmidt-sebastian schmidt-sebastian marked this pull request as ready for review October 2, 2020 21:01
@codecov
Copy link

codecov bot commented Oct 2, 2020

Codecov Report

Merging #1320 into master will decrease coverage by 0.01%.
The diff coverage is 97.58%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1320      +/-   ##
==========================================
- Coverage   98.51%   98.49%   -0.02%     
==========================================
  Files          30       32       +2     
  Lines       18760    19111     +351     
  Branches     1451     1464      +13     
==========================================
+ Hits        18481    18823     +342     
- Misses        276      285       +9     
  Partials        3        3              
Impacted Files Coverage Δ
dev/src/collection-group.ts 95.13% <95.13%> (ø)
dev/src/bulk-writer.ts 99.76% <100.00%> (ø)
dev/src/document-change.ts 100.00% <100.00%> (ø)
dev/src/document.ts 98.77% <100.00%> (ø)
dev/src/field-value.ts 97.06% <100.00%> (ø)
dev/src/index.ts 97.58% <100.00%> (+<0.01%) ⬆️
dev/src/query-partition.ts 100.00% <100.00%> (ø)
dev/src/reference.ts 99.89% <100.00%> (+<0.01%) ⬆️
dev/src/transaction.ts 97.03% <100.00%> (ø)
dev/src/types.ts 99.37% <100.00%> (+0.01%) ⬆️
... and 3 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b493baf...e8dcaa6. Read the comment docs.

Copy link

@thebrianchen thebrianchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly left some commenting nits along with some questions

constructor(
private readonly _firestore: Firestore,
private readonly _collectionId: string,
private readonly _converter:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this converter have to be undefined here? QueryPartition's converter comes from QueryOptions, which always has FirestoreDataConverter defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Simplified.

private _memoizedStartAt: unknown[] | undefined;
private _memoizedEndBefore: unknown[] | undefined;

constructor(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add hideconstructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* @return {AsyncIterable<QueryPartition>} An AsyncIterable of
* `QueryPartition`s.
*/
async *getPartitionsAsync(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getPartitionsAsync()'s name was initially confusing to me, since I thought once the non-async one would be a function that had a : void return signature. Both getPartitionsAsync() and getPartitions() are essentially async methods, which added to my confusion.

How about getPartititionsIterator and getPartitionsPromise, or something more along those lines (granted, those 2 names are the best)? Is there any other established pattern for methods that return an iterator vs. a promise?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the precedent in the generated Gapic library. I am kind of leaning towards removing the "non-async" method (which is also async) altogether. Streaming iterators are very easy to use, so maybe there is no benefit of exposing both methods. I will ask for opinions before merging.

* The cursor that defines the first result for this partition or `undefined`
* if this is the first partition.
*
* @return a cursor value that can be used with {@link Query#startAt} or

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding other annotations (@return, @type, etc.) like in other getters. As it stands, the docs file looks pretty bare: https://screenshot.googleplex.com/mNvFsQh4X2E2msJ.png.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. We should always do this for JSDoc.

/**
* Returns a query that only returns the documents for this partition.
*
* @return a query partitioned by a {@link Query#startAt} and {@link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding return type: {Query<T>}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* The cursor that defines the first result for this partition or `undefined`
* if this is the first partition.
*
* @return a cursor value that can be used with {@link Query#startAt} or

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uber-nit: s/a cursor/A cursor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

/**
* Returns a query that only returns the documents for this partition.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider: Returns a query that only contains documents for/inside this partition.

Technically, a query doesn't "return" the documents.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used encapsulates. Let me know what you think.

expect(actual).to.deep.eq(query);
}

export function result(documentId: string): api.IRunQueryResponse {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete unused function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

queryOptions = queryOptions.with({
startAt: {before: true, values: this._startAt},
});
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how important it is to test L105-108, but codecov is complaining about missing tests here. Flagging this in-case you missed it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test that should cover this.

* The cursor that defines the first result for this partition or
* `undefined` if this is the first partition.
*
* @return cursor values that can be used with {@link Query#startAt} or

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "destructure" comment was hard for me to follow, consider adding an example of how to do so properly?

Also, consider adding test for query.startAt(..queryPartition.start)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added examples for all methods and expanded on the description of the return type. Also added test

Copy link

@thebrianchen thebrianchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, those were some pretty sleek tests

/**
* A `CollectionGroup` refers to all documents that are contained in a
* collection or subcollection with a specific collection ID.
*/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need add the CollectionGroup after @class, or else the constructor will still appear. Not sure why, but I regenerated the docs and still see the constructor with your current PR.

* A split point that can be used in a query as a starting and/or end point for
* the query results. The cursors returned by {@link #startAt} and {@link
* #endBefore} can only be used in a query that matches the constraint of query
* that produced this partition.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.

@@ -194,6 +196,126 @@ describe('Firestore class', () => {
});
});

describe('CollectionGroup class', () => {
const desiredPartitionCount = 3;
const documentCount = 2 * 128 + 127; // Minimum partition size is 128.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, just caught this, but why is the minimum partition size 128? I didn't see this requirement elsewhere in the code. Also, is this something the developer needs to know?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the partition size, but rather the minimum result set size in order for partitions to work. If a collection group has fewer than 128 documents, then it will not be partitioned. This is deemed acceptable with the current API as the provided partition count value is documented to be best effort.

@schmidt-sebastian
Copy link
Contributor Author

@BenWhitehead Can you take a look at this as well?
@bcoe Do you think it is acceptable to only provide the AsyncIterator<QueryPartition> API or do we also need to have an API that returns Promise<QueryPartition[]>

Copy link
Contributor

@BenWhitehead BenWhitehead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superficial LGTM.

The signatures look in line with the design set forward in the Java PR. But I don't know the knitty gritty of typescript so can't comment on that.

@schmidt-sebastian
Copy link
Contributor Author

Discussed offline with @bcoe. We may add a listPartitions API that returns a Promise<QueryPartition[]> at a later point. This would match listDocuments and listCollections.

@schmidt-sebastian schmidt-sebastian merged commit 51961c3 into master Oct 13, 2020
thebrianchen pushed a commit that referenced this pull request Oct 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: firestore Issues related to the googleapis/nodejs-firestore API. cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants