Skip to content

Commit 865e289

Browse files
authored
Fix an issue around deleting records from the database. (#3926)
* Assign weakself to self. * Add unit test. * Style fixes. * Address review comments. * Review comments.
1 parent c295991 commit 865e289

File tree

2 files changed

+106
-8
lines changed

2 files changed

+106
-8
lines changed

FirebaseRemoteConfig/Sources/RCNConfigDBManager.m

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,12 @@ - (NSMutableDictionary *)loadMainTableWithBundleIdentifier:(NSString *)bundleIde
899899
- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
900900
bundleIdentifier:(NSString *)bundleIdentifier
901901
fromSource:(RCNDBSource)source {
902-
__weak RCNConfigDBManager *weakSelf;
902+
__weak RCNConfigDBManager *weakSelf = self;
903903
dispatch_async(_databaseOperationQueue, ^{
904+
RCNConfigDBManager *strongSelf = weakSelf;
905+
if (!strongSelf) {
906+
return;
907+
}
904908
NSArray *params = @[ bundleIdentifier, namespace_p ];
905909
const char *SQL =
906910
"DELETE FROM " RCNTableNameMain " WHERE bundle_identifier = ? and namespace = ?";
@@ -909,42 +913,54 @@ - (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
909913
} else if (source == RCNDBSourceActive) {
910914
SQL = "DELETE FROM " RCNTableNameMainActive " WHERE bundle_identifier = ? and namespace = ?";
911915
}
912-
[weakSelf executeQuery:SQL withParams:params];
916+
[strongSelf executeQuery:SQL withParams:params];
913917
});
914918
}
915919

916920
- (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier
917921
isInternalDB:(BOOL)isInternalDB {
918-
__weak RCNConfigDBManager *weakSelf;
922+
__weak RCNConfigDBManager *weakSelf = self;
919923
dispatch_async(_databaseOperationQueue, ^{
924+
RCNConfigDBManager *strongSelf = weakSelf;
925+
if (!strongSelf) {
926+
return;
927+
}
920928
const char *SQL = "DELETE FROM " RCNTableNameInternalMetadata " WHERE key LIKE ?";
921929
if (!isInternalDB) {
922930
SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ?";
923931
}
924932
NSArray *params = @[ bundleIdentifier ];
925-
[weakSelf executeQuery:SQL withParams:params];
933+
[strongSelf executeQuery:SQL withParams:params];
926934
});
927935
}
928936

929937
- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source {
930-
__weak RCNConfigDBManager *weakSelf;
938+
__weak RCNConfigDBManager *weakSelf = self;
931939
dispatch_async(_databaseOperationQueue, ^{
940+
RCNConfigDBManager *strongSelf = weakSelf;
941+
if (!strongSelf) {
942+
return;
943+
}
932944
const char *SQL = "DELETE FROM " RCNTableNameMain;
933945
if (source == RCNDBSourceDefault) {
934946
SQL = "DELETE FROM " RCNTableNameMainDefault;
935947
} else if (source == RCNDBSourceActive) {
936948
SQL = "DELETE FROM " RCNTableNameMainActive;
937949
}
938-
[weakSelf executeQuery:SQL];
950+
[strongSelf executeQuery:SQL];
939951
});
940952
}
941953

942954
- (void)deleteExperimentTableForKey:(NSString *)key {
943-
__weak RCNConfigDBManager *weakSelf;
955+
__weak RCNConfigDBManager *weakSelf = self;
944956
dispatch_async(_databaseOperationQueue, ^{
957+
RCNConfigDBManager *strongSelf = weakSelf;
958+
if (!strongSelf) {
959+
return;
960+
}
945961
NSArray *params = @[ key ];
946962
const char *SQL = "DELETE FROM " RCNTableNameExperiment " WHERE key = ?";
947-
[weakSelf executeQuery:SQL withParams:params];
963+
[strongSelf executeQuery:SQL withParams:params];
948964
});
949965
}
950966

FirebaseRemoteConfig/Tests/Unit/RCNConfigDBManagerTest.m

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,88 @@ - (void)testWriteAndLoadMetadataResult {
258258
}];
259259
}
260260

261+
// Create a key each for two namespaces, delete it from one namespace, read both namespaces.
262+
- (void)testDeleteParamAndLoadMainTable {
263+
XCTestExpectation *namespaceDeleteExpectation =
264+
[self expectationWithDescription:@"Contents of 'namespace_delete' should be deleted."];
265+
XCTestExpectation *namespaceKeepExpectation =
266+
[self expectationWithDescription:@"Write a key to namespace_keep and read back again."];
267+
NSString *namespaceToDelete = @"namespace_delete";
268+
NSString *namespaceToKeep = @"namespace_keep";
269+
NSString *bundleIdentifier = @"testBundleID";
270+
271+
// Write something to the database for both namespaces.
272+
// Completion handler for the write to namespace_delete namespace.
273+
RCNDBCompletion insertNamespace1Completion = ^void(BOOL success, NSDictionary *result) {
274+
XCTAssertTrue(success);
275+
276+
// Delete the key for given namespace.
277+
[_DBManager deleteRecordFromMainTableWithNamespace:namespaceToDelete
278+
bundleIdentifier:bundleIdentifier
279+
fromSource:RCNDBSourceActive];
280+
281+
// Read from the database and verify expected values.
282+
[_DBManager
283+
loadMainWithBundleIdentifier:bundleIdentifier
284+
completionHandler:^(BOOL success, NSDictionary *fetchedConfig,
285+
NSDictionary *activeConfig, NSDictionary *defaultConfig) {
286+
NSMutableDictionary *res = [activeConfig mutableCopy];
287+
XCTAssertTrue(success);
288+
FIRRemoteConfigValue *value = res[namespaceToDelete][@"keyToDelete"];
289+
XCTAssertNil(value);
290+
291+
FIRRemoteConfigValue *value2 = res[namespaceToKeep][@"keyToRetain"];
292+
XCTAssertTrue([value2.stringValue isEqualToString:@"valueToRetain"]);
293+
294+
[namespaceDeleteExpectation fulfill];
295+
}];
296+
};
297+
298+
// Insert a key into the second namespace.
299+
RCNDBCompletion insertNamespace2Completion = ^void(BOOL success, NSDictionary *result) {
300+
XCTAssertTrue(success);
301+
302+
// Ensure DB read succeeds.
303+
[_DBManager
304+
loadMainWithBundleIdentifier:bundleIdentifier
305+
completionHandler:^(BOOL success, NSDictionary *fetchedConfig,
306+
NSDictionary *activeConfig, NSDictionary *defaultConfig) {
307+
NSMutableDictionary *res = [activeConfig mutableCopy];
308+
XCTAssertTrue(success);
309+
FIRRemoteConfigValue *value2 = res[namespaceToKeep][@"keyToRetain"];
310+
XCTAssertTrue([value2.stringValue isEqualToString:@"valueToRetain"]);
311+
312+
[namespaceKeepExpectation fulfill];
313+
}];
314+
};
315+
// We will delete this key after storing in the database.
316+
NSString *valueToDelete = @"valueToDelete";
317+
NSString *keyToDelete = @"keyToDelete";
318+
NSArray *items = @[
319+
bundleIdentifier, namespaceToDelete, keyToDelete,
320+
[valueToDelete dataUsingEncoding:NSUTF8StringEncoding]
321+
];
322+
[_DBManager insertMainTableWithValues:items
323+
fromSource:RCNDBSourceActive
324+
completionHandler:insertNamespace1Completion];
325+
326+
// This key value will be retained.
327+
NSString *valueToRetain = @"valueToRetain";
328+
NSString *keyToRetain = @"keyToRetain";
329+
NSArray *items2 = @[
330+
bundleIdentifier, namespaceToKeep, keyToRetain,
331+
[valueToRetain dataUsingEncoding:NSUTF8StringEncoding]
332+
];
333+
[_DBManager insertMainTableWithValues:items2
334+
fromSource:RCNDBSourceActive
335+
completionHandler:insertNamespace2Completion];
336+
337+
[self waitForExpectationsWithTimeout:_expectionTimeout
338+
handler:^(NSError *error) {
339+
XCTAssertNil(error);
340+
}];
341+
}
342+
261343
- (void)testWriteAndLoadExperiments {
262344
XCTestExpectation *updateAndLoadExperimentExpectation =
263345
[self expectationWithDescription:@"Update and load experiment in database successfully"];

0 commit comments

Comments
 (0)