-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make breaking changes needed to support arrays of primitives #5149
Conversation
Shouldn't we pull in the changes from master (and #5148, once it's merged to master) via a merge commit, rather than rebasing as you appear to have done here? |
Yes, but that merge should be from |
2a254d7
to
59a7340
Compare
Realm/RLMArray.mm
Outdated
if (![array->_objectClassName isEqualToString:object->_objectSchema.className]) { | ||
@throw RLMException(@"Object type '%@' does not match RLMArray type '%@'.", | ||
object->_objectSchema.className, array->_objectClassName); | ||
- (RLMResults *)sortedResultsUsingProperty:(NSString *)property ascending:(BOOL)ascending { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be completely removed for 3.0.
@@ -387,7 +435,7 @@ - (id)maxOfProperty:(NSString *)property { | |||
|
|||
- (id)sumOfProperty:(NSString *)property { | |||
[self validateAggregateProperty:property method:_cmd allowDate:false]; | |||
return [_backingArray valueForKeyPath:[@"@sum." stringByAppendingString:property]]; | |||
return [_backingArray valueForKeyPath:[@"@sum." stringByAppendingString:property]] ?: @0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Foundation's @sum
returns nil
for an empty array, shouldn't we match that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We decided not to match Foundation's behavior because Foundation is wrong; the sum of an empty set isn't undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I vaguely remember this discussion, but not the outcome. thanks for clarifying.
// get object class from type string - @"RLMArray<objectClassName>" | ||
_objectClassName = [[NSString alloc] initWithBytes:code + arrayPrefixLen | ||
length:strlen(code + arrayPrefixLen) - 2 // drop trailing >" | ||
encoding:NSUTF8StringEncoding]; | ||
|
||
if ([RLMSchema classForString:_objectClassName]) { | ||
_optional = false; | ||
_type = RLMPropertyTypeArray; | ||
_type = RLMPropertyTypeObject; | ||
return YES; | ||
} | ||
@throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This exception message is incorrect now "RLMArrays can only contain instances of RLMObject subclasses."
Realm/RLMQueryUtil.mm
Outdated
|
||
if (property.type == RLMPropertyTypeArray || property.type == RLMPropertyTypeLinkingObjects) | ||
if (property.array || property.type == RLMPropertyTypeLinkingObjects) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RLMPropertyTypeLinkingObjects
properties have array
set to true
, so this check can just be if (property.array)
return YES; | ||
} | ||
if (array) { | ||
if (RLMArray *array = RLMDynamicCast<RLMArray>(value)) { | ||
return [array.objectClassName isEqualToString:objectClassName]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this need to consider primitive types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this PR does not add support for arrays of primitives.
return [array.objectClassName isEqualToString:objectClassName]; | ||
} | ||
if (RLMListBase *list = RLMDynamicCast<RLMListBase>(value)) { | ||
return [list._rlmArray.objectClassName isEqualToString:objectClassName]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this need to consider primitive types?
f4664c2
to
db1e356
Compare
db1e356
to
f80f7fb
Compare
f80f7fb
to
4943c8f
Compare
public override func value(forKey key: String) -> Any? { | ||
return value(forKeyPath: key) | ||
*/ | ||
@nonobjc public func value(forKey key: String) -> [AnyObject] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does @nonobjc
mean that this cannot be invoked from Obj-C? I'd think that would give unexpected behavior from calls to -valueForKeyPath:
with a key path that traverses into a List
but where the List
isn't the root object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invoking it from obj-c calls the one defined on the parent class which does the exact same thing. This function just refines the return type when calling it from from Swift to make the code using it a little less awkward.
RealmSwift/RealmCollection.swift
Outdated
@@ -123,6 +122,11 @@ private func forceCast<A, U>(_ from: A, to type: U.Type) -> U { | |||
return from as! U | |||
} | |||
|
|||
/// A type which can be stored in a Realm List or Results | |||
public protocol RealmCollectionValue { | |||
static func className() -> String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will this return for primitive types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function has actually gone away on the primitive arrays branch because different functions were needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like CI is failing due to this function being undocumented:
Undocumented Realm swift declarations:
{
"warnings": [
{
"file": "/Users/realm/workspace/objc_pr/configuration/Release/target/docs/xcode_version/8.3.3/RealmSwift/RealmCollection.swift",
"line": 127,
"symbol": "RealmCollectionValue.className()",
"symbol_kind": "source.lang.swift.decl.function.method.static",
"warning": "undocumented"
}
],
RealmSwift/Tests/ListTests.swift
Outdated
assertThrows(array.swap(index1: 0, -1)) | ||
assertThrows(array.swap(index1: 1000, 0)) | ||
assertThrows(array.swap(index1: 0, 1000)) | ||
assertThrows(array.swap(-1, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Swift 4, the equivalent method on Array
appears to be called swapAt
.
// swiftlint:disable:next line_length | ||
XCTAssertEqual(objectSchema.description, "SwiftObject {\n\tboolCol {\n\t\ttype = bool;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tintCol {\n\t\ttype = int;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tfloatCol {\n\t\ttype = float;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdoubleCol {\n\t\ttype = double;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tstringCol {\n\t\ttype = string;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tbinaryCol {\n\t\ttype = data;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdateCol {\n\t\ttype = date;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tobjectCol {\n\t\ttype = object;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = YES;\n\t}\n\tarrayCol {\n\t\ttype = array;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n}") | ||
// XCTAssertEqual(objectSchema.description, "SwiftObject {\n\tboolCol {\n\t\ttype = bool;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tintCol {\n\t\ttype = int;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tfloatCol {\n\t\ttype = float;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdoubleCol {\n\t\ttype = double;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tstringCol {\n\t\ttype = string;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tbinaryCol {\n\t\ttype = data;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdateCol {\n\t\ttype = date;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tobjectCol {\n\t\ttype = object;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = YES;\n\t}\n\tarrayCol {\n\t\ttype = array;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this needs to be updated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good to me. I have no feedback of any real significance.
CHANGELOG.md
Outdated
@@ -99,6 +99,13 @@ x.x.x Release notes (yyyy-MM-dd) | |||
correctly nil out nullable properties when updating an existing | |||
object when the `value` argument specifies nil or `NSNull` for | |||
the property value. | |||
* Rename `List.remove(objectAtIndex:)` to `List.remove(at:)` to match the named |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"name"
Realm/RLMObjectBase.mm
Outdated
@@ -78,34 +78,28 @@ - (void)dealloc { | |||
_observationInfo = nullptr; | |||
} | |||
|
|||
static id cooerceToObjectType(id obj, Class cls, RLMSchema *schema) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"coerce"
@@ -314,14 +314,16 @@ public final class List<T: Object>: ListBase { | |||
|
|||
- parameter index: The index at which to remove the object. | |||
*/ | |||
public func remove(objectAtIndex index: Int) { | |||
public func remove(at index: Int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Swift standard library version of this method returns the removed element. I don't know if this is something we should replicate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's sort of gratuitous overhead for something that's at best vaguely convenient, but matching the standard library is probably the way to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like Array
returns the value that was there, but Collection
/RangeReplaceableCollection
don't and there's alternative functions on Collection
for remove and return old (popLast()
etc.), so I'm inclined to leave it as a void return.
ba37482
to
215909c
Compare
The changelog entries will need to be moved into the section for the upcoming section now that v3.0.0-beta.3 has been released. |
2caba93
to
719ded8
Compare
Failures are both CI things that passed before updating the changelog. |
Everything but the last commit is just pulling in latest master and #5148 on top of master-3.0.
This makes the two API changes needed for arrays of primitives: loosening the generic constraint to allow non-RLMObjects in RLMArray/RLMResults (but not yet actually supporting anything else), and changing RLMProperty/RLMPropertyType so that arrays of things other than objects can be expressed.