-
Notifications
You must be signed in to change notification settings - Fork 892
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 Numeric Add #1368
Add Numeric Add #1368
Conversation
30eea3f
to
03e0063
Compare
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.
LGTM with a few nits!
packages/firebase/index.d.ts
Outdated
* are subject to precision loss. Furthermore, once processed by the Firestore | ||
* backend, all integer operations are capped between -2^63 and 2^63-1. | ||
* | ||
* If field is not an integer or double, or if the field does not yet exist, |
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 field" => "If the field"
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
packages/firebase/index.d.ts
Outdated
* Returns a special value that can be used with set() or update() that tells | ||
* the server to add the given value to the field's current value. | ||
* | ||
* If either the operand or the current field value is of type double, both |
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.
FWIW it's tempting to try to avoid using "double" because JavaScript just has Numbers (and so we should just talk about integer and non-integer numbers). But the backend has doubles, so I guess this needs to cover that. Anyway, it's going to be subtly confusing no matter how we explain it, so this is probably fine. :-)
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 changed this section to:
* If either the operand or the current field value uses floating point
* precision, all arithmetic will follow IEEE 754 semantics. If both values
* are integers, values outside of JavaScript's safe number range
* (`Number.MIN_SAFE_INTEGER` to `Number.MAX_SAFE_INTEGER`) are also subject
* to precision loss. Furthermore, once processed by the Firestore backend,
* all integer operations are capped between -2^63 and 2^63-1.
*
* If the current field value is not of type number, or if the field does not
* yet exist, the transformation will set the field to the given value.
@@ -50,6 +53,11 @@ export abstract class FieldValueImpl implements firestore.FieldValue { | |||
return new ArrayRemoveFieldValueImpl(elements); | |||
} | |||
|
|||
static numericAdd(n: number): FieldValueImpl { |
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 should probably use validateExactNumberOfArgs() to verify we got 1 arg. delete() and serverTimestamp() should probably be verifying no args.
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.
Done. I added a validateNoArgs
and used it in delete()
and serverTimestamp()
.
* non-idempotent write before the write is removed from the queue. | ||
* | ||
* These mutations are never sent to the backend and serialized via | ||
* JsonProtoSerializer.toMutation(). |
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 kind of sounds like you're saying they're never serialized via JsonProtoSerializer.toMutation(). In general it seems awkward to combine these two statements into one sentence. They don't seem very related.
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 removed the last part of this.
const keys = mutations.reduce( | ||
(keys, m) => keys.add(m.key), | ||
documentKeySet() | ||
); |
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.
Nice!
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.
s/Nice/Oh... Nice/g
const fieldMask = mutation.fieldMask; | ||
if (fieldMask) { | ||
if (maybeDoc instanceof Document) { | ||
const baseValues = fieldMask.applyTo(maybeDoc.data); |
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.
Can you port the latest Android? (Assign baseValues using ternary operator and include comment about Precondition.exists(true)).
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.
Done
@@ -228,6 +228,7 @@ export class MemoryEagerDelegate implements ReferenceDelegate { | |||
return cache | |||
.getMatchingKeysForTargetId(txn, queryData.targetId) | |||
.next(keys => { | |||
console.log('Found matching keys ' + keys.size); |
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.
Shouldn't tslint yell about this? (and throughout the rest of this PR)
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.
Uhm. Sorry. I had a bunch of GitHub trouble where it wouldn't show my latest changes. Looks like I rebasing my stashed changes from last week solved my troubles :/
return new DoubleValue(sum); | ||
} | ||
|
||
// If the existing value is not a number, use the value of the transform as |
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.
Can you put this in an else block? (since I don't like early return and conceptually I think there are 3 possible cases here and we should just structure the code as such)
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.
Done
@@ -595,7 +595,7 @@ describeSpec('Writes:', [], () => { | |||
|
|||
specTest( | |||
'Writes are released when there are no queries left', | |||
['eager-gc'], | |||
['eager-gc','exclusive'], |
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 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.
Mila must have pushed to this branch. Investigating.
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.
Feedback addressed, and random changes reverted.
packages/firebase/index.d.ts
Outdated
* Returns a special value that can be used with set() or update() that tells | ||
* the server to add the given value to the field's current value. | ||
* | ||
* If either the operand or the current field value is of type double, both |
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 changed this section to:
* If either the operand or the current field value uses floating point
* precision, all arithmetic will follow IEEE 754 semantics. If both values
* are integers, values outside of JavaScript's safe number range
* (`Number.MIN_SAFE_INTEGER` to `Number.MAX_SAFE_INTEGER`) are also subject
* to precision loss. Furthermore, once processed by the Firestore backend,
* all integer operations are capped between -2^63 and 2^63-1.
*
* If the current field value is not of type number, or if the field does not
* yet exist, the transformation will set the field to the given value.
packages/firebase/index.d.ts
Outdated
* are subject to precision loss. Furthermore, once processed by the Firestore | ||
* backend, all integer operations are capped between -2^63 and 2^63-1. | ||
* | ||
* If field is not an integer or double, or if the field does not yet exist, |
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
@@ -50,6 +53,11 @@ export abstract class FieldValueImpl implements firestore.FieldValue { | |||
return new ArrayRemoveFieldValueImpl(elements); | |||
} | |||
|
|||
static numericAdd(n: number): FieldValueImpl { |
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.
Done. I added a validateNoArgs
and used it in delete()
and serverTimestamp()
.
* non-idempotent write before the write is removed from the queue. | ||
* | ||
* These mutations are never sent to the backend and serialized via | ||
* JsonProtoSerializer.toMutation(). |
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 removed the last part of this.
const keys = mutations.reduce( | ||
(keys, m) => keys.add(m.key), | ||
documentKeySet() | ||
); |
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.
s/Nice/Oh... Nice/g
@@ -228,6 +228,7 @@ export class MemoryEagerDelegate implements ReferenceDelegate { | |||
return cache | |||
.getMatchingKeysForTargetId(txn, queryData.targetId) | |||
.next(keys => { | |||
console.log('Found matching keys ' + keys.size); |
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.
Uhm. Sorry. I had a bunch of GitHub trouble where it wouldn't show my latest changes. Looks like I rebasing my stashed changes from last week solved my troubles :/
return new DoubleValue(sum); | ||
} | ||
|
||
// If the existing value is not a number, use the value of the transform as |
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.
Done
@@ -595,7 +595,7 @@ describeSpec('Writes:', [], () => { | |||
|
|||
specTest( | |||
'Writes are released when there are no queries left', | |||
['eager-gc'], | |||
['eager-gc','exclusive'], |
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.
Mila must have pushed to this branch. Investigating.
const fieldMask = mutation.fieldMask; | ||
if (fieldMask) { | ||
if (maybeDoc instanceof Document) { | ||
const baseValues = fieldMask.applyTo(maybeDoc.data); |
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.
Done
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, changes look good!
@@ -83,6 +91,12 @@ export class ArrayRemoveFieldValueImpl extends FieldValueImpl { | |||
} | |||
} | |||
|
|||
export class NumericAddFieldValueImpl extends FieldValueImpl { | |||
constructor(readonly _operand: number) { |
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 would do public readonly
to make the intent clear.
@@ -644,6 +646,15 @@ export class UserDataConverter { | |||
context.fieldTransforms.push( | |||
new FieldTransform(context.path, arrayRemove) | |||
); | |||
} else if (value instanceof NumericAddFieldValueImpl) { |
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.
An alternative if you are not matching super class.
switch( value.constructor) {
case NumericAddFieldValueImpl:
....
}
FYI: Pushed commit to rename |
PR updated with new Protobuf naming. |
Hello @schmidt-sebastian |
@mohshraim We're waiting on the backend changes to fully deploy. Sorry for the delay. |
Port of firebase/firebase-android-sdk#105
Unlike Android, this PR doesn't treat INT64 overflows, as JavaScript's precision is limited to 53 bit. We likely can't properly expose the full backend semantics to our customers since we eventually surface the results as a number.
This limitation is currently - along with the rest of the API - going through API review.