Skip to content

Commit 674c666

Browse files
Add ServerTimestamp helpers
1 parent 1a0b08d commit 674c666

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import * as api from '../protos/firestore_proto_api';
2+
import { Timestamp } from '../api/timestamp';
3+
import { normalizeTimestamp } from './proto_values';
4+
5+
/**
6+
* Represents a locally-applied ServerTimestamp.
7+
*
8+
* Server Timestamps are backed by MapValues that contain an internal field
9+
* `__type__` with a value of `server_timestamp`. The previous value and local
10+
* write time are stored in its `__previous_value__` and `__local_write_time__`
11+
* fields respectively.
12+
*
13+
* Notes:
14+
* - ServerTimestampValue instances are created as the result of applying a
15+
* TransformMutation (see TransformMutation.applyTo()). They can only exist in
16+
* the local view of a document. Therefore they do not need to be parsed or
17+
* serialized.
18+
* - When evaluated locally (e.g. for snapshot.data()), they by default
19+
* evaluate to `null`. This behavior can be configured by passing custom
20+
* FieldValueOptions to value().
21+
* - With respect to other ServerTimestampValues, they sort by their
22+
* localWriteTime.
23+
*/
24+
25+
const SERVER_TIMESTAMP_SENTINEL = 'server_timestamp';
26+
const TYPE_KEY = '__type__';
27+
const PREVIOUS_VALUE_KEY = '__previous_value__';
28+
const LOCAL_WRITE_TIME_KEY = '__local_write_time__';
29+
30+
export function isServerTimestamp(value: api.Value | null): boolean {
31+
const type = (value?.mapValue?.fields || {})[TYPE_KEY]?.stringValue;
32+
return type === SERVER_TIMESTAMP_SENTINEL;
33+
}
34+
35+
/**
36+
* Creates a new ServerTimestamp proto value (using the internal format).
37+
*/
38+
export function serverTimestamp(
39+
localWriteTime: Timestamp,
40+
previousValue: api.Value | null
41+
): api.Value {
42+
const mapValue: api.MapValue = {
43+
fields: {
44+
[TYPE_KEY]: {
45+
stringValue: SERVER_TIMESTAMP_SENTINEL
46+
},
47+
[LOCAL_WRITE_TIME_KEY]: {
48+
timestampValue: {
49+
seconds: localWriteTime.seconds,
50+
nanos: localWriteTime.nanoseconds
51+
}
52+
}
53+
}
54+
};
55+
56+
if (previousValue) {
57+
mapValue.fields![PREVIOUS_VALUE_KEY] = previousValue;
58+
}
59+
60+
return { mapValue };
61+
}
62+
63+
/**
64+
* Returns the value of the field before this ServerTimestamp was set.
65+
*
66+
* Preserving the previous values allows the user to display the last resoled
67+
* value until the backend responds with the timestamp.
68+
*/
69+
70+
export function getPreviousValue(value: api.Value): api.Value | null {
71+
const previousValue = value.mapValue!.fields![PREVIOUS_VALUE_KEY];
72+
73+
if (isServerTimestamp(previousValue)) {
74+
return getPreviousValue(previousValue);
75+
}
76+
return previousValue;
77+
}
78+
79+
/**
80+
* Returns the local time at which this timestamp was first set.
81+
*/
82+
export function getLocalWriteTime(value: api.Value): Timestamp {
83+
const localWriteTime = normalizeTimestamp(
84+
value.mapValue!.fields![LOCAL_WRITE_TIME_KEY].timestampValue!
85+
);
86+
return new Timestamp(localWriteTime.seconds, localWriteTime.nanos);
87+
}

0 commit comments

Comments
 (0)