@@ -61,6 +61,34 @@ static id RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut
6161 return nil ;
6262}
6363
64+ // Only merges objects - all other types are just clobbered (including arrays)
65+ static void RCTMergeRecursive (NSMutableDictionary *destination, NSDictionary *source)
66+ {
67+ for (NSString *key in source) {
68+ id sourceValue = source[key];
69+ if ([sourceValue isKindOfClass: [NSDictionary class ]]) {
70+ id destinationValue = destination[key];
71+ NSMutableDictionary *nestedDestination;
72+ if ([destinationValue classForCoder ] == [NSMutableDictionary class ]) {
73+ nestedDestination = destinationValue;
74+ } else {
75+ if ([destinationValue isKindOfClass: [NSDictionary class ]]) {
76+ // Ideally we wouldn't eagerly copy here...
77+ nestedDestination = [destinationValue mutableCopy ];
78+ } else {
79+ destination[key] = [sourceValue copy ];
80+ }
81+ }
82+ if (nestedDestination) {
83+ RCTMergeRecursive (nestedDestination, sourceValue);
84+ destination[key] = nestedDestination;
85+ }
86+ } else {
87+ destination[key] = sourceValue;
88+ }
89+ }
90+ }
91+
6492#pragma mark - RCTAsyncLocalStorage
6593
6694@implementation RCTAsyncLocalStorage
@@ -135,13 +163,19 @@ - (id)_appendItemForKey:(NSString *)key toArray:(NSMutableArray *)result
135163 if (errorOut) {
136164 return errorOut;
137165 }
166+ id value = [self _getValueForKey: key errorOut: &errorOut];
167+ [result addObject: @[key, value ?: [NSNull null ]]]; // Insert null if missing or failure.
168+ return errorOut;
169+ }
170+
171+ - (NSString *)_getValueForKey : (NSString *)key errorOut : (NSDictionary **)errorOut
172+ {
138173 id value = _manifest[key]; // nil means missing, null means there is a data file, anything else is an inline value.
139174 if (value == [NSNull null ]) {
140175 NSString *filePath = [self _filePathForKey: key];
141- value = RCTReadFile (filePath, key, & errorOut);
176+ value = RCTReadFile (filePath, key, errorOut);
142177 }
143- [result addObject: @[key, value ?: [NSNull null ]]]; // Insert null if missing or failure.
144- return errorOut;
178+ return value;
145179}
146180
147181- (id )_writeEntry : (NSArray *)entry
@@ -198,7 +232,6 @@ - (id)_writeEntry:(NSArray *)entry
198232 id keyError = [self _appendItemForKey: key toArray: result];
199233 RCTAppendError (keyError, &errors);
200234 }
201- [self _writeManifest: &errors];
202235 callback (@[errors ?: [NSNull null ], result]);
203236}
204237
@@ -221,6 +254,38 @@ - (id)_writeEntry:(NSArray *)entry
221254 }
222255}
223256
257+ RCT_EXPORT_METHOD (multiMerge:(NSArray *)kvPairs
258+ callback:(RCTResponseSenderBlock)callback)
259+ {
260+ id errorOut = [self _ensureSetup ];
261+ if (errorOut) {
262+ callback (@[@[errorOut]]);
263+ return ;
264+ }
265+ NSMutableArray *errors;
266+ for (__strong NSArray *entry in kvPairs) {
267+ id keyError;
268+ NSString *value = [self _getValueForKey: entry[0 ] errorOut: &keyError];
269+ if (keyError) {
270+ RCTAppendError (keyError, &errors);
271+ } else {
272+ if (value) {
273+ NSMutableDictionary *mergedVal = [RCTJSONParseMutable (value, &keyError) mutableCopy ];
274+ RCTMergeRecursive (mergedVal, RCTJSONParse (entry[1 ], &keyError));
275+ entry = @[entry[0 ], RCTJSONStringify (mergedVal, &keyError)];
276+ }
277+ if (!keyError) {
278+ keyError = [self _writeEntry: entry];
279+ }
280+ RCTAppendError (keyError, &errors);
281+ }
282+ }
283+ [self _writeManifest: &errors];
284+ if (callback) {
285+ callback (@[errors ?: [NSNull null ]]);
286+ }
287+ }
288+
224289RCT_EXPORT_METHOD (multiRemove:(NSArray *)keys
225290 callback:(RCTResponseSenderBlock)callback)
226291{
0 commit comments