-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add FieldValue helpers #7642
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
Add FieldValue helpers #7642
Conversation
Generated by 🚫 Danger |
e1e8d0f
to
1b6d50e
Compare
136e2c8
to
3098e4a
Compare
Coverage ReportAffected SDKs
Test Logs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly around how strings are handled.
|
||
const uint64_t kNanBits = 0x7fff000000000000ULL; | ||
|
||
} // namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entire test should be in the unnamed namespace, Costa would give you a link explaining why, I am just forwarding his review comments from my PR..something to do with avoid potential conflict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking forward to the link :) Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're interested, here's the recommendation. The idea is to prevent potential name clashes. If you were to accidentally write, say, two different functions the same name and signature in two different test files, they will clash -- the linker would presume they are the same function. That is because by default functions have external linkage and are visible (to the linker) outside of their translation unit (every .cc
file corresponds to a translation unit, and the entire program is then built from these TUs). However, functions (and variables, etc.) placed in the unnamed namespace have internal linkage and thus cannot clash (even if they have the same name, the linker will correctly interpret functions with internal linkage as two different functions).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am always interested in learning :) I hope I will remember this time.
// latin small letter e + combining acute accent | ||
Add(equals_group, Wrap("e\u0301b")); | ||
// latin small letter e with acute accent | ||
Add(equals_group, Wrap("\u00e9a")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other possible case: string with '\0' in the middle of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should already be done in the line below (added in that review cycle). I added additional ones for comparison + canoncial ID now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! I assigning it to Costa as well for some final thoughts.
|
||
const uint64_t kNanBits = 0x7fff000000000000ULL; | ||
|
||
} // namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking forward to the link :) Fixed
Firestore/core/src/model/values.h
Outdated
const int32_t kTypeOrderArray = 9; | ||
const int32_t kTypeOrderMap = 10; | ||
|
||
class Values { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General observation: this class is very Java-style. Since there are no free functions in Java, creating classes that only have static methods makes sense. In C++, it's more natural to just use free functions (note, there's nothing wrong with using free functions when they are appropriate). The private static functions can just be moved into the implementation file (the .cc
file), with the additional benefit of a smaller header file.
Similarly, the pattern of naming an utility class that deals with Foo
s Foos
is specific to Java. Consider a file name like value_ordering
, field_value_ordering
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made all methods free-standing and renamed the file to "value.h/cc". Should we create a separate namespace the functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks much better now.
Re. the file name -- do you plan to add more functions (that aren't concerned with comparisons) to this file in the future?
Should we create a separate namespace the functions?
We use namespaces for system layers, so to speak (e.g. model
or remote
), but not for finer-grained combinations. This is fine to just be in the model
namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file contains equals, compareTo and canonical ID support. That's all we have on Web and Android, but in general we treated this file as a "proto values utility" class on the other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: a file named value
seems to indicate that it defines a Value
class. I don't have a better suggestion than the uninspired value_helpers
, but personally, I feel it would convey the intention better (same for the server timestamp one). If you can think of a better name, that's great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to value_util.h to match nanopb_util.h
|
||
template <typename... Args> | ||
google_firestore_v1_Value WrapObject(Args... key_value_pairs) { | ||
FieldValue fv = testutil::WrapObject((key_value_pairs)...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits:
- the extra parentheses around
key_value_pairs
are unnecessary; - it's not very important because it's a test file, but ideally you would make sure to forward the arguments to
WrapObject
to avoid extra copies (thoughWrapObject
's implementation would then proceed to create those copies regardless -- ideally it should be fixed, but that's out of scope for this PR):
template <typename... Args>
// Make `Args` a forwarding reference
google_firestore_v1_Value WrapObject(Args&&... key_value_pairs) {
FieldValue fv = testutil::WrapObject(std::forward<Args>(key_value_pairs)...);
Feel free to disregard the point re. forwarding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed both. Thanks for the explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for implementing the feedback!
Firestore/core/src/model/values.h
Outdated
const int32_t kTypeOrderArray = 9; | ||
const int32_t kTypeOrderMap = 10; | ||
|
||
class Values { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks much better now.
Re. the file name -- do you plan to add more functions (that aren't concerned with comparisons) to this file in the future?
Should we create a separate namespace the functions?
We use namespaces for system layers, so to speak (e.g. model
or remote
), but not for finer-grained combinations. This is fine to just be in the model
namespace.
|
||
const uint64_t kNanBits = 0x7fff000000000000ULL; | ||
|
||
} // namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're interested, here's the recommendation. The idea is to prevent potential name clashes. If you were to accidentally write, say, two different functions the same name and signature in two different test files, they will clash -- the linker would presume they are the same function. That is because by default functions have external linkage and are visible (to the linker) outside of their translation unit (every .cc
file corresponds to a translation unit, and the entire program is then built from these TUs). However, functions (and variables, etc.) placed in the unnamed namespace have internal linkage and thus cannot clash (even if they have the same name, the linker will correctly interpret functions with internal linkage as two different functions).
Firestore/core/src/model/values.cc
Outdated
} | ||
|
||
for (size_t i = 0; i < right_map.fields_count; ++i) { | ||
const std::string& key = nanopb::MakeString(right_map.fields[i].key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you trying to use flat_hash_map
(judging by container_internal::FlatHashMapPolicy
)? Can you try adding absl::flat_hash_map
to the dependencies?
Firestore/core/src/model/value.h
Outdated
kTypeOrderArray = 9, | ||
kTypeOrderMap = 10 | ||
enum class TypeOrder { | ||
Null = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: enum members should be named like constants, i.e. prefixed with a k
(e.g. kNull
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should get my inspirations from the style guide, and not from other places in the code :)
Firestore/core/src/model/values.cc
Outdated
} | ||
|
||
for (size_t i = 0; i < right_map.fields_count; ++i) { | ||
const std::string& key = nanopb::MakeString(right_map.fields[i].key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: as far as I understand, the underscored targets are supposed to be internal, and the public Abseil targets have semicolons in them (e.g. absl::flat_hash_map
is public) (I'm basing this on this readme). If you're interested, you can try to add absl::flat_hash_map
to the list of dependencies. If that doesn't help, it's probably not worth spending any extra time on.
Firestore/core/src/model/values.h
Outdated
const int32_t kTypeOrderArray = 9; | ||
const int32_t kTypeOrderMap = 10; | ||
|
||
class Values { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: a file named value
seems to indicate that it defines a Value
class. I don't have a better suggestion than the uninspired value_helpers
, but personally, I feel it would convey the intention better (same for the server timestamp one). If you can think of a better name, that's great.
This PR adds equal, compareTo and canonicalId helpers that work directly on Protobuf field values.
This is a port of
https://github.com/firebase/firebase-android-sdk/blob/master/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.java
https://github.com/firebase/firebase-android-sdk/blob/master/firebase-firestore/src/test/java/com/google/firebase/firestore/model/ValuesTest.java
and of some of the code that we need from https://github.com/firebase/firebase-android-sdk/blob/master/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ServerTimestamps.java