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

Make Timestamp a part of the public Firestore API. #544

Merged
merged 21 commits into from
Mar 30, 2018

Conversation

var-const
Copy link
Contributor

No description provided.

This is a transitional state; eventually, Timestamp will live in a new
separate package (common-types/).

Also:
- move Timestamp.fromISOString method into Serializer, the only place of
usage;
- rename nanos to nanoseconds.
Truncate Timestamps to microseconds immediately upon receiving them as a parameter, so that offline and online behavior is consistent.
The behavior to return timestamp fields as dates is now legacy. It's on
by default to allow for a transitional period. The new behavior to
return Timestamp objects instead is opt-in, but will become default in
the future. The advantage Timestamps have is higher precision than
native browser Date. If the new behavior is not enabled, a warning is
logged on startup urging users to upgrade.
Copy link
Contributor Author

@var-const var-const left a comment

Choose a reason for hiding this comment

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

Hi Michael,

I decided to do this as a single PR, partially because it's similar to other platforms that were reviewed already, and partially because line count is lower in TypeScript. The PR is split into 3 meaningful commits. If you'd rather have me split this into 3 PRs, I'll do it.

The one thing I'm not sure about is the suggestion from API review that Timestamp should live in a common-types/ folder. Currently, all such folders come in pairs, e.g. firestore/ and firestore-types/. I'm not sure if it should be common/ and common-types/?

* Creates a new timestamp from the given number of milliseconds since Unix
* epoch 1970-01-01T00:00:00Z.
*/
static fromMillis(milliseconds: number): Timestamp;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed the name to match the API review doc, let me know if you think we should try to push back on this.

@@ -296,6 +321,32 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
'FirestoreSettings.host cannot be falsey'
);

if (!this._config.settings.timestampsInSnapshotsEnabled) {
log.error(`
The default behavior for Date objects stored in Firestore is going to change
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. After seeing this message in the logs, wrapping it to 80 columns seemed like a good idea.
  2. This message gets logged about a thousand times during tests. It's super-annoying, do you have any suggestions on how to disable it during a test run?

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Good call.
  2. Can we just set it to true, at least for the majority of our tests? That would be desirable, since that'll be the eventual default anyway.

FWIW- since this is javascript, we could have tests do hackiness like:

let oldConsoleError = console.error;
console.error = () => { };
...
console.error = oldConsoleError;

That might be okay if there was a very well-defined scope where we wanted to suppress the log message, but it's probably not a great solution. :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. Do you think this applies to other platforms as well? I'm not sure how developers usually read logs there.
  2. Setting it to true sounds good, but I'd like to clarify before implementing: it leads to breakage of 11 existing tests, mostly around server timestamps. Do you think the tests should be changed to anticipate the new behavior, or should I specifically use the old behavior in these tests?

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Hrm. I suspect wrapping to 80 columns would be friendly on the other platforms, though I don't remember if Xcode and Android Studio wrap automatically in their consoles or not. So when you revisit the log messages pending API review feedback, etc., maybe wrap them, but I am not too concerned about it.
  2. I think the 11 tests should be changed to expect the new behavior, but I'd make sure we have at least one test that verifies server timestamps return Dates (for ServerTimestampBehavior 'estimate') if you have the enableTimestampsInSnapshots setting turned off.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed the tests, including one test for server timestamps that previously checked for Timestamps if the setting is true, but now checks for Dates if setting is false.

@@ -387,7 +438,9 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
if (this._firestoreClient) {
return this._firestoreClient.shutdown();
}
}
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if this should be in INTERNAL. My reasoning was that it seems that in TypeScript, current settings aren't exposed (or I just missed it).

Copy link
Contributor

Choose a reason for hiding this comment

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

INTERNAL is semi-public. So as-is users of the SDK could access this via firebase.firestore().INTERNAL.areTimestampsInSnapshotsEnabled() which we don't really want. So I think instead I'd make this a property on Firestore:

get _areTimestampsInSnapshotsEnabled(): boolean {
return this._config.settings.timestampsInSnapshotsEnabled;
}

Note that we use '_' for any members of our public API classes (like Firestore) that we don't want to be visible in our public API. There's a minification step as part of our build that will rename '_blah' properties to obfuscated names.

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, thanks for the explanation.


constructor(readonly seconds: number, readonly nanoseconds: number) {
if (nanoseconds < 0) {
throw new FirestoreError(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Use throw instead of assert.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this comment is asking a question, but I think throw is appropriate since this is a user-facing error rather than an internal assertion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for not being clear, I just wanted to draw attention to the change.

@@ -69,21 +69,32 @@ export enum ServerTimestampBehavior {

/** Holds properties that define field value deserialization options. */
export class FieldValueOptions {
static readonly defaultOptions = new FieldValueOptions(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed defaultOptions like elsewhere.

@@ -83,6 +83,9 @@ const OPERATORS = (() => {
return ops;
})();

// A RegExp matching ISO 8601 UTC timestamps with optional fraction.
const ISO_REG_EXP = new RegExp(/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.(\d+))?Z$/);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I originally moved everything connected to parsing ISO strings here to avoid exposing this functionality in the public API. I guess it was possible to leave it on the Timestamp and not declare it in index.d.ts file (at least I assume so), but on the other hand, that functionality is only used in the serializer. Feel free to push back on this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, it would be fine to have it in Timestamp but not expose it in the .d.ts. Though we would also want to prefix the APIs with '_' to ensure they're minified. That said, it seems like ISO timestamp conversion is specific to the web serializer implementation (we don't have iso timestamp conversion in the iOS / Android Timestamp.java implementation) and so keeping it in the serializer sounds good to me.

@@ -86,6 +86,11 @@ export function toDataArray(
return docSet.docs.map(d => d.data());
}

/** Converts a DocumentSet to an array with the id of each document */
export function toIds(docSet: firestore.QuerySnapshot): 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.

There is a similar helper function on iOS and Android (I hope I didn't miss it here).

Copy link
Contributor

Choose a reason for hiding this comment

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

It's possible it was omitted because map() is so easy in JS, but I'm not opposed to having it.

});
});

it('fromISOString', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to serializer tests.

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Awesome. I haven't reviewed the code yet but I preemptively replied to a couple of your comments. As for where to put Timestamp (creating a common/ and common-types/ directory, etc.), that is a question for @jshcrowthe. Josh, is this on your radar? We've been asked to contribute Timestamp as a "common" type to be used by Firestore but potentially other parts of the Firebase SDK in the future (ping me or @var-const for more details).

@@ -387,7 +438,9 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
if (this._firestoreClient) {
return this._firestoreClient.shutdown();
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

INTERNAL is semi-public. So as-is users of the SDK could access this via firebase.firestore().INTERNAL.areTimestampsInSnapshotsEnabled() which we don't really want. So I think instead I'd make this a property on Firestore:

get _areTimestampsInSnapshotsEnabled(): boolean {
return this._config.settings.timestampsInSnapshotsEnabled;
}

Note that we use '_' for any members of our public API classes (like Firestore) that we don't want to be visible in our public API. There's a minification step as part of our build that will rename '_blah' properties to obfuscated names.


constructor(readonly seconds: number, readonly nanoseconds: number) {
if (nanoseconds < 0) {
throw new FirestoreError(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this comment is asking a question, but I think throw is appropriate since this is a user-facing error rather than an internal assertion.

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Overall looks great. Have a few minor requests, mostly around comments, etc.

* DocumentSnapshot}s.
*
* Currently, Firestore returns timestamp fields as {@link Date} but {@link
* Date} only supports millisecond precision, which leads to truncation and
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting! I didn't know @link was available in JSDoc / TypeDoc (this is TypeScript so in theory we'd use something like TypeDoc, but in practice we end up copying these comments into an externs file and generating docs via JSDoc :-/). That said, I'd be surprised if {@link Date} will do anything useful, since Date isn't defined in the codebase (and there isn't a canonical location for docs on JavaScript standard types). So I'd be inclined to do Date or "a JavaScript Date object" or similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Examining the file, it appears that class names are just wrapped in code tags ``. Changed all usages of @link to this. What do you think about using Date and wrapping it in backticks?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that seems fine and consistent with what we've been doing. Using @link might be a good idea, but we can tackle that holistically at a later time.

@@ -20,21 +20,45 @@ import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
* Document data (for use with `DocumentReference.set()`) consists of fields
* mapped to values.
*/
export type DocumentData = { [field: string]: any };
export type DocumentData = {
[field: string]: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you intentionally add these semicolons? I don't care one way or the other. I'm surprised that it's apparently optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty sure this is from the precommit code formatting. I'll have to figure out why it reformats so much before merging; rerunning yarn didn't seem to help.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see. It looks like if I remove the semicolon, prettier adds it back, but if I completely undo this change (remove the semicolon and put this back to being one line) then prettier leaves it as-is... Maybe you ended up formatting with a "wrong" version and then the "right" version, which had a different net effect than just formatting with the "right" version or something? I don't know... Anyway, I'm not inclined to worry about it for this PR...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, this sounds like it could be the cause. I first formatted using clang-format, which resulted in a pretty different formatting, and I guess prettier couldn't restore it successfully.

*/
static now(): Timestamp;

/** Creates a new timestamp from the given date. */
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 add the @param / @return comments? I'm happy to omit them in our normal codebase, but this .d.ts file (indirectly) ends up being used to generate docs, so I think we want to be complete.

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.

These comments become pretty repetitive, please let me know what you think.

/**
* Creates a new timestamp.
*
* @param seconds represents seconds of UTC time since Unix epoch
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 rather than "seconds represents seconds ..." we probably want "seconds The number of seconds ..." or similar to match our other comments.

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.

*/
toMillis(): number;

compareTo(other: Timestamp): number;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should expose compareTo() in our public API. We don't on any of our other types today.

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.

@@ -86,6 +86,11 @@ export function toDataArray(
return docSet.docs.map(d => d.data());
}

/** Converts a DocumentSet to an array with the id of each document */
export function toIds(docSet: firestore.QuerySnapshot): String[] {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's possible it was omitted because map() is so easy in JS, but I'm not opposed to having it.

const makeTimestamp = (seconds, micros) =>
new Timestamp(seconds, micros * 1000);

it('can accept Timestamps as limits', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if this was copied from elsewhere, but since we have a limit() API, this would be clearer as "can accept Timestamps as bounds" or similar.

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. Yes, I used similar test names on other platforms, I guess I'll change them to refer to "bounds" as well.

longitude: 4.56
}
};
const expected = { geoPointValue: { latitude: 1.23, longitude: 4.56 } };
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious if you reformatted these or prettier did it for some reason...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

prettier is the culprit!

return this.seconds * 1000 + this.nanoseconds / 1e6;
}

compareTo(other: Timestamp): number {
Copy link
Contributor

Choose a reason for hiding this comment

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

Assuming we don't make this public, can you rename to _compareTo()?

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.

Does it apply to isEqual as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

isEqual() is considered part of our public API and so we don't want it minified and so it should stay isEqual(), not _isEqual().


isEqual(other: Timestamp): boolean;

toString(): string;
Copy link
Contributor

Choose a reason for hiding this comment

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

toString() exists on any Object in JavaScript and doesn't need to be explicitly listed here.

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.

@var-const var-const requested a review from jshcrowthe as a code owner March 8, 2018 21:17
Copy link
Contributor Author

@var-const var-const left a comment

Choose a reason for hiding this comment

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

One more question: it looks like dist/ folder contains build artifacts. Should I update it? If yes, how do I do it?

@@ -20,21 +20,45 @@ import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
* Document data (for use with `DocumentReference.set()`) consists of fields
* mapped to values.
*/
export type DocumentData = { [field: string]: any };
export type DocumentData = {
[field: string]: any;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty sure this is from the precommit code formatting. I'll have to figure out why it reformats so much before merging; rerunning yarn didn't seem to help.

* DocumentSnapshot}s.
*
* Currently, Firestore returns timestamp fields as {@link Date} but {@link
* Date} only supports millisecond precision, which leads to truncation and
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Examining the file, it appears that class names are just wrapped in code tags ``. Changed all usages of @link to this. What do you think about using Date and wrapping it in backticks?

@@ -127,6 +128,8 @@ class FirestoreSettings {
/** Whether to use SSL when connecting. */
ssl: boolean;

timestampsInSnapshotsEnabled: boolean;
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.

}

isEqual(other: FirestoreSettings): boolean {
return (
this.host === other.host &&
this.ssl === other.ssl &&
this.timestampsInSnapshotsEnabled == other.timestampsInSnapshotsEnabled &&
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.


constructor(readonly seconds: number, readonly nanoseconds: number) {
if (nanoseconds < 0) {
throw new FirestoreError(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for not being clear, I just wanted to draw attention to the change.

*/
static now(): Timestamp;

/** Creates a new timestamp from the given date. */
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.

These comments become pretty repetitive, please let me know what you think.

/**
* Creates a new timestamp.
*
* @param seconds represents seconds of UTC time since Unix epoch
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.


compareTo(other: Timestamp): number;

isEqual(other: Timestamp): boolean;
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.

@@ -387,7 +438,9 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
if (this._firestoreClient) {
return this._firestoreClient.shutdown();
}
}
},
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, thanks for the explanation.

settings.timestampsInSnapshotsEnabled,
DEFAULT_TIMESTAMPS_IN_SNAPSHOTS_ENABLED
);
this.timestampsInSnapshotsEnabled = settings.timestampsInSnapshotsEnabled;
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, thanks for spotting it.

- add additional comments in Timestamp declarations;
- remove unnecessary method declarations from Timestamp;
- rename timestampsInSnapshotsEnabled -> timestampsInSnapshots;
- use timestampsInSnapshots = true in tests;
- small code cleanup.
@var-const var-const force-pushed the varconst-timestamp2 branch from 4f58e9d to ff1583d Compare March 8, 2018 23:21
Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Thanks! Changes look good pending the remaining test fixup...

* DocumentSnapshot}s.
*
* Currently, Firestore returns timestamp fields as {@link Date} but {@link
* Date} only supports millisecond precision, which leads to truncation and
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that seems fine and consistent with what we've been doing. Using @link might be a good idea, but we can tackle that holistically at a later time.

@@ -20,21 +20,45 @@ import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
* Document data (for use with `DocumentReference.set()`) consists of fields
* mapped to values.
*/
export type DocumentData = { [field: string]: any };
export type DocumentData = {
[field: string]: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see. It looks like if I remove the semicolon, prettier adds it back, but if I completely undo this change (remove the semicolon and put this back to being one line) then prettier leaves it as-is... Maybe you ended up formatting with a "wrong" version and then the "right" version, which had a different net effect than just formatting with the "right" version or something? I don't know... Anyway, I'm not inclined to worry about it for this PR...

@@ -296,6 +321,32 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
'FirestoreSettings.host cannot be falsey'
);

if (!this._config.settings.timestampsInSnapshotsEnabled) {
log.error(`
The default behavior for Date objects stored in Firestore is going to change
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Hrm. I suspect wrapping to 80 columns would be friendly on the other platforms, though I don't remember if Xcode and Android Studio wrap automatically in their consoles or not. So when you revisit the log messages pending API review feedback, etc., maybe wrap them, but I am not too concerned about it.
  2. I think the 11 tests should be changed to expect the new behavior, but I'd make sure we have at least one test that verifies server timestamps return Dates (for ServerTimestampBehavior 'estimate') if you have the enableTimestampsInSnapshots setting turned off.

return this.seconds * 1000 + this.nanoseconds / 1e6;
}

compareTo(other: Timestamp): number {
Copy link
Contributor

Choose a reason for hiding this comment

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

isEqual() is considered part of our public API and so we don't want it minified and so it should stay isEqual(), not _isEqual().

Also add a test to make sure server timestamps retain the old behavior
if the global settings if not set.
Copy link
Contributor Author

@var-const var-const left a comment

Choose a reason for hiding this comment

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

I will hold off merging until API review passes. Also, I have a question: it looks like dist/ folder contains build artifacts, do I have to/how do I update its contents?

@@ -157,12 +165,29 @@ class FirestoreSettings {
settings.credentials
);
this.credentials = settings.credentials;

if (settings.timestampsInSnapshotsEnabled === undefined) {
this.timestampsInSnapshotsEnabled = DEFAULT_TIMESTAMPS_IN_SNAPSHOTS_ENABLED;
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.

@@ -296,6 +321,32 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
'FirestoreSettings.host cannot be falsey'
);

if (!this._config.settings.timestampsInSnapshotsEnabled) {
log.error(`
The default behavior for Date objects stored in Firestore is going to change
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed the tests, including one test for server timestamps that previously checked for Timestamps if the setting is true, but now checks for Dates if setting is false.

@@ -20,21 +20,45 @@ import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
* Document data (for use with `DocumentReference.set()`) consists of fields
* mapped to values.
*/
export type DocumentData = { [field: string]: any };
export type DocumentData = {
[field: string]: any;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, this sounds like it could be the cause. I first formatted using clang-format, which resulted in a pretty different formatting, and I guess prettier couldn't restore it successfully.

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Test changes look good. Thanks! Also, I forgot to reply to your comment about dist/ but you shouldn't ever need to check in anything there. That's all build output, and shouldn't be in git AFAIK.

Copy link
Contributor Author

@var-const var-const left a comment

Choose a reason for hiding this comment

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

@mikelehen Michael, sorry, I have a couple more questions:

  • I just noticed that the automated "prettier" commit added a huge package-lock.json file. I'm pretty sure this has happened before, but I didn't notice and didn't remove it this time. Is this a known issue?
  • since in this PR, we decided to configure tests to use the new behavior, do you think other platforms should be updated to do the same?

@mikelehen
Copy link
Contributor

Hrm. My guess is you accidentally created the package-lock.json file while the prepush hook was running and it looks like (

await git.add('.');
) it just does a "git add ." at the end and so it inadvertently included it... cc/ @jshcrowthe We should probably do "git add -u" or skip "git add" and just do a "git commit -a"

I'm not 100% sure what you would have done to create package-lock.json though... perhaps you did an "npm" command instead of "yarn" or something? FYI- I think I see an unintentional files.txt in your PR too...

As for the test configuration change, yes please! Other than things that are actually platform-specific we want to keep the platforms as in-sync as possible. It's a bit painful but it makes for healthy and consistent codebases. So the effort is appreciated. :-)

- make _areTimestampsInSnapshotsEnabled a regular function instead of
a property (underscore in the name doesn't work well with the minifier);
- remove type annotations from code snippets in the log warning, and
change reference to `app` (presumably a variable defined previously) to
`firebase.app()`;
- undo most of formatting changes (the exception is breaking lines above
the column limit);
- restore alphabetical order of imports.
@var-const var-const assigned mikelehen and unassigned var-const Mar 28, 2018
@var-const
Copy link
Contributor Author

@mikelehen Michael, could you please take another look? The only change since the last time is slight tweaking of warning due to feedback on the doc. The idea was to phrase it clearer that the current behavior is not going to be supported in the future. I'll be happy to change if you'd like.

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

LGTM with minor nit and unfortunately we need to update a couple more index.d.ts files. :-/

@@ -35,6 +35,26 @@ export interface Settings {
host?: string;
/** Whether to use SSL when connecting. */
ssl?: boolean;

Copy link
Contributor

Choose a reason for hiding this comment

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

So... it turns out our types exist in 3 .d.ts files. 😦 @jshcrowthe has plans to fix this, but for now can you update packages/firebase/index.d.ts and packages/firebase/app/index.d.ts too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the tip!

To hide this warning and ensure your app does not break, you need to add the
following code to your app before calling any other Cloud Firestore methods:

const firestore = firebase.firestore(firebase.app());
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 firebase.app() is not necessary? Just doing firebase.firestore() should use the default app...

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.

Just out of curiosity, where is the code handling this?

Copy link
Contributor

Choose a reason for hiding this comment

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

So it's a bit convoluted. firebase.firestore() is actually a function that FirebaseApp creates when we (Firestore) call firebase.INTERNAL.registerService() to register ourselves. So:

  1. We call firebase.INTERNAL.registerService() here:
    (firebase as _FirebaseNamespace).INTERNAL.registerService(
  2. It creates this serviceNamespace which is the firebase.firestore() function [see line 369] except it also has properties like firebase.firestore.FieldValue hence it's called a "namespace":
    const serviceNamespace = (appArg: FirebaseApp = app()) => {
  3. That serviceNamespace function defaults to using the default app (appArg: FirebaseApp = app()).

So app is optional...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I tried finding it in the code, realized it's something dynamically created and gave up.

@mikelehen mikelehen removed their assignment Mar 29, 2018
Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Still LGTM. Tiny optional suggestion for changelog.

@@ -2,6 +2,14 @@
- [fixed] Fixed a regression in the Firebase JS release 4.11.0 that could
cause get() requests made while offline to be delayed by up to 10
seconds (rather than returning from cache immediately).
- [feature] Added a new `Timestamp` class to represent timestamp fields,
currently supporting up to microsecond precision. It can be passed to API
methods anywhere a system Date is currently accepted. To make
Copy link
Contributor

Choose a reason for hiding this comment

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

optional nit: 'JS Date object' might be clearer than 'system Date' (here and below)

Copy link
Contributor

@jshcrowthe jshcrowthe left a comment

Choose a reason for hiding this comment

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

Non package specific changes LGTM 👍

@var-const var-const merged commit 1608edb into master Mar 30, 2018
@jshcrowthe jshcrowthe deleted the varconst-timestamp2 branch April 16, 2018 21:58
@firebase firebase locked and limited conversation to collaborators Oct 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants