diff --git a/Parse/Parse/PFObject.m b/Parse/Parse/PFObject.m index 657207dd4..6dbf2ee0a 100644 --- a/Parse/Parse/PFObject.m +++ b/Parse/Parse/PFObject.m @@ -13,6 +13,8 @@ #import "PFObject+Deprecated.h" #import "PFObjectSubclassingController.h" +#import + #import #import #import @@ -1460,6 +1462,11 @@ - (BFTask *)saveAsync:(BFTask *)toAwait { if (![self isDirty:YES]) { return @YES; } + + if([Parse isAllowCustomObjectIds]){ + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId message:@"ObjectId must not be null"]; + return [BFTask taskWithError:error]; + } [self _objectWillSave]; @@ -1532,18 +1539,31 @@ - (nullable PFRESTCommand *)_constructSaveCommandForChanges:(PFOperationSet *)ch NSDictionary *parameters = [self _convertToDictionaryForSaving:changes withObjectEncoder:encoder error:error]; PFPreconditionBailOnError(parameters, error, nil); - if (self._state.objectId) { - return [PFRESTObjectCommand updateObjectCommandForObjectState:self._state + if(!self._state.objectId){ + return [PFRESTObjectCommand createObjectCommandForObjectState:self._state changes:parameters operationSetUUID:changes.uuid - sessionToken:sessionToken]; + sessionToken:sessionToken]; + }else{ + if([Parse isAllowCustomObjectIds]){ + if(self._state.createdAt == nil){ + return [PFRESTObjectCommand createObjectCommandForObjectState:self._state + changes:parameters + operationSetUUID:changes.uuid + sessionToken:sessionToken]; + }else{ + return [PFRESTObjectCommand updateObjectCommandForObjectState:self._state + changes:parameters + operationSetUUID:changes.uuid + sessionToken:sessionToken]; + } + }else{ + return [PFRESTObjectCommand updateObjectCommandForObjectState:self._state + changes:parameters + operationSetUUID:changes.uuid + sessionToken:sessionToken]; + } } - - return [PFRESTObjectCommand createObjectCommandForObjectState:self._state - changes:parameters - operationSetUUID:changes.uuid - sessionToken:sessionToken]; - } } @@ -1792,6 +1812,11 @@ + (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className } - (BFTask *)_validateSaveEventuallyAsync { + if([Parse isAllowCustomObjectIds]){ + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId message:@"ObjectId must not be null"]; + return [BFTask taskWithError:error]; + } + return [BFTask taskWithResult:nil]; } diff --git a/Parse/Parse/Parse.h b/Parse/Parse/Parse.h index 136dec364..873ea8b79 100644 --- a/Parse/Parse/Parse.h +++ b/Parse/Parse/Parse.h @@ -152,6 +152,22 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, readonly, class) BOOL isLocalDatastoreEnabled PF_TV_UNAVAILABLE; +///-------------------------------------- +#pragma mark - Allowing Custom ObjectIds +///-------------------------------------- + +/** + Allow custom ObjectIds in your application.`. + */ ++ (void)allowCustomObjectIds PF_TV_UNAVAILABLE; + +/** + Flag that indicates whether Custom ObjectIds are allowed. + + @return `YES` if Custom ObjectIds are allowed, otherwise `NO`. + */ +@property (nonatomic, readonly, class) BOOL isAllowCustomObjectIds PF_TV_UNAVAILABLE; + ///-------------------------------------- #pragma mark - Enabling Extensions Data Sharing ///-------------------------------------- diff --git a/Parse/Parse/Parse.m b/Parse/Parse/Parse.m index d4c2ae765..7cda43fd8 100644 --- a/Parse/Parse/Parse.m +++ b/Parse/Parse/Parse.m @@ -189,6 +189,14 @@ + (BOOL)isLocalDatastoreEnabled { return currentParseManager_.offlineStoreLoaded; } +///-------------------------------------- +#pragma mark - Custom ObjectIds +///-------------------------------------- + ++ (BOOL)isAllowCustomObjectIds { + return currentParseConfiguration_.allowCustomObjectId; +} + ///-------------------------------------- #pragma mark - User Interface ///-------------------------------------- diff --git a/Parse/Parse/ParseClientConfiguration.h b/Parse/Parse/ParseClientConfiguration.h index 256e6e4c5..66d8e7e7e 100644 --- a/Parse/Parse/ParseClientConfiguration.h +++ b/Parse/Parse/ParseClientConfiguration.h @@ -67,6 +67,17 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign, getter=isLocalDatastoreEnabled) BOOL localDatastoreEnabled PF_TV_UNAVAILABLE; +///-------------------------------------- +#pragma mark - Enabling Custom Object Ids +///-------------------------------------- + +/** + Whether or not to enable support for custom object ids in the SDK. + + The default value is `NO`. + */ +@property (nonatomic, assign, getter=allowCustomObjectId) BOOL allowCustomObjectId; + ///-------------------------------------- #pragma mark - Enabling Extensions Data Sharing ///-------------------------------------- @@ -148,6 +159,17 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign, readonly, getter=isLocalDatastoreEnabled) BOOL localDatastoreEnabled; +///-------------------------------------- +#pragma mark - Enabling Custom Object Ids +///-------------------------------------- + +/** + Whether or not to enable support for custom object ids in the SDK. + + The default value is `NO`. + */ +@property (nonatomic, assign, readonly, getter=isAllowCustomObjectId) BOOL allowCustomObjectId; + ///-------------------------------------- #pragma mark - Enabling Extensions Data Sharing ///-------------------------------------- diff --git a/Parse/Parse/ParseClientConfiguration.m b/Parse/Parse/ParseClientConfiguration.m index 8420224b4..44912b6af 100644 --- a/Parse/Parse/ParseClientConfiguration.m +++ b/Parse/Parse/ParseClientConfiguration.m @@ -115,6 +115,7 @@ - (BOOL)isEqual:(id)object { [self.server isEqualToString:other.server] && self.fileUploadController == other.fileUploadController && self.localDatastoreEnabled == other.localDatastoreEnabled && + self.allowCustomObjectId == other.allowCustomObjectId && [PFObjectUtilities isObject:self.applicationGroupIdentifier equalToObject:other.applicationGroupIdentifier] && [PFObjectUtilities isObject:self.containingApplicationBundleIdentifier equalToObject:other.containingApplicationBundleIdentifier] && [PFObjectUtilities isObject:self.URLSessionConfiguration equalToObject:other.URLSessionConfiguration] && @@ -134,6 +135,7 @@ - (instancetype)copyWithZone:(NSZone *)zone { configuration->_server = [self.server copy]; configuration->_fileUploadController = self->_fileUploadController; configuration->_localDatastoreEnabled = self->_localDatastoreEnabled; + configuration->_allowCustomObjectId = self->_allowCustomObjectId; configuration->_applicationGroupIdentifier = [self->_applicationGroupIdentifier copy]; configuration->_containingApplicationBundleIdentifier = [self->_containingApplicationBundleIdentifier copy]; configuration->_networkRetryAttempts = self->_networkRetryAttempts; diff --git a/Parse/Tests/Unit/ObjectUnitTests.m b/Parse/Tests/Unit/ObjectUnitTests.m index 56b7333f3..e9da654ec 100644 --- a/Parse/Tests/Unit/ObjectUnitTests.m +++ b/Parse/Tests/Unit/ObjectUnitTests.m @@ -307,6 +307,7 @@ -(void)testSaveRelationToACycle { XCTAssertEqualObjects(error.domain, PFParseErrorDomain); XCTAssertEqualObjects(error.localizedDescription, @"Found a circular dependency when saving."); } + -(void)testSaveRelationToACycleInAnArray { PFObject *objectA = [PFObject objectWithClassName:@"A"]; PFObject *objectB = [PFObject objectWithClassName:@"B"]; diff --git a/Parse/Tests/Unit/ParseClientConfigurationTests.m b/Parse/Tests/Unit/ParseClientConfigurationTests.m index a76d7d8be..e08780e20 100644 --- a/Parse/Tests/Unit/ParseClientConfigurationTests.m +++ b/Parse/Tests/Unit/ParseClientConfigurationTests.m @@ -40,6 +40,7 @@ - (void)testConfigurationWithBlock { configuration.server = @"http://localhost"; configuration.localDatastoreEnabled = YES; configuration.networkRetryAttempts = 1337; + configuration.allowCustomObjectId = YES }]; XCTAssertEqualObjects(configuration.applicationId, @"foo"); @@ -47,6 +48,7 @@ - (void)testConfigurationWithBlock { XCTAssertEqualObjects(configuration.server, @"http://localhost"); XCTAssertTrue(configuration.localDatastoreEnabled); XCTAssertEqual(configuration.networkRetryAttempts, 1337); + XCTAssertTrue(configuration.allowCustomObjectId); } - (void)testEqual {