Skip to content

Commit 6d5290b

Browse files
committed
WIP: Decimal128Value.
1 parent 31a1bd8 commit 6d5290b

File tree

8 files changed

+180
-1
lines changed

8 files changed

+180
-1
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import <FirebaseFirestoreInternal/FIRDecimal128Value.h>

Firestore/Example/Tests/API/FIRBsonTypesUnitTests.mm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import <FirebaseFirestore/FIRBSONBinaryData.h>
1818
#import <FirebaseFirestore/FIRBSONObjectId.h>
1919
#import <FirebaseFirestore/FIRBSONTimestamp.h>
20+
#import <FirebaseFirestore/FIRDecimal128Value.h>
2021
#import <FirebaseFirestore/FIRFieldValue.h>
2122
#import <FirebaseFirestore/FIRInt32Value.h>
2223
#import <FirebaseFirestore/FIRMaxKey.h>
@@ -75,6 +76,24 @@ - (void)testCreateAndReadAndCompareInt32Value {
7576
XCTAssertFalse([val1 isEqual:val3]);
7677
}
7778

79+
- (void)testCreateAndReadAndCompareDecimal128Value {
80+
FIRDecimal128Value *val1 = [[FIRDecimal128Value alloc] initWithValue:@"1.2e3"];
81+
FIRDecimal128Value *val2 = [[FIRDecimal128Value alloc] initWithValue:@"12e2"];
82+
FIRDecimal128Value *val3 = [[FIRDecimal128Value alloc] initWithValue:@"0.12e4"];
83+
FIRDecimal128Value *val4 = [[FIRDecimal128Value alloc] initWithValue:@"12000e-1"];
84+
FIRDecimal128Value *val5 = [[FIRDecimal128Value alloc] initWithValue:@"1.2"];
85+
86+
// Test reading the value back
87+
XCTAssertEqual(@"1.2e3", val1.value);
88+
89+
// Test isEqual
90+
XCTAssertTrue([val1 isEqual:val2]);
91+
XCTAssertTrue([val1 isEqual:val3]);
92+
XCTAssertTrue([val1 isEqual:val4]);
93+
XCTAssertFalse([val1 isEqual:val5]);
94+
}
95+
96+
7897
- (void)testCreateAndReadAndCompareBsonObjectId {
7998
FIRBSONObjectId *val1 = [[FIRBSONObjectId alloc] initWithValue:@"abcd"];
8099
FIRBSONObjectId *val2 = [[FIRBSONObjectId alloc] initWithValue:@"abcd"];
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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/FIRDecimal128Value.h"
18+
19+
@implementation FIRDecimal128Value
20+
21+
- (instancetype)initWithValue:(NSString *)value {
22+
self = [super init];
23+
if (self) {
24+
_value = [value copy];
25+
}
26+
return self;
27+
}
28+
29+
- (BOOL)isEqual:(nullable id)object {
30+
if (self == object) {
31+
return YES;
32+
}
33+
34+
if (![object isKindOfClass:[FIRDecimal128Value class]]) {
35+
return NO;
36+
}
37+
38+
FIRDecimal128Value *other = (FIRDecimal128Value *)object;
39+
//
40+
// TODO(ehsann): Convert to Quadruple and compare quadruples.
41+
//
42+
return [self.value isEqualToString:other.value];
43+
}
44+
45+
- (id)copyWithZone:(__unused NSZone *_Nullable)zone {
46+
return [[FIRDecimal128Value alloc] initWithValue:self.value];
47+
}
48+
49+
- (NSString *)description {
50+
return [NSString stringWithFormat:@"<FIRDecimal128Value: (%@)>", self.value];
51+
}
52+
53+
@end

Firestore/Source/API/FSTUserDataReader.mm

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#import "FIRBSONBinaryData.h"
2828
#import "FIRBSONObjectId.h"
2929
#import "FIRBSONTimestamp.h"
30+
#import "FIRDecimal128Value.h"
3031
#import "FIRGeoPoint.h"
3132
#import "FIRInt32Value.h"
3233
#import "FIRMaxKey.h"
@@ -452,6 +453,19 @@ - (ParsedUpdateData)parsedUpdateData:(id)input {
452453
return std::move(result);
453454
}
454455

456+
- (Message<google_firestore_v1_Value>)parseDecimal128Value:(FIRDecimal128Value *)decimal128
457+
context:(ParseContext &&)context {
458+
__block Message<google_firestore_v1_Value> result;
459+
result->which_value_type = google_firestore_v1_Value_map_value_tag;
460+
result->map_value = {};
461+
result->map_value.fields_count = 1;
462+
result->map_value.fields = nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(1);
463+
result->map_value.fields[0].key = nanopb::CopyBytesArray(model::kDecimal128TypeFieldValue);
464+
result->map_value.fields[0].value = *[self encodeStringValue:MakeString(decimal128.value)].release();
465+
466+
return std::move(result);
467+
}
468+
455469
- (Message<google_firestore_v1_Value>)parseBsonObjectId:(FIRBSONObjectId *)oid
456470
context:(ParseContext &&)context {
457471
__block Message<google_firestore_v1_Value> result;
@@ -723,6 +737,9 @@ - (void)parseSentinelFieldValue:(FIRFieldValue *)fieldValue context:(ParseContex
723737
} else if ([input isKindOfClass:[FIRInt32Value class]]) {
724738
FIRInt32Value *value = input;
725739
return [self parseInt32Value:value context:std::move(context)];
740+
} else if ([input isKindOfClass:[FIRDecimal128Value class]]) {
741+
FIRDecimal128Value *value = input;
742+
return [self parseDecimal128Value:value context:std::move(context)];
726743
} else if ([input isKindOfClass:[FIRBSONObjectId class]]) {
727744
FIRBSONObjectId *oid = input;
728745
return [self parseBsonObjectId:oid context:std::move(context)];

Firestore/Source/API/FSTUserDataWriter.mm

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONBinaryData.h"
2727
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONObjectId.h"
2828
#include "Firestore/Source/Public/FirebaseFirestore/FIRBSONTimestamp.h"
29+
#include "Firestore/Source/Public/FirebaseFirestore/FIRDecimal128Value.h"
2930
#include "Firestore/Source/Public/FirebaseFirestore/FIRInt32Value.h"
3031
#include "Firestore/Source/Public/FirebaseFirestore/FIRMaxKey.h"
3132
#include "Firestore/Source/Public/FirebaseFirestore/FIRMinKey.h"
@@ -58,6 +59,8 @@
5859
using firebase::firestore::google_protobuf_Timestamp;
5960
using firebase::firestore::model::kRawBsonTimestampTypeIncrementFieldValue;
6061
using firebase::firestore::model::kRawBsonTimestampTypeSecondsFieldValue;
62+
using firebase::firestore::model::kRawInt32TypeFieldValue;
63+
using firebase::firestore::model::kRawDecimal128TypeFieldValue;
6164
using firebase::firestore::model::kRawRegexTypeOptionsFieldValue;
6265
using firebase::firestore::model::kRawRegexTypePatternFieldValue;
6366
using firebase::firestore::model::kRawVectorValueFieldKey;
@@ -109,7 +112,12 @@ - (id)convertedValue:(const google_firestore_v1_Value &)value {
109112
return value.boolean_value ? @YES : @NO;
110113
case TypeOrder::kNumber:
111114
if (value.which_value_type == google_firestore_v1_Value_map_value_tag) {
112-
return [self convertedInt32:value.map_value];
115+
absl::string_view key = MakeStringView(value.map_value.fields[0].key);
116+
if (0 == key.compare(absl::string_view(kRawInt32TypeFieldValue))) {
117+
return [self convertedInt32:value.map_value];
118+
} else if (0 == key.compare(absl::string_view(kRawDecimal128TypeFieldValue))) {
119+
return [self convertedDecimal128Value:value.map_value];
120+
}
113121
}
114122
return value.which_value_type == google_firestore_v1_Value_integer_value_tag
115123
? @(value.integer_value)
@@ -198,6 +206,18 @@ - (FIRInt32Value *)convertedInt32:(const google_firestore_v1_MapValue &)mapValue
198206
return [[FIRInt32Value alloc] initWithValue:value];
199207
}
200208

209+
- (FIRDecimal128Value *)convertedDecimal128Value:(const google_firestore_v1_MapValue &)mapValue {
210+
NSString *decimalString = @"";
211+
if (mapValue.fields_count == 1) {
212+
const google_firestore_v1_Value &decimalValue = mapValue.fields[0].value;
213+
if (decimalValue.which_value_type == google_firestore_v1_Value_string_value_tag) {
214+
decimalString = MakeNSString(MakeStringView(decimalValue.string_value));
215+
}
216+
}
217+
218+
return [[FIRDecimal128Value alloc] initWithValue:decimalString];
219+
}
220+
201221
- (FIRBSONObjectId *)convertedBsonObjectId:(const google_firestore_v1_MapValue &)mapValue {
202222
NSString *oid = @"";
203223
if (mapValue.fields_count == 1) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
#import <Foundation/Foundation.h>
18+
19+
NS_ASSUME_NONNULL_BEGIN
20+
21+
/**
22+
* Represents a 128-bit decimal number type in Firestore documents.
23+
*/
24+
NS_SWIFT_SENDABLE
25+
NS_SWIFT_NAME(Decimal128Value)
26+
__attribute__((objc_subclassing_restricted))
27+
@interface FIRDecimal128Value : NSObject<NSCopying>
28+
29+
/** The string representation of the 128-bit decimal value. */
30+
@property(nonatomic, copy, readonly) NSString *value;
31+
32+
/** :nodoc: */
33+
- (instancetype)init NS_UNAVAILABLE;
34+
35+
/**
36+
* Creates a `Decimal128Value` with the given value.
37+
* @param value The string representation of the number to be stored.
38+
*/
39+
- (instancetype)initWithValue:(NSString *)value NS_SWIFT_NAME(init(_:));
40+
41+
/** Returns true if the given object is equal to this, and false otherwise. */
42+
- (BOOL)isEqual:(nullable id)object;
43+
44+
@end
45+
46+
NS_ASSUME_NONNULL_END

Firestore/core/src/model/value_util.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ const char* kRawInt32TypeFieldValue = "__int__";
9696
pb_bytes_array_s* kInt32TypeFieldValue =
9797
nanopb::MakeBytesArray(kRawInt32TypeFieldValue);
9898

99+
/** The key of a decimal128 in a map proto. */
100+
const char* kRawDecimal128TypeFieldValue = "__decimal128__";
101+
pb_bytes_array_s* kDecimal128TypeFieldValue =
102+
nanopb::MakeBytesArray(kRawInt32TypeFieldValue);
103+
99104
/** The key of a BSON ObjectId in a map proto. */
100105
const char* kRawBsonObjectIdTypeFieldValue = "__oid__";
101106
pb_bytes_array_s* kBsonObjectIdTypeFieldValue =

Firestore/core/src/model/value_util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ extern pb_bytes_array_s* kRegexTypeOptionsFieldValue;
8181
extern const char* kRawInt32TypeFieldValue;
8282
extern pb_bytes_array_s* kInt32TypeFieldValue;
8383

84+
/** The key of a decimal128 in a map proto. */
85+
extern const char* kRawDecimal128TypeFieldValue;
86+
extern pb_bytes_array_s* kDecimal128TypeFieldValue;
87+
8488
/** The key of a BSON ObjectId in a map proto. */
8589
extern const char* kRawBsonObjectIdTypeFieldValue;
8690
extern pb_bytes_array_s* kBsonObjectIdTypeFieldValue;

0 commit comments

Comments
 (0)