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

fix: support byte values in Bundles #1395

Merged
merged 13 commits into from
Feb 4, 2021
Merged

Conversation

wu-hui
Copy link
Contributor

@wu-hui wu-hui commented Jan 24, 2021

No description provided.

@wu-hui wu-hui requested review from a team as code owners January 24, 2021 20:29
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Jan 24, 2021
@product-auto-label product-auto-label bot added the api: firestore Issues related to the googleapis/nodejs-firestore API. label Jan 24, 2021
@codecov
Copy link

codecov bot commented Jan 24, 2021

Codecov Report

Merging #1395 (187650b) into master (fa6721f) will decrease coverage by 0.00%.
The diff coverage is 77.77%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1395      +/-   ##
==========================================
- Coverage   98.51%   98.50%   -0.01%     
==========================================
  Files          32       32              
  Lines       19392    19397       +5     
  Branches     1273     1362      +89     
==========================================
+ Hits        19104    19107       +3     
- Misses        284      286       +2     
  Partials        4        4              
Impacted Files Coverage Δ
dev/src/document.ts 98.50% <0.00%> (-0.19%) ⬇️
dev/src/bundle.ts 94.44% <100.00%> (+0.12%) ⬆️
dev/src/timestamp.ts 100.00% <100.00%> (ø)

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 fa6721f...676be69. Read the comment docs.

Comment on lines +148 to +149
const message = BundleElement.fromObject(bundleElement).toJSON();
const buffer = Buffer.from(JSON.stringify(message), 'utf-8');
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's talk about this offline later, but this is quite an expensive operation. The steps are:

  • Manually serialize documents in ProtobufJS format
  • Read elements back Protobuf JS and convert to Proto3 JSON
  • Parse Proto3 JSON into string

This seems like an okay "quick fix", but not the most elegant solution. We should figure out whether we are ok with this quick fix or whether we should directly produce Proto3 JSON. We could use a similar approach as the Web SDK and use different serialization options in our serializer depending on the target. While this might end up being a fair amount of work, it also helps us with the timestamp conversion.

Furthermore, can you verify whether the current conversion correctly translates numbers greater than 2^53 bits? You would have to turn on useBigInt and then write a large integer value like such: 2147483647n. I am asking because the JSON roundtrip might convert this type to a lossy floating point representation.

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 for BigInt.

@@ -41,7 +42,6 @@ export class BundleBuilder {
private latestReadTime = new Timestamp(0, 0);

constructor(readonly bundleId: string) {}

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should add this back.

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.

Comment on lines 46 to 49
import BundledDocumentMetadata = firestore.BundledDocumentMetadata;
import IBundleElement = firestore.IBundleElement;
import NamedQuery = firestore.NamedQuery;
import Document = google.firestore.v1.Document;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you move these imports to a different "section" (separated by a blank space below)?

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.

structuredQuery: query.toProto().structuredQuery,
}
),
}).toJSON()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to do this round-trip here (and below)? Can we not just compare against the resulting JSON directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The trick here is the expected object we use here will have int64 encoded as number, while the actual object we get from bundles have them encoded as strings, for example.

I have created some utility functions to help with the boilerplate. Unfortunately i cannot figure out how to make them generic, because fromObject is static, and returns different types.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it not possible to manually create the desired Proto output? Would it be possible to write expect(...).to.deep.equal({integerValue:'1337'})) instead of expect(...).to.deep.equal(fromJson({integerValue:1337}).toJSON()))?

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 works for the example you give. But the tests deal a lot with timestamps, and expect(...).to.deep.equal(snap.readTime.toProto.timestampValue) will compare encoded string seconds to the actual integer value. So you get tests failures like:

      -    "seconds": "1577836805"
      +    "seconds": 1577836805

@wu-hui wu-hui assigned schmidt-sebastian and unassigned wu-hui Jan 28, 2021
}
expect(meta.id).to.equal(TEST_BUNDLE_ID);
expect(meta.version).to.equal(TEST_BUNDLE_VERSION);
expect(meta.totalDocuments).to.equal(totalDocuments);
expect(meta.createTime).to.deep.equal(createTime);
expect(google.protobuf.Timestamp.fromObject(meta.createTime!)).to.deep.equal(
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

@schmidt-sebastian schmidt-sebastian left a comment

Choose a reason for hiding this comment

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

Please update the tests to not use the JSON helpers as it hides bugs in the JSON creation.

@wu-hui wu-hui assigned schmidt-sebastian and unassigned wu-hui Feb 3, 2021
@schmidt-sebastian schmidt-sebastian changed the title Fix: Use protobuf.js toJson to get valid bundle output fix: use protobuf.js toJson to get valid bundle output Feb 3, 2021
@schmidt-sebastian schmidt-sebastian changed the title fix: use protobuf.js toJson to get valid bundle output fix: support byte values in Bundles Feb 3, 2021
dev/src/bundle.ts Outdated Show resolved Hide resolved
dev/src/bundle.ts Outdated Show resolved Hide resolved
@@ -43,12 +43,14 @@ import {
postConverterMerge,
verifyInstance,
} from '../test/util/helpers';
import IBundleElement = firestore.IBundleElement;
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for re-ordering. Can you remove the empty line?

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.

@@ -37,17 +38,17 @@ export function verifyMetadata(
expectEmptyContent = false
): void {
if (!expectEmptyContent) {
expect(meta.totalBytes).greaterThan(0);
expect(parseInt(meta.totalBytes!.toString())).greaterThan(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can probably emit toString() here (totalBytes should be a string).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's there to silent the type error, it can be number or string.

@schmidt-sebastian schmidt-sebastian removed their assignment Feb 3, 2021
wu-hui and others added 4 commits February 4, 2021 15:55
Co-authored-by: Sebastian Schmidt <mrschmidt@google.com>
Co-authored-by: Sebastian Schmidt <mrschmidt@google.com>
Copy link
Contributor

@JustinBeckwith JustinBeckwith left a comment

Choose a reason for hiding this comment

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

Rubber stamp because I broke CODEOWNERs

@wu-hui wu-hui merged commit 8cf53a9 into master Feb 4, 2021
@wu-hui wu-hui deleted the wuandy/BundlesFixJsonOutput branch February 4, 2021 22:31
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