Support -0.0 in Firestore (#2751) · firebase/firebase-js-sdk@4f1f303 (original) (raw)
5 files changed
lines changed
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,8 @@ | ||
| 1 | 1 | # Unreleased |
| 2 | +- [fixed] Fixed an issue where the number value `-0.0` would lose its sign when | |
| 3 | + stored in Firestore. | |
| 4 | + | |
| 5 | +# 1.10.0 | |
| 2 | 6 | - [feature] Implemented `Timestamp.valueOf()` so that `Timestamp` objects can be |
| 3 | 7 | compared for relative ordering using the JavaScript arithmetic comparison |
| 4 | 8 | operators (#2632). |
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -438,6 +438,8 @@ export class JsonProtoSerializer { | ||
| 438 | 438 | return { doubleValue: 'Infinity' } as {}; |
| 439 | 439 | } else if (doubleValue === -Infinity) { |
| 440 | 440 | return { doubleValue: '-Infinity' } as {}; |
| 441 | +} else if (typeUtils.isNegativeZero(doubleValue)) { | |
| 442 | +return { doubleValue: '-0' } as {}; | |
| 441 | 443 | } |
| 442 | 444 | } |
| 443 | 445 | return { doubleValue: val.value() }; |
| @@ -487,6 +489,8 @@ export class JsonProtoSerializer { | ||
| 487 | 489 | return fieldValue.DoubleValue.POSITIVE_INFINITY; |
| 488 | 490 | } else if ((obj.doubleValue as {}) === '-Infinity') { |
| 489 | 491 | return fieldValue.DoubleValue.NEGATIVE_INFINITY; |
| 492 | +} else if ((obj.doubleValue as {}) === '-0') { | |
| 493 | +return new fieldValue.DoubleValue(-0); | |
| 490 | 494 | } |
| 491 | 495 | } |
| 492 | 496 |
Lines changed: 10 additions & 2 deletions
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -27,6 +27,13 @@ export function isNullOrUndefined(value: unknown): boolean { | ||
| 27 | 27 | return value === null | |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | +/** Returns whether the value represents -0. */ | |
| 31 | +export function isNegativeZero(value: number) : boolean { | |
| 32 | +// Detect if the value is -0.0. Based on polyfill from | |
| 33 | +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Object/is | |
| 34 | +return value === -0 && 1 / value === 1 / -0; | |
| 35 | +} | |
| 36 | + | |
| 30 | 37 | /** |
| 31 | 38 | * Returns whether a value is an integer and in the safe integer range |
| 32 | 39 | * @param value The value to test for being an integer and in the safe range |
| @@ -35,7 +42,8 @@ export function isSafeInteger(value: unknown): boolean { | ||
| 35 | 42 | return ( |
| 36 | 43 | typeof value === 'number' && |
| 37 | 44 | Number.isInteger(value) && |
| 38 | -(value as number) <= Number.MAX_SAFE_INTEGER && | |
| 39 | -(value as number) >= Number.MIN_SAFE_INTEGER | |
| 45 | +!isNegativeZero(value) && | |
| 46 | +value <= Number.MAX_SAFE_INTEGER && | |
| 47 | +value >= Number.MIN_SAFE_INTEGER | |
| 40 | 48 | ); |
| 41 | 49 | } |
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -47,6 +47,12 @@ apiDescribe('Firestore', (persistence: boolean) => { | ||
| 47 | 47 | }); |
| 48 | 48 | }); |
| 49 | 49 | |
| 50 | +it('can read and write number fields', () => { | |
| 51 | +return withTestDb(persistence, db => { | |
| 52 | +return expectRoundtrip(db, { a: 1, b: NaN, c: Infinity, d: -0.0 }); | |
| 53 | +}); | |
| 54 | +}); | |
| 55 | + | |
| 50 | 56 | it('can read and write array fields', () => { |
| 51 | 57 | return withTestDb(persistence, db => { |
| 52 | 58 | return expectRoundtrip(db, { array: [1, 'foo', { deep: true }, null] }); |
Lines changed: 8 additions & 7 deletions
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -34,20 +34,21 @@ export interface Equatable { | ||
| 34 | 34 | */ |
| 35 | 35 | |
| 36 | 36 | function customDeepEqual(left: unknown, right: unknown): boolean { |
| 37 | -/** | |
| 38 | - * START: Custom compare logic | |
| 39 | - */ | |
| 40 | 37 | if (typeof left === 'object' && left && 'isEqual' in left) { |
| 41 | 38 | return (left as Equatable<unknown>).isEqual(right); |
| 42 | 39 | } |
| 43 | 40 | if (typeof right === 'object' && right && 'isEqual' in right) { |
| 44 | 41 | return (right as Equatable<unknown>).isEqual(left); |
| 45 | 42 | } |
| 46 | -/** | |
| 47 | - * END: Custom compare logic | |
| 48 | - */ | |
| 49 | 43 | if (left === right) { |
| 50 | -return true; | |
| 44 | +if (left === 0.0 && right === 0.0) { | |
| 45 | +// Firestore treats -0.0 and +0.0 as not equals, even though JavaScript | |
| 46 | +// treats them as equal by default. Implemented based on MDN's Object.is() | |
| 47 | +// polyfill. | |
| 48 | +return 1 / left === 1 / right; | |
| 49 | +} else { | |
| 50 | +return true; | |
| 51 | +} | |
| 51 | 52 | } |
| 52 | 53 | if ( |
| 53 | 54 | typeof left === 'number' && |