Skip to content

Make server timestamp methods static, rename ServerTimestamps #1222

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

Merged
merged 3 commits into from
Feb 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.ResourcePath;
import com.google.firebase.firestore.model.value.ProtoValues;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.model.value.ServerTimestamps;
import com.google.firebase.firestore.util.Executors;
import com.google.firebase.firestore.util.Util;
import com.google.firestore.v1.ArrayValue;
Expand Down Expand Up @@ -751,7 +751,7 @@ private Bound boundFromDocumentSnapshot(
components.add(ProtoValues.refValue(firestore.getDatabaseId(), document.getKey()));
} else {
Value value = document.getField(orderBy.getField());
if (ServerTimestampValue.isServerTimestamp(value)) {
if (ServerTimestamps.isServerTimestamp(value)) {
throw new IllegalArgumentException(
"Invalid query. You are trying to start or end a query using a document for which "
+ "the field '"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

package com.google.firebase.firestore;

import static com.google.firebase.firestore.model.value.ServerTimestamps.getLocalWriteTime;
import static com.google.firebase.firestore.model.value.ServerTimestamps.getPreviousValue;
import static com.google.firebase.firestore.model.value.ServerTimestamps.isServerTimestamp;
import static com.google.firebase.firestore.util.Assert.fail;

import androidx.annotation.RestrictTo;
import com.google.firebase.Timestamp;
import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.util.Logger;
import com.google.firestore.v1.ArrayValue;
import com.google.firestore.v1.Value;
Expand Down Expand Up @@ -52,8 +54,8 @@ public class UserDataWriter {
Object convertValue(Value value) {
switch (value.getValueTypeCase()) {
case MAP_VALUE:
if (ServerTimestampValue.isServerTimestamp(value)) {
return convertServerTimestamp(new ServerTimestampValue(value));
if (isServerTimestamp(value)) {
return convertServerTimestamp(value);
}
return convertObject(value.getMapValue().getFieldsMap());
case ARRAY_VALUE:
Expand Down Expand Up @@ -90,14 +92,16 @@ Map<String, Object> convertObject(Map<String, Value> mapValue) {
return result;
}

private Object convertServerTimestamp(ServerTimestampValue value) {
private Object convertServerTimestamp(Value serverTimestampValue) {
switch (serverTimestampBehavior) {
case PREVIOUS:
return value.getPreviousValue() == null ? null : convertValue(value.getPreviousValue());
Value previousValue = getPreviousValue(serverTimestampValue);
if (previousValue == null) {
return null;
}
return convertValue(previousValue);
case ESTIMATE:
return !timestampsInSnapshots
? value.getLocalWriteTime().toDate()
: value.getLocalWriteTime();
return convertTimestamp(getLocalWriteTime(serverTimestampValue));
Copy link
Contributor

Choose a reason for hiding this comment

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

:) Much better.

default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import androidx.annotation.Nullable;
import com.google.firebase.Timestamp;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.model.value.ServerTimestamps;
import com.google.firestore.v1.Value;

/** Transforms a value into a server-generated timestamp. */
Expand All @@ -31,7 +31,7 @@ public static ServerTimestampOperation getInstance() {

@Override
public Value applyToLocalView(@Nullable Value previousValue, Timestamp localWriteTime) {
return ServerTimestampValue.valueOf(localWriteTime, previousValue);
return ServerTimestamps.valueOf(localWriteTime, previousValue);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ObjectValue(Value value) {
value.getValueTypeCase() == Value.ValueTypeCase.MAP_VALUE,
"ObjectValues should be backed by a MapValue");
hardAssert(
!ServerTimestampValue.isServerTimestamp(value),
!ServerTimestamps.isServerTimestamp(value),
"ServerTimestamps should not be used as an ObjectValue");
this.internalValue = value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package com.google.firebase.firestore.model.value;

import static com.google.firebase.firestore.model.value.ServerTimestamps.getLocalWriteTime;
import static com.google.firebase.firestore.model.value.ServerTimestamps.isServerTimestamp;
import static com.google.firebase.firestore.util.Assert.fail;
import static com.google.firebase.firestore.util.Assert.hardAssert;

Expand Down Expand Up @@ -78,7 +80,7 @@ public static int typeOrder(Value value) {
case ARRAY_VALUE:
return TYPE_ORDER_ARRAY;
case MAP_VALUE:
if (ServerTimestampValue.isServerTimestamp(value)) {
if (isServerTimestamp(value)) {
return TYPE_ORDER_TIMESTAMP;
}
return TYPE_ORDER_MAP;
Expand Down Expand Up @@ -115,13 +117,9 @@ public static boolean equals(Value left, Value right) {
}

private static boolean timestampEquals(Value left, Value right) {
if (ServerTimestampValue.isServerTimestamp(left)
&& ServerTimestampValue.isServerTimestamp(right)) {
return new ServerTimestampValue(left)
.getLocalWriteTime()
.equals(new ServerTimestampValue(right).getLocalWriteTime());
} else if (ServerTimestampValue.isServerTimestamp(left)
|| ServerTimestampValue.isServerTimestamp(right)) {
if (isServerTimestamp(left) && isServerTimestamp(right)) {
return getLocalWriteTime(left).equals(getLocalWriteTime(right));
} else if (isServerTimestamp(left) || isServerTimestamp(right)) {
return false;
}

Expand Down Expand Up @@ -241,27 +239,30 @@ private static int compareNumbers(Value left, Value right) {
}

private static int compareTimestamps(Value left, Value right) {
if (ServerTimestampValue.isServerTimestamp(left)
&& ServerTimestampValue.isServerTimestamp(right)) {
return new ServerTimestampValue(left)
.getLocalWriteTime()
.compareTo(new ServerTimestampValue(right).getLocalWriteTime());
} else if (ServerTimestampValue.isServerTimestamp(left)) {
// Server timestamps come after all concrete timestamps.
return 1;
} else if (ServerTimestampValue.isServerTimestamp(right)) {
// Server timestamps come after all concrete timestamps.
return -1;
if (isServerTimestamp(left)) {
if (isServerTimestamp(right)) {
return compareTimestamps(getLocalWriteTime(left), getLocalWriteTime(right));
} else {
// Server timestamps come after all concrete timestamps.
return 1;
}
} else {
if (isServerTimestamp(right)) {
// Server timestamps come after all concrete timestamps.
return -1;
} else {
return compareTimestamps(left.getTimestampValue(), right.getTimestampValue());
}
}
}

int comparison =
Util.compareLongs(
left.getTimestampValue().getSeconds(), right.getTimestampValue().getSeconds());
if (comparison != 0) {
return comparison;
private static int compareTimestamps(Timestamp left, Timestamp right) {
int cmp = Util.compareLongs(left.getSeconds(), right.getSeconds());
if (cmp != 0) {
return cmp;
}
return Util.compareIntegers(
left.getTimestampValue().getNanos(), right.getTimestampValue().getNanos());

return Util.compareIntegers(left.getNanos(), right.getNanos());
}

private static int compareReferences(String leftPath, String rightPath) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,40 @@

package com.google.firebase.firestore.model.value;

import static com.google.firebase.firestore.util.Assert.hardAssert;

import androidx.annotation.Nullable;
import com.google.firebase.Timestamp;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firestore.v1.MapValue;
import com.google.firestore.v1.Value;

/**
* Represents a locally-applied Server Timestamp.
* Methods for manipulating locally-applied Server Timestamps.
*
* <p>Server Timestamps are backed by MapValues that contain an internal field `__type__` with a
* value of `server_timestamp`. The previous value and local write time are stored in its
* `__previous_value__` and `__local_write_time__` fields respectively.
*
* <p>Notes:
* <li>ServerTimestampValue instances are created as the result of applying a TransformMutation (see
* <li>ServerTimestamp Values are created as the result of applying a TransformMutation (see
* TransformMutation.applyTo()). They can only exist in the local view of a document. Therefore
* they do not need to be parsed or serialized.
* <li>When evaluated locally (e.g. via DocumentSnapshot data), they evaluate to null.
* <li>They sort after all TimestampValues. With respect to other ServerTimestampValues, they sort
* <li>They sort after all Timestamp Values. With respect to other ServerTimestamp Values, they sort
* by their localWriteTime.
*/
public final class ServerTimestampValue {
public final class ServerTimestamps {
private static final String SERVER_TIMESTAMP_SENTINEL = "server_timestamp";
private static final String TYPE_KEY = "__type__";
private static final String PREVIOUS_VALUE_KEY = "__previous_value__";
private static final String LOCAL_WRITE_TIME_KEY = "__local_write_time__";

private ServerTimestamps() {}

public static boolean isServerTimestamp(@Nullable Value value) {
Value type = value == null ? null : value.getMapValue().getFieldsOrDefault(TYPE_KEY, null);
return type != null && SERVER_TIMESTAMP_SENTINEL.equals(type.getStringValue());
}

private final Value internalValue;

public ServerTimestampValue(Value value) {
hardAssert(
ServerTimestampValue.isServerTimestamp(value),
"Backing value is not a ServerTimestampValue");
this.internalValue = value;
}

public static Value valueOf(Timestamp localWriteTime, @Nullable Value previousValue) {
Value encodedType = Value.newBuilder().setStringValue(SERVER_TIMESTAMP_SENTINEL).build();
Value encodeWriteTime =
Expand Down Expand Up @@ -86,17 +77,19 @@ public static Value valueOf(Timestamp localWriteTime, @Nullable Value previousVa
* backend responds with the timestamp {@link DocumentSnapshot.ServerTimestampBehavior}.
*/
@Nullable
public Value getPreviousValue() {
Value previousValue = internalValue.getMapValue().getFieldsOrDefault(PREVIOUS_VALUE_KEY, null);
if (ServerTimestampValue.isServerTimestamp(previousValue)) {
return new ServerTimestampValue(previousValue).getPreviousValue();
public static Value getPreviousValue(Value serverTimestampValue) {
Value previousValue =
serverTimestampValue.getMapValue().getFieldsOrDefault(PREVIOUS_VALUE_KEY, null);
if (isServerTimestamp(previousValue)) {
return getPreviousValue(previousValue);
}
return previousValue;
}

public Timestamp getLocalWriteTime() {
com.google.protobuf.Timestamp localWriteTime =
internalValue.getMapValue().getFieldsOrThrow(LOCAL_WRITE_TIME_KEY).getTimestampValue();
return new Timestamp(localWriteTime.getSeconds(), localWriteTime.getNanos());
public static com.google.protobuf.Timestamp getLocalWriteTime(Value serverTimestampValue) {
return serverTimestampValue
.getMapValue()
.getFieldsOrThrow(LOCAL_WRITE_TIME_KEY)
.getTimestampValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import com.google.firebase.firestore.model.Document;
import com.google.firebase.firestore.model.DocumentSet;
import com.google.firebase.firestore.model.value.ObjectValue;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.model.value.ServerTimestamps;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -86,7 +86,7 @@ public void testToObjects() {
.thenReturn(new FirebaseFirestoreSettings.Builder().build());

ObjectValue objectData =
ObjectValue.fromMap(map("timestamp", ServerTimestampValue.valueOf(Timestamp.now(), null)));
ObjectValue.fromMap(map("timestamp", ServerTimestamps.valueOf(Timestamp.now(), null)));
QuerySnapshot foo = TestUtil.querySnapshot("foo", map(), map("a", objectData), true, false);

List<POJO> docs = foo.toObjects(POJO.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import com.google.firebase.firestore.model.mutation.TransformMutation;
import com.google.firebase.firestore.model.value.ObjectValue;
import com.google.firebase.firestore.model.value.ProtoValues;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.model.value.ServerTimestamps;
import com.google.firestore.v1.Value;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -157,7 +157,7 @@ public void testAppliesLocalServerTimestampTransformsToDocuments() {
// Server timestamps aren't parsed, so we manually insert it.
ObjectValue expectedData =
wrapObject(map("foo", map("bar", "<server-timestamp>"), "baz", "baz-value"));
Value fieldValue = ServerTimestampValue.valueOf(timestamp, wrap("bar-value"));
Value fieldValue = ServerTimestamps.valueOf(timestamp, wrap("bar-value"));
expectedData = expectedData.toBuilder().set(field("foo.bar"), fieldValue).build();

Document expectedDoc =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import com.google.firebase.Timestamp;
import com.google.firebase.firestore.GeoPoint;
import com.google.firebase.firestore.model.value.ProtoValues;
import com.google.firebase.firestore.model.value.ServerTimestampValue;
import com.google.firebase.firestore.model.value.ServerTimestamps;
import com.google.firebase.firestore.testutil.ComparatorTester;
import com.google.firebase.firestore.testutil.TestUtil;
import com.google.firestore.v1.Value;
Expand Down Expand Up @@ -81,12 +81,11 @@ public void testValueEquality() {
.addEqualityGroup(wrap("\u00e9a"))
.addEqualityGroup(wrap(date1), wrap(timestamp1))
.addEqualityGroup(wrap(timestamp2))
// NOTE: ServerTimestampValues can't be parsed via wrap().
// NOTE: ServerTimestamps can't be parsed via wrap().
.addEqualityGroup(
new EqualsWrapper(ServerTimestampValue.valueOf(new Timestamp(date1), null)),
new EqualsWrapper(ServerTimestampValue.valueOf(new Timestamp(date1), null)))
.addEqualityGroup(
new EqualsWrapper(ServerTimestampValue.valueOf(new Timestamp(date2), null)))
new EqualsWrapper(ServerTimestamps.valueOf(new Timestamp(date1), null)),
new EqualsWrapper(ServerTimestamps.valueOf(new Timestamp(date1), null)))
.addEqualityGroup(new EqualsWrapper(ServerTimestamps.valueOf(new Timestamp(date2), null)))
.addEqualityGroup(wrap(geoPoint1), wrap(new GeoPoint(1, 0)))
.addEqualityGroup(wrap(geoPoint2))
.addEqualityGroup(
Expand Down Expand Up @@ -143,10 +142,8 @@ public void testValueOrdering() {

// server timestamps come after all concrete timestamps.
// NOTE: server timestamps can't be parsed with wrap().
.addEqualityGroup(
new EqualsWrapper(ServerTimestampValue.valueOf(new Timestamp(date1), null)))
.addEqualityGroup(
new EqualsWrapper(ServerTimestampValue.valueOf(new Timestamp(date2), null)))
.addEqualityGroup(new EqualsWrapper(ServerTimestamps.valueOf(new Timestamp(date1), null)))
.addEqualityGroup(new EqualsWrapper(ServerTimestamps.valueOf(new Timestamp(date2), null)))

// strings
.addEqualityGroup(wrap(""))
Expand Down