Skip to content

Commit

Permalink
Merge pull request #4102 from realm/jp-random-defaults
Browse files Browse the repository at this point in the history
Use default property value for primary key if none was provided when creating objects
  • Loading branch information
jpsim authored Sep 16, 2016
2 parents 41db543 + d7efada commit 548113b
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 15 deletions.
29 changes: 14 additions & 15 deletions Realm/RLMObjectStore.mm
Original file line number Diff line number Diff line change
Expand Up @@ -387,21 +387,10 @@ void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object,
}
}
else {
// get or create our accessor
bool foundExisting;
auto primaryGetter = [=](RLMProperty *p) { return [value valueForKey:p.name]; };
object->_row = (*info.table())[createOrGetRowForObject(info, primaryGetter, createOrUpdate, &foundExisting)];

// populate
NSDictionary *defaultValues = nil;
for (RLMProperty *prop in info.rlmObjectSchema.properties) {

// skip primary key when updating since it doesn't change
if (prop.isPrimary)
continue;

__block bool foundExisting = false;
__block NSDictionary *defaultValues = nil;
auto getValue = ^(RLMProperty *prop) {
id propValue = RLMValidatedValueForProperty(value, prop.name, info.rlmObjectSchema.className);

if (!propValue && !foundExisting) {
if (!defaultValues) {
defaultValues = RLMDefaultValuesForObjectSchema(info.rlmObjectSchema);
Expand All @@ -411,8 +400,18 @@ void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object,
propValue = NSNull.null;
}
}
return propValue;
};
// get or create our accessor
object->_row = (*info.table())[createOrGetRowForObject(info, getValue, createOrUpdate, &foundExisting)];

// populate
for (RLMProperty *prop in info.rlmObjectSchema.properties) {
// skip primary key when updating since it doesn't change
if (prop.isPrimary)
continue;

if (propValue) {
if (id propValue = getValue(prop)) {
validateValueForProperty(propValue, prop);
RLMDynamicSet(object, prop, RLMCoerceToNil(propValue), creationOptions);
}
Expand Down
47 changes: 47 additions & 0 deletions Realm/Tests/ObjectTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,35 @@ + (NSDictionary *)defaultPropertyValues
@end


NSInteger dynamicDefaultSeed = 0;
@interface DynamicDefaultObject : RLMObject
@property int intCol;
@property float floatCol;
@property double doubleCol;
@property NSDate *dateCol;
@property NSString *stringCol;
@property NSData *binaryCol;
@end

@implementation DynamicDefaultObject
+ (BOOL)shouldIncludeInDefaultSchema {
return NO;
}
+ (NSDictionary *)defaultPropertyValues {
dynamicDefaultSeed++;
return @{@"intCol" : @(dynamicDefaultSeed),
@"floatCol" : @((float)dynamicDefaultSeed),
@"doubleCol" : @((double)dynamicDefaultSeed),
@"dateCol" : [NSDate dateWithTimeIntervalSince1970:dynamicDefaultSeed],
@"stringCol" : [[NSUUID UUID] UUIDString],
@"binaryCol" : [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding]};
}
+ (NSString *)primaryKey {
return @"intCol";
}
@end


@interface IgnoredURLObject : RLMObject
@property NSString *name;
@property NSURL *url;
Expand Down Expand Up @@ -1243,6 +1272,24 @@ - (void)testDefaultNSNumberPropertyValues {
[realm cancelWriteTransaction];
}

- (void)testDynamicDefaultPropertyValues {
void (^assertDifferentPropertyValues)(DynamicDefaultObject *, DynamicDefaultObject *) = ^(DynamicDefaultObject *obj1, DynamicDefaultObject *obj2) {
XCTAssertNotEqual(obj1.intCol, obj2.intCol);
XCTAssertNotEqual(obj1.floatCol, obj2.floatCol);
XCTAssertNotEqual(obj1.doubleCol, obj2.doubleCol);
XCTAssertNotEqualWithAccuracy(obj1.dateCol.timeIntervalSinceReferenceDate, obj2.dateCol.timeIntervalSinceReferenceDate, 0.01f);
XCTAssertNotEqualObjects(obj1.stringCol, obj2.stringCol);
XCTAssertNotEqualObjects(obj1.binaryCol, obj2.binaryCol);
};
assertDifferentPropertyValues([[DynamicDefaultObject alloc] init], [[DynamicDefaultObject alloc] init]);
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.objectClasses = @[[DynamicDefaultObject class]];
RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration error:nil];
[realm beginWriteTransaction];
assertDifferentPropertyValues([DynamicDefaultObject createInRealm:realm withValue:@{}], [DynamicDefaultObject createInRealm:realm withValue:@{}]);
[realm cancelWriteTransaction];
}

#pragma mark - Ignored Properties

- (void)testIgnoredUnsupportedProperty
Expand Down
68 changes: 68 additions & 0 deletions RealmSwift/Tests/ObjectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ import Foundation

#if swift(>=3.0)

private var dynamicDefaultSeed = 0
private func nextDynamicDefaultSeed() -> Int {
dynamicDefaultSeed += 1
return dynamicDefaultSeed
}
class DynamicDefaultObject: Object {
dynamic var intCol = nextDynamicDefaultSeed()
dynamic var floatCol = Float(nextDynamicDefaultSeed())
dynamic var doubleCol = Double(nextDynamicDefaultSeed())
dynamic var dateCol = Date(timeIntervalSinceReferenceDate: TimeInterval(nextDynamicDefaultSeed()))
dynamic var stringCol = UUID().uuidString
dynamic var binaryCol = UUID().uuidString.data(using: .utf8)

override static func primaryKey() -> String? {
return "intCol"
}
}

class ObjectTests: TestCase {

// init() Tests are in ObjectCreationTests.swift
Expand Down Expand Up @@ -194,6 +212,22 @@ class ObjectTests: TestCase {
XCTAssertFalse(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalDoubleCol"]!.isIndexed)
}

func testDynamicDefaultPropertyValues() {
func assertDifferentPropertyValues(_ obj1: DynamicDefaultObject, _ obj2: DynamicDefaultObject) {
XCTAssertNotEqual(obj1.intCol, obj2.intCol)
XCTAssertNotEqual(obj1.floatCol, obj2.floatCol)
XCTAssertNotEqual(obj1.doubleCol, obj2.doubleCol)
XCTAssertNotEqualWithAccuracy(obj1.dateCol.timeIntervalSinceReferenceDate, obj2.dateCol.timeIntervalSinceReferenceDate, 0.01)
XCTAssertNotEqual(obj1.stringCol, obj2.stringCol)
XCTAssertNotEqual(obj1.binaryCol, obj2.binaryCol)
}
assertDifferentPropertyValues(DynamicDefaultObject(), DynamicDefaultObject())
let realm = try! Realm()
try! realm.write {
assertDifferentPropertyValues(realm.create(DynamicDefaultObject.self), realm.create(DynamicDefaultObject.self))
}
}

func testValueForKey() {
let test: (SwiftObject) -> () = { object in
XCTAssertEqual(object.value(forKey: "boolCol") as! Bool!, false)
Expand Down Expand Up @@ -409,6 +443,24 @@ class ObjectTests: TestCase {

#else

private var dynamicDefaultSeed = 0
private func nextDynamicDefaultSeed() -> Int {
dynamicDefaultSeed += 1
return dynamicDefaultSeed
}
class DynamicDefaultObject: Object {
dynamic var intCol = nextDynamicDefaultSeed()
dynamic var floatCol = Float(nextDynamicDefaultSeed())
dynamic var doubleCol = Double(nextDynamicDefaultSeed())
dynamic var dateCol = NSDate(timeIntervalSinceReferenceDate: NSTimeInterval(nextDynamicDefaultSeed()))
dynamic var stringCol = NSUUID().UUIDString
dynamic var binaryCol = NSUUID().UUIDString.dataUsingEncoding(NSUTF8StringEncoding)

override static func primaryKey() -> String? {
return "intCol"
}
}

class ObjectTests: TestCase {

// init() Tests are in ObjectCreationTests.swift
Expand Down Expand Up @@ -581,6 +633,22 @@ class ObjectTests: TestCase {
XCTAssertFalse(SwiftIndexedOptionalPropertiesObject().objectSchema["optionalDoubleCol"]!.indexed)
}

func testDynamicDefaultPropertyValues() {
func assertDifferentPropertyValues(obj1: DynamicDefaultObject, _ obj2: DynamicDefaultObject) {
XCTAssertNotEqual(obj1.intCol, obj2.intCol)
XCTAssertNotEqual(obj1.floatCol, obj2.floatCol)
XCTAssertNotEqual(obj1.doubleCol, obj2.doubleCol)
XCTAssertNotEqualWithAccuracy(obj1.dateCol.timeIntervalSinceReferenceDate, obj2.dateCol.timeIntervalSinceReferenceDate, 0.01)
XCTAssertNotEqual(obj1.stringCol, obj2.stringCol)
XCTAssertNotEqual(obj1.binaryCol, obj2.binaryCol)
}
assertDifferentPropertyValues(DynamicDefaultObject(), DynamicDefaultObject())
let realm = try! Realm()
try! realm.write {
assertDifferentPropertyValues(realm.create(DynamicDefaultObject.self), realm.create(DynamicDefaultObject.self))
}
}

func testValueForKey() {
let test: (SwiftObject) -> () = { object in
XCTAssertEqual(object.valueForKey("boolCol") as! Bool!, false)
Expand Down

0 comments on commit 548113b

Please sign in to comment.