@@ -160,7 +160,7 @@ export const MIN_BSON_BINARY_VALUE: Value = {
160160 }
161161} ;
162162
163- export enum SpecialMapValueType {
163+ export enum MapRepresentation {
164164 REGEX = 'regexValue' ,
165165 BSON_OBJECT_ID = 'bsonObjectIdValue' ,
166166 INT32 = 'int32Value' ,
@@ -195,27 +195,27 @@ export function typeOrder(value: Value): TypeOrder {
195195 } else if ( 'arrayValue' in value ) {
196196 return TypeOrder . ArrayValue ;
197197 } else if ( 'mapValue' in value ) {
198- const valueType = detectSpecialMapType ( value ) ;
198+ const valueType = detectMapRepresentation ( value ) ;
199199 switch ( valueType ) {
200- case SpecialMapValueType . SERVER_TIMESTAMP :
200+ case MapRepresentation . SERVER_TIMESTAMP :
201201 return TypeOrder . ServerTimestampValue ;
202- case SpecialMapValueType . INTERNAL_MAX :
202+ case MapRepresentation . INTERNAL_MAX :
203203 return TypeOrder . MaxValue ;
204- case SpecialMapValueType . VECTOR :
204+ case MapRepresentation . VECTOR :
205205 return TypeOrder . VectorValue ;
206- case SpecialMapValueType . REGEX :
206+ case MapRepresentation . REGEX :
207207 return TypeOrder . RegexValue ;
208- case SpecialMapValueType . BSON_OBJECT_ID :
208+ case MapRepresentation . BSON_OBJECT_ID :
209209 return TypeOrder . BsonObjectIdValue ;
210- case SpecialMapValueType . INT32 :
210+ case MapRepresentation . INT32 :
211211 return TypeOrder . NumberValue ;
212- case SpecialMapValueType . BSON_TIMESTAMP :
212+ case MapRepresentation . BSON_TIMESTAMP :
213213 return TypeOrder . BsonTimestampValue ;
214- case SpecialMapValueType . BSON_BINARY :
214+ case MapRepresentation . BSON_BINARY :
215215 return TypeOrder . BsonBinaryValue ;
216- case SpecialMapValueType . MIN_KEY :
216+ case MapRepresentation . MIN_KEY :
217217 return TypeOrder . MinKeyValue ;
218- case SpecialMapValueType . MAX_KEY :
218+ case MapRepresentation . MAX_KEY :
219219 return TypeOrder . MaxKeyValue ;
220220 default :
221221 return TypeOrder . ObjectValue ;
@@ -319,8 +319,8 @@ function blobEquals(left: Value, right: Value): boolean {
319319export function numberEquals ( left : Value , right : Value ) : boolean {
320320 if (
321321 ( 'integerValue' in left && 'integerValue' in right ) ||
322- ( detectSpecialMapType ( left ) === SpecialMapValueType . INT32 &&
323- detectSpecialMapType ( right ) === SpecialMapValueType . INT32 )
322+ ( detectMapRepresentation ( left ) === MapRepresentation . INT32 &&
323+ detectMapRepresentation ( right ) === MapRepresentation . INT32 )
324324 ) {
325325 return extractNumber ( left ) === extractNumber ( right ) ;
326326 } else if ( 'doubleValue' in left && 'doubleValue' in right ) {
@@ -427,7 +427,7 @@ export function valueCompare(left: Value, right: Value): number {
427427
428428export function extractNumber ( value : Value ) : number {
429429 let numberValue ;
430- if ( detectSpecialMapType ( value ) === SpecialMapValueType . INT32 ) {
430+ if ( detectMapRepresentation ( value ) === MapRepresentation . INT32 ) {
431431 numberValue = value . mapValue ! . fields ! [ RESERVED_INT32_KEY ] . integerValue ! ;
432432 } else {
433433 numberValue = value . integerValue || value . doubleValue ;
@@ -686,10 +686,6 @@ function canonifyValue(value: Value): string {
686686 } else if ( 'arrayValue' in value ) {
687687 return canonifyArray ( value . arrayValue ! ) ;
688688 } else if ( 'mapValue' in value ) {
689- // BsonBinaryValue contains an array of bytes, and needs to extract `subtype` and `data` from it before canonifying.
690- if ( detectSpecialMapType ( value ) === SpecialMapValueType . BSON_BINARY ) {
691- return canonifyBsonBinaryData ( value . mapValue ! ) ;
692- }
693689 return canonifyMap ( value . mapValue ! ) ;
694690 } else {
695691 return fail ( 'Invalid value type: ' + JSON . stringify ( value ) ) ;
@@ -713,19 +709,6 @@ function canonifyReference(referenceValue: string): string {
713709 return DocumentKey . fromName ( referenceValue ) . toString ( ) ;
714710}
715711
716- function canonifyBsonBinaryData ( mapValue : MapValue ) : string {
717- const fields = mapValue ! . fields ?. [ RESERVED_BSON_BINARY_KEY ] ;
718- const subtypeAndData = fields ?. bytesValue ;
719- if ( ! subtypeAndData ) {
720- throw new Error ( 'Received incorrect bytesValue for BsonBinaryData' ) ;
721- }
722- // Normalize the bytesValue to Uint8Array before extracting subtype and data.
723- const bytes = normalizeByteString ( subtypeAndData ) . toUint8Array ( ) ;
724- return `{__binary__:{subType:${ bytes . at ( 0 ) } ,data:${ canonifyByteString (
725- bytes . slice ( 1 )
726- ) } }}`;
727- }
728-
729712function canonifyMap ( mapValue : MapValue ) : string {
730713 // Iteration order in JavaScript is not guaranteed. To ensure that we generate
731714 // matching canonical IDs for identical maps, we need to sort the keys.
@@ -886,35 +869,41 @@ export function isMapValue(
886869 return ! ! value && 'mapValue' in value ;
887870}
888871
889- export function detectSpecialMapType ( value : Value ) : SpecialMapValueType {
872+ export function detectMapRepresentation ( value : Value ) : MapRepresentation {
890873 if ( ! value || ! value . mapValue || ! value . mapValue . fields ) {
891- return SpecialMapValueType . REGULAR_MAP ; // Not a special map type
874+ return MapRepresentation . REGULAR_MAP ; // Not a special map type
892875 }
893876
894877 const fields = value . mapValue . fields ;
895878
896879 // Check for type-based mappings
897880 const type = fields [ TYPE_KEY ] ?. stringValue ;
898881 if ( type ) {
899- const typeMap : Record < string , SpecialMapValueType > = {
900- [ RESERVED_VECTOR_KEY ] : SpecialMapValueType . VECTOR ,
901- [ RESERVED_MAX_KEY ] : SpecialMapValueType . INTERNAL_MAX ,
902- [ RESERVED_SERVER_TIMESTAMP_KEY ] : SpecialMapValueType . SERVER_TIMESTAMP
882+ const typeMap : Record < string , MapRepresentation > = {
883+ [ RESERVED_VECTOR_KEY ] : MapRepresentation . VECTOR ,
884+ [ RESERVED_MAX_KEY ] : MapRepresentation . INTERNAL_MAX ,
885+ [ RESERVED_SERVER_TIMESTAMP_KEY ] : MapRepresentation . SERVER_TIMESTAMP
903886 } ;
904887 if ( typeMap [ type ] ) {
905888 return typeMap [ type ] ;
906889 }
907890 }
908891
892+ if ( objectSize ( fields ) !== 1 ) {
893+ // All BSON types have 1 key in the map. To improve performance, we can
894+ // return early if the number of keys in the map is not 1.
895+ return MapRepresentation . REGULAR_MAP ;
896+ }
897+
909898 // Check for BSON-related mappings
910- const bsonMap : Record < string , SpecialMapValueType > = {
911- [ RESERVED_REGEX_KEY ] : SpecialMapValueType . REGEX ,
912- [ RESERVED_BSON_OBJECT_ID_KEY ] : SpecialMapValueType . BSON_OBJECT_ID ,
913- [ RESERVED_INT32_KEY ] : SpecialMapValueType . INT32 ,
914- [ RESERVED_BSON_TIMESTAMP_KEY ] : SpecialMapValueType . BSON_TIMESTAMP ,
915- [ RESERVED_BSON_BINARY_KEY ] : SpecialMapValueType . BSON_BINARY ,
916- [ RESERVED_MIN_KEY ] : SpecialMapValueType . MIN_KEY ,
917- [ RESERVED_MAX_KEY ] : SpecialMapValueType . MAX_KEY
899+ const bsonMap : Record < string , MapRepresentation > = {
900+ [ RESERVED_REGEX_KEY ] : MapRepresentation . REGEX ,
901+ [ RESERVED_BSON_OBJECT_ID_KEY ] : MapRepresentation . BSON_OBJECT_ID ,
902+ [ RESERVED_INT32_KEY ] : MapRepresentation . INT32 ,
903+ [ RESERVED_BSON_TIMESTAMP_KEY ] : MapRepresentation . BSON_TIMESTAMP ,
904+ [ RESERVED_BSON_BINARY_KEY ] : MapRepresentation . BSON_BINARY ,
905+ [ RESERVED_MIN_KEY ] : MapRepresentation . MIN_KEY ,
906+ [ RESERVED_MAX_KEY ] : MapRepresentation . MAX_KEY
918907 } ;
919908
920909 for ( const key in bsonMap ) {
@@ -923,20 +912,20 @@ export function detectSpecialMapType(value: Value): SpecialMapValueType {
923912 }
924913 }
925914
926- return SpecialMapValueType . REGULAR_MAP ;
915+ return MapRepresentation . REGULAR_MAP ;
927916}
928917
929918export function isBsonType ( value : Value ) : boolean {
930919 const bsonTypes = new Set ( [
931- SpecialMapValueType . REGEX ,
932- SpecialMapValueType . BSON_OBJECT_ID ,
933- SpecialMapValueType . INT32 ,
934- SpecialMapValueType . BSON_TIMESTAMP ,
935- SpecialMapValueType . BSON_BINARY ,
936- SpecialMapValueType . MIN_KEY ,
937- SpecialMapValueType . MAX_KEY
920+ MapRepresentation . REGEX ,
921+ MapRepresentation . BSON_OBJECT_ID ,
922+ MapRepresentation . INT32 ,
923+ MapRepresentation . BSON_TIMESTAMP ,
924+ MapRepresentation . BSON_BINARY ,
925+ MapRepresentation . MIN_KEY ,
926+ MapRepresentation . MAX_KEY
938927 ] ) ;
939- return bsonTypes . has ( detectSpecialMapType ( value ) ) ;
928+ return bsonTypes . has ( detectMapRepresentation ( value ) ) ;
940929}
941930
942931/** Creates a deep copy of `source`. */
@@ -987,23 +976,23 @@ export function valuesGetLowerBound(value: Value): Value {
987976 } else if ( 'arrayValue' in value ) {
988977 return { arrayValue : { } } ;
989978 } else if ( 'mapValue' in value ) {
990- const type = detectSpecialMapType ( value ) ;
991- if ( type === SpecialMapValueType . VECTOR ) {
979+ const type = detectMapRepresentation ( value ) ;
980+ if ( type === MapRepresentation . VECTOR ) {
992981 return MIN_VECTOR_VALUE ;
993- } else if ( type === SpecialMapValueType . BSON_OBJECT_ID ) {
982+ } else if ( type === MapRepresentation . BSON_OBJECT_ID ) {
994983 return MIN_BSON_OBJECT_ID_VALUE ;
995- } else if ( type === SpecialMapValueType . BSON_TIMESTAMP ) {
984+ } else if ( type === MapRepresentation . BSON_TIMESTAMP ) {
996985 return MIN_BSON_TIMESTAMP_VALUE ;
997- } else if ( type === SpecialMapValueType . BSON_BINARY ) {
986+ } else if ( type === MapRepresentation . BSON_BINARY ) {
998987 return MIN_BSON_BINARY_VALUE ;
999- } else if ( type === SpecialMapValueType . REGEX ) {
988+ } else if ( type === MapRepresentation . REGEX ) {
1000989 return MIN_REGEX_VALUE ;
1001- } else if ( type === SpecialMapValueType . INT32 ) {
990+ } else if ( type === MapRepresentation . INT32 ) {
1002991 // int32Value is treated the same as integerValue and doubleValue
1003992 return { doubleValue : NaN } ;
1004- } else if ( type === SpecialMapValueType . MIN_KEY ) {
993+ } else if ( type === MapRepresentation . MIN_KEY ) {
1005994 return MIN_KEY_VALUE ;
1006- } else if ( type === SpecialMapValueType . MAX_KEY ) {
995+ } else if ( type === MapRepresentation . MAX_KEY ) {
1007996 return MAX_KEY_VALUE ;
1008997 }
1009998 return { mapValue : { } } ;
@@ -1033,23 +1022,23 @@ export function valuesGetUpperBound(value: Value): Value {
10331022 } else if ( 'arrayValue' in value ) {
10341023 return MIN_VECTOR_VALUE ;
10351024 } else if ( 'mapValue' in value ) {
1036- const type = detectSpecialMapType ( value ) ;
1037- if ( type === SpecialMapValueType . VECTOR ) {
1025+ const type = detectMapRepresentation ( value ) ;
1026+ if ( type === MapRepresentation . VECTOR ) {
10381027 return { mapValue : { } } ;
1039- } else if ( type === SpecialMapValueType . BSON_OBJECT_ID ) {
1028+ } else if ( type === MapRepresentation . BSON_OBJECT_ID ) {
10401029 return { geoPointValue : { latitude : - 90 , longitude : - 180 } } ;
1041- } else if ( type === SpecialMapValueType . BSON_TIMESTAMP ) {
1030+ } else if ( type === MapRepresentation . BSON_TIMESTAMP ) {
10421031 return { stringValue : '' } ;
1043- } else if ( type === SpecialMapValueType . BSON_BINARY ) {
1032+ } else if ( type === MapRepresentation . BSON_BINARY ) {
10441033 return refValue ( DatabaseId . empty ( ) , DocumentKey . empty ( ) ) ;
1045- } else if ( type === SpecialMapValueType . REGEX ) {
1034+ } else if ( type === MapRepresentation . REGEX ) {
10461035 return { arrayValue : { } } ;
1047- } else if ( type === SpecialMapValueType . INT32 ) {
1036+ } else if ( type === MapRepresentation . INT32 ) {
10481037 // int32Value is treated the same as integerValue and doubleValue
10491038 return { timestampValue : { seconds : Number . MIN_SAFE_INTEGER } } ;
1050- } else if ( type === SpecialMapValueType . MIN_KEY ) {
1039+ } else if ( type === MapRepresentation . MIN_KEY ) {
10511040 return { booleanValue : false } ;
1052- } else if ( type === SpecialMapValueType . MAX_KEY ) {
1041+ } else if ( type === MapRepresentation . MAX_KEY ) {
10531042 return INTERNAL_MAX_VALUE ;
10541043 }
10551044 return MAX_KEY_VALUE ;
0 commit comments