Skip to content

Commit d27c90b

Browse files
committed
refactor: Replace BSONBinaryData with Blob on iOS
1 parent 3f6b5c1 commit d27c90b

15 files changed

Lines changed: 275 additions & 184 deletions

File tree

FirebaseFirestoreInternal/FirebaseFirestore/FIRBSONBinaryData.h renamed to FirebaseFirestoreInternal/FirebaseFirestore/FIRBlob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#import <FirebaseFirestoreInternal/FIRBSONBinaryData.h>
15+
#import <FirebaseFirestoreInternal/FIRBlob.h>

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 9 additions & 19 deletions
Large diffs are not rendered by default.

Firestore/Example/Tests/API/FIRBsonTypesUnitTests.mm

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
#import <FirebaseFirestore/FIRBSONBinaryData.h>
1817
#import <FirebaseFirestore/FIRBSONObjectId.h>
1918
#import <FirebaseFirestore/FIRBSONTimestamp.h>
19+
#import <FirebaseFirestore/FIRBlob.h>
2020
#import <FirebaseFirestore/FIRDecimal128Value.h>
2121
#import <FirebaseFirestore/FIRFieldValue.h>
2222
#import <FirebaseFirestore/FIRInt32Value.h>
@@ -138,27 +138,54 @@ - (void)testCreateAndReadAndCompareBsonTimestamp {
138138
XCTAssertFalse([val1 isEqual:val4]);
139139
}
140140

141-
- (void)testCreateAndReadAndCompareBsonBinaryData {
141+
- (void)testCreateAndReadAndCompareBlob {
142142
uint8_t byteArray1[] = {0x01, 0x02, 0x03, 0x04, 0x05};
143143
uint8_t byteArray2[] = {0x01, 0x02, 0x03, 0x04, 0x99};
144144
NSData *data1 = [NSData dataWithBytes:byteArray1 length:sizeof(byteArray1)];
145145
NSData *data2 = [NSData dataWithBytes:byteArray1 length:sizeof(byteArray1)];
146146
NSData *data3 = [NSData dataWithBytes:byteArray2 length:sizeof(byteArray2)];
147147

148-
FIRBSONBinaryData *val1 = [[FIRBSONBinaryData alloc] initWithSubtype:128 data:data1];
149-
FIRBSONBinaryData *val2 = [[FIRBSONBinaryData alloc] initWithSubtype:128 data:data2];
150-
FIRBSONBinaryData *val3 = [[FIRBSONBinaryData alloc] initWithSubtype:128 data:data3];
151-
FIRBSONBinaryData *val4 = [[FIRBSONBinaryData alloc] initWithSubtype:1 data:data1];
148+
// Standard Blobs
149+
FIRBlob *std1 = [FIRBlob blobWithBytes:data1];
150+
FIRBlob *std2 = [FIRBlob blobWithBytes:data2];
151+
FIRBlob *std3 = [FIRBlob blobWithBytes:data3];
152152

153-
// Test reading the values back.
154-
XCTAssertEqual(128, val1.subtype);
155-
XCTAssertEqual(data1, val1.data);
156-
XCTAssertTrue([val1.data isEqualToData:data1]);
153+
// BSON Blobs
154+
FIRBlob *bson1 = [FIRBlob blobWithBSONBinary:data1 subtype:128];
155+
FIRBlob *bson2 = [FIRBlob blobWithBSONBinary:data2 subtype:128];
156+
FIRBlob *bson3 = [FIRBlob blobWithBSONBinary:data3 subtype:128];
157+
FIRBlob *bson4 = [FIRBlob blobWithBSONBinary:data1 subtype:1];
158+
159+
// Test reading properties back
160+
XCTAssertEqual(0, std1.subtype);
161+
XCTAssertFalse(std1.isBSON);
162+
XCTAssertEqual(data1, std1.bytes);
163+
164+
XCTAssertEqual(128, bson1.subtype);
165+
XCTAssertTrue(bson1.isBSON);
166+
XCTAssertEqual(data1, bson1.bytes);
157167

158168
// Test isEqual
159-
XCTAssertTrue([val1 isEqual:val2]);
160-
XCTAssertFalse([val1 isEqual:val3]);
161-
XCTAssertFalse([val1 isEqual:val4]);
169+
XCTAssertTrue([std1 isEqual:std2]);
170+
XCTAssertFalse([std1 isEqual:std3]);
171+
XCTAssertFalse([std1 isEqual:bson1]);
172+
173+
XCTAssertTrue([bson1 isEqual:bson2]);
174+
XCTAssertFalse([bson1 isEqual:bson3]);
175+
XCTAssertFalse([bson1 isEqual:bson4]);
176+
177+
// Test compare
178+
XCTAssertEqual(NSOrderedSame, [std1 compare:std2]);
179+
XCTAssertEqual(NSOrderedAscending, [std1 compare:std3]);
180+
XCTAssertEqual(NSOrderedDescending, [std3 compare:std1]);
181+
182+
XCTAssertEqual(NSOrderedSame, [bson1 compare:bson2]);
183+
XCTAssertEqual(NSOrderedAscending, [bson1 compare:bson3]);
184+
185+
// Standard blob (subtype 0) compares less than BSON blob (subtype 1)
186+
XCTAssertEqual(NSOrderedAscending, [std1 compare:bson4]);
187+
// BSON blob (subtype 1) compares less than BSON blob (subtype 128)
188+
XCTAssertEqual(NSOrderedAscending, [bson4 compare:bson1]);
162189
}
163190

164191
- (void)testFieldValueMinKey {
@@ -205,14 +232,14 @@ - (void)testFieldValueBsonTimestamp {
205232
XCTAssertEqual(100U, val2.increment);
206233
}
207234

208-
- (void)testFieldValueBsonBinaryData {
235+
- (void)testFieldValueBlob {
209236
uint8_t byteArray[] = {0x01, 0x02, 0x03, 0x04, 0x05};
210237
NSData *data = [NSData dataWithBytes:byteArray length:sizeof(byteArray)];
211-
FIRBSONBinaryData *val1 = [[FIRBSONBinaryData alloc] initWithSubtype:128 data:data];
212-
FIRBSONBinaryData *val2 = [[FIRBSONBinaryData alloc] initWithSubtype:128 data:data];
238+
FIRBlob *val1 = [FIRBlob blobWithBSONBinary:data subtype:128];
239+
FIRBlob *val2 = [FIRBlob blobWithBSONBinary:data subtype:128];
213240
XCTAssertTrue([val1 isEqual:val2]);
214241
XCTAssertEqual(128, val2.subtype);
215-
XCTAssertEqual(data, val2.data);
242+
XCTAssertEqual(data, val2.bytes);
216243
}
217244

218245
@end

Firestore/Source/API/FIRBSONBinaryData.m

Lines changed: 0 additions & 52 deletions
This file was deleted.

Firestore/Source/API/FIRBlob.m

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/Source/Public/FirebaseFirestore/FIRBlob.h"
18+
19+
@implementation FIRBlob
20+
21+
- (instancetype)initWithBytes:(NSData *)bytes subtype:(uint8_t)subtype isBSON:(BOOL)isBSON {
22+
self = [super init];
23+
if (self) {
24+
_subtype = subtype;
25+
_bytes = [bytes copy];
26+
_BSON = isBSON;
27+
}
28+
return self;
29+
}
30+
31+
+ (instancetype)blobWithBytes:(NSData *)bytes {
32+
return [[FIRBlob alloc] initWithBytes:bytes subtype:0 isBSON:NO];
33+
}
34+
35+
+ (instancetype)blobWithBSONBinary:(NSData *)bytes {
36+
return [[FIRBlob alloc] initWithBytes:bytes subtype:0 isBSON:YES];
37+
}
38+
39+
+ (instancetype)blobWithBSONBinary:(NSData *)bytes subtype:(uint8_t)subtype {
40+
return [[FIRBlob alloc] initWithBytes:bytes subtype:subtype isBSON:YES];
41+
}
42+
43+
- (BOOL)isEqual:(nullable id)object {
44+
if (self == object) {
45+
return YES;
46+
}
47+
48+
if (![object isKindOfClass:[FIRBlob class]]) {
49+
return NO;
50+
}
51+
52+
FIRBlob *other = (FIRBlob *)object;
53+
return self.subtype == other.subtype && [self.bytes isEqualToData:other.bytes];
54+
}
55+
56+
- (NSUInteger)hash {
57+
return [self.bytes hash] ^ self.subtype;
58+
}
59+
60+
- (id)copyWithZone:(__unused NSZone *_Nullable)zone {
61+
return [[FIRBlob alloc] initWithBytes:self.bytes subtype:self.subtype isBSON:self.isBSON];
62+
}
63+
64+
- (NSComparisonResult)compare:(FIRBlob *)other {
65+
if (self.subtype < other.subtype) {
66+
return NSOrderedAscending;
67+
} else if (self.subtype > other.subtype) {
68+
return NSOrderedDescending;
69+
}
70+
71+
NSUInteger selfLength = self.bytes.length;
72+
NSUInteger otherLength = other.bytes.length;
73+
NSUInteger minLength = MIN(selfLength, otherLength);
74+
int cmp = memcmp(self.bytes.bytes, other.bytes.bytes, minLength);
75+
if (cmp < 0) {
76+
return NSOrderedAscending;
77+
} else if (cmp > 0) {
78+
return NSOrderedDescending;
79+
}
80+
81+
if (selfLength < otherLength) {
82+
return NSOrderedAscending;
83+
} else if (selfLength > otherLength) {
84+
return NSOrderedDescending;
85+
}
86+
return NSOrderedSame;
87+
}
88+
89+
- (NSString *)description {
90+
return [NSString stringWithFormat:@"<FIRBlob: isBSON:%@, subtype:%u, bytes:%@>",
91+
self.isBSON ? @"YES" : @"NO", (unsigned int)self.subtype,
92+
self.bytes];
93+
}
94+
95+
@end

Firestore/Source/API/FSTUserDataReader.mm

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424

2525
#import "Firestore/Source/API/FSTUserDataReader.h"
2626

27-
#import "FIRBSONBinaryData.h"
2827
#import "FIRBSONObjectId.h"
2928
#import "FIRBSONTimestamp.h"
29+
#import "FIRBlob.h"
3030
#import "FIRDecimal128Value.h"
3131
#import "FIRGeoPoint.h"
3232
#import "FIRInt32Value.h"
@@ -515,26 +515,29 @@ - (ParsedUpdateData)parsedUpdateData:(id)input {
515515
return std::move(result);
516516
}
517517

518-
- (Message<google_firestore_v1_Value>)parseBsonBinaryData:(FIRBSONBinaryData *)binaryData
519-
context:(ParseContext &&)context {
520-
uint8_t subtypeByte = binaryData.subtype;
521-
NSData *data = binaryData.data;
518+
- (Message<google_firestore_v1_Value>)parseBlob:(FIRBlob *)blob context:(ParseContext &&)context {
519+
if (blob.isBSON) {
520+
uint8_t subtypeByte = blob.subtype;
521+
NSData *data = blob.bytes;
522522

523-
// We need to prepend the data with one byte representation of the subtype.
524-
NSMutableData *concatData = [NSMutableData data];
525-
[concatData appendBytes:&subtypeByte length:1];
526-
[concatData appendData:data];
523+
// We need to prepend the data with one byte representation of the subtype.
524+
NSMutableData *concatData = [NSMutableData data];
525+
[concatData appendBytes:&subtypeByte length:1];
526+
[concatData appendData:data];
527527

528-
__block Message<google_firestore_v1_Value> result;
529-
result->which_value_type = google_firestore_v1_Value_map_value_tag;
530-
result->map_value = {};
531-
result->map_value.fields_count = 1;
532-
result->map_value.fields = nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(1);
533-
result->map_value.fields[0].key = nanopb::CopyBytesArray(model::kBsonBinaryDataTypeFieldValue);
534-
result->map_value.fields[0].value =
535-
*[self encodeBlob:(nanopb::MakeByteString(concatData))].release();
528+
__block Message<google_firestore_v1_Value> result;
529+
result->which_value_type = google_firestore_v1_Value_map_value_tag;
530+
result->map_value = {};
531+
result->map_value.fields_count = 1;
532+
result->map_value.fields = nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(1);
533+
result->map_value.fields[0].key = nanopb::CopyBytesArray(model::kBsonBinaryDataTypeFieldValue);
534+
result->map_value.fields[0].value =
535+
*[self encodeBlob:(nanopb::MakeByteString(concatData))].release();
536536

537-
return std::move(result);
537+
return std::move(result);
538+
} else {
539+
return [self encodeBlob:(nanopb::MakeByteString(blob.bytes))];
540+
}
538541
}
539542

540543
- (Message<google_firestore_v1_Value>)parseArray:(NSArray<id> *)array
@@ -747,9 +750,9 @@ - (void)parseSentinelFieldValue:(FIRFieldValue *)fieldValue context:(ParseContex
747750
} else if ([input isKindOfClass:[FIRBSONTimestamp class]]) {
748751
FIRBSONTimestamp *timestamp = input;
749752
return [self parseBsonTimestamp:timestamp context:std::move(context)];
750-
} else if ([input isKindOfClass:[FIRBSONBinaryData class]]) {
751-
FIRBSONBinaryData *binaryData = input;
752-
return [self parseBsonBinaryData:binaryData context:std::move(context)];
753+
} else if ([input isKindOfClass:[FIRBlob class]]) {
754+
FIRBlob *blob = input;
755+
return [self parseBlob:blob context:std::move(context)];
753756
} else {
754757
ThrowInvalidArgument("Unsupported type: %s%s", NSStringFromClass([input class]),
755758
context.FieldDescription());

Firestore/Source/API/FSTUserDataWriter.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
#include "Firestore/Source/API/FIRDocumentReference+Internal.h"
2424
#include "Firestore/Source/API/FIRFieldValue+Internal.h"
2525
#include "Firestore/Source/API/converters.h"
26-
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONBinaryData.h"
2726
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONObjectId.h"
2827
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONTimestamp.h"
28+
#include "Firestore/Source/Public/FirebaseFirestore/FIRBlob.h"
2929
#include "Firestore/Source/Public/FirebaseFirestore/FIRDecimal128Value.h"
3030
#include "Firestore/Source/Public/FirebaseFirestore/FIRInt32Value.h"
3131
#include "Firestore/Source/Public/FirebaseFirestore/FIRMaxKey.h"
@@ -256,7 +256,7 @@ - (FIRBSONTimestamp *)convertedBsonTimestamp:(const google_firestore_v1_MapValue
256256
return [[FIRBSONTimestamp alloc] initWithSeconds:seconds increment:increment];
257257
}
258258

259-
- (FIRBSONBinaryData *)convertedBsonBinaryData:(const google_firestore_v1_MapValue &)mapValue {
259+
- (FIRBlob *)convertedBsonBinaryData:(const google_firestore_v1_MapValue &)mapValue {
260260
uint8_t subtype = 0;
261261
NSData *data = [[NSData alloc] init];
262262

@@ -275,7 +275,7 @@ - (FIRBSONBinaryData *)convertedBsonBinaryData:(const google_firestore_v1_MapVal
275275
}
276276
}
277277

278-
return [[FIRBSONBinaryData alloc] initWithSubtype:subtype data:data];
278+
return [FIRBlob blobWithBSONBinary:data subtype:subtype];
279279
}
280280

281281
- (NSArray<id> *)convertedArray:(const google_firestore_v1_ArrayValue &)arrayValue {

0 commit comments

Comments
 (0)