@@ -31,9 +31,16 @@ import {
3131 MapRepresentation ,
3232 RESERVED_REGEX_PATTERN_KEY ,
3333 RESERVED_REGEX_OPTIONS_KEY ,
34- RESERVED_INT32_KEY
34+ RESERVED_INT32_KEY ,
35+ RESERVED_DECIMAL128_KEY
3536} from '../model/values' ;
36- import { ArrayValue , MapValue , Value } from '../protos/firestore_proto_api' ;
37+ import {
38+ ArrayValue ,
39+ MapValue ,
40+ Value ,
41+ Timestamp ,
42+ LatLng
43+ } from '../protos/firestore_proto_api' ;
3744import { fail } from '../util/assert' ;
3845import { isNegativeZero } from '../util/types' ;
3946
@@ -106,26 +113,10 @@ export class FirestoreIndexValueWriter {
106113 this . writeValueTypeLabel ( encoder , INDEX_TYPE_NUMBER ) ;
107114 encoder . writeNumber ( normalizeNumber ( indexValue . integerValue ) ) ;
108115 } else if ( 'doubleValue' in indexValue ) {
109- const n = normalizeNumber ( indexValue . doubleValue ) ;
110- if ( isNaN ( n ) ) {
111- this . writeValueTypeLabel ( encoder , INDEX_TYPE_NAN ) ;
112- } else {
113- this . writeValueTypeLabel ( encoder , INDEX_TYPE_NUMBER ) ;
114- if ( isNegativeZero ( n ) ) {
115- // -0.0, 0 and 0.0 are all considered the same
116- encoder . writeNumber ( 0.0 ) ;
117- } else {
118- encoder . writeNumber ( n ) ;
119- }
120- }
116+ const doubleValue = normalizeNumber ( indexValue . doubleValue ) ;
117+ this . writeIndexDouble ( doubleValue , encoder ) ;
121118 } else if ( 'timestampValue' in indexValue ) {
122- let timestamp = indexValue . timestampValue ! ;
123- this . writeValueTypeLabel ( encoder , INDEX_TYPE_TIMESTAMP ) ;
124- if ( typeof timestamp === 'string' ) {
125- timestamp = normalizeTimestamp ( timestamp ) ;
126- }
127- encoder . writeString ( `${ timestamp . seconds || '' } ` ) ;
128- encoder . writeNumber ( timestamp . nanos || 0 ) ;
119+ this . writeIndexTimestamp ( indexValue . timestampValue ! , encoder ) ;
129120 } else if ( 'stringValue' in indexValue ) {
130121 this . writeIndexString ( indexValue . stringValue ! , encoder ) ;
131122 this . writeTruncationMarker ( encoder ) ;
@@ -136,10 +127,7 @@ export class FirestoreIndexValueWriter {
136127 } else if ( 'referenceValue' in indexValue ) {
137128 this . writeIndexEntityRef ( indexValue . referenceValue ! , encoder ) ;
138129 } else if ( 'geoPointValue' in indexValue ) {
139- const geoPoint = indexValue . geoPointValue ! ;
140- this . writeValueTypeLabel ( encoder , INDEX_TYPE_GEOPOINT ) ;
141- encoder . writeNumber ( geoPoint . latitude || 0 ) ;
142- encoder . writeNumber ( geoPoint . longitude || 0 ) ;
130+ this . writeIndexGeoPoint ( indexValue . geoPointValue ! , encoder ) ;
143131 } else if ( 'mapValue' in indexValue ) {
144132 const type = detectMapRepresentation ( indexValue ) ;
145133 if ( type === MapRepresentation . INTERNAL_MAX ) {
@@ -159,12 +147,14 @@ export class FirestoreIndexValueWriter {
159147 } else if ( type === MapRepresentation . BSON_OBJECT_ID ) {
160148 this . writeIndexBsonObjectId ( indexValue . mapValue ! , encoder ) ;
161149 } else if ( type === MapRepresentation . INT32 ) {
162- this . writeValueTypeLabel ( encoder , INDEX_TYPE_NUMBER ) ;
163- encoder . writeNumber (
164- normalizeNumber (
165- indexValue . mapValue ! . fields ! [ RESERVED_INT32_KEY ] ! . integerValue !
166- )
150+ this . writeIndexInt32 ( indexValue . mapValue ! , encoder ) ;
151+ } else if ( type === MapRepresentation . DECIMAL128 ) {
152+ // Double and Decimal128 sort the same
153+ // Decimal128 is written as double with precision lost
154+ const parsedValue = parseFloat (
155+ indexValue . mapValue ! . fields ! [ RESERVED_DECIMAL128_KEY ] ! . stringValue !
167156 ) ;
157+ this . writeIndexDouble ( parsedValue , encoder ) ;
168158 } else {
169159 this . writeIndexMap ( indexValue . mapValue ! , encoder ) ;
170160 this . writeTruncationMarker ( encoder ) ;
@@ -192,6 +182,54 @@ export class FirestoreIndexValueWriter {
192182 encoder . writeString ( stringIndexValue ) ;
193183 }
194184
185+ private writeIndexDouble (
186+ double : number ,
187+ encoder : DirectionalIndexByteEncoder
188+ ) : void {
189+ if ( isNaN ( double ) ) {
190+ this . writeValueTypeLabel ( encoder , INDEX_TYPE_NAN ) ;
191+ } else {
192+ this . writeValueTypeLabel ( encoder , INDEX_TYPE_NUMBER ) ;
193+ if ( isNegativeZero ( double ) ) {
194+ // -0.0, 0 and 0.0 are all considered the same
195+ encoder . writeNumber ( 0.0 ) ;
196+ } else {
197+ encoder . writeNumber ( double ) ;
198+ }
199+ }
200+ }
201+
202+ private writeIndexInt32 (
203+ mapValue : MapValue ,
204+ encoder : DirectionalIndexByteEncoder
205+ ) : void {
206+ this . writeValueTypeLabel ( encoder , INDEX_TYPE_NUMBER ) ;
207+ encoder . writeNumber (
208+ normalizeNumber ( mapValue . fields ! [ RESERVED_INT32_KEY ] ! . integerValue ! )
209+ ) ;
210+ }
211+
212+ private writeIndexTimestamp (
213+ timestamp : Timestamp ,
214+ encoder : DirectionalIndexByteEncoder
215+ ) : void {
216+ this . writeValueTypeLabel ( encoder , INDEX_TYPE_TIMESTAMP ) ;
217+ if ( typeof timestamp === 'string' ) {
218+ timestamp = normalizeTimestamp ( timestamp ) ;
219+ }
220+ encoder . writeString ( `${ timestamp . seconds || '' } ` ) ;
221+ encoder . writeNumber ( timestamp . nanos || 0 ) ;
222+ }
223+
224+ private writeIndexGeoPoint (
225+ geoPoint : LatLng ,
226+ encoder : DirectionalIndexByteEncoder
227+ ) : void {
228+ this . writeValueTypeLabel ( encoder , INDEX_TYPE_GEOPOINT ) ;
229+ encoder . writeNumber ( geoPoint . latitude || 0 ) ;
230+ encoder . writeNumber ( geoPoint . longitude || 0 ) ;
231+ }
232+
195233 private writeIndexMap (
196234 mapIndexValue : MapValue ,
197235 encoder : DirectionalIndexByteEncoder
0 commit comments