LinkingObject property doesn't notify correctly
How frequently does the bug occur?
All the time
Description
~~It appears that a linkingObject property doesn't notify properly when the origin property is on the same class~~ Write transactions where only a backlink property is changed does not notify.
This happens even without a keyPath parameter.

Expected behavior is to receive a notification on a linkingObject property. Similar to how testBacklinkPropertyKeyPathNotifications4 behaves.
Stacktrace & log output
No response
Can you reproduce the bug?
Yes, always
Reproduction Steps
Example reproduction code
Version
10.17
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
All
Build environment
Xcode version: 13.0 Dependency manager and version: SPM
The issue is not strictly related to origin table and target table having the same table key. The below passes:
func testBacklinkPropertyKeyPathToSameClass() {
var parent: ModernAllTypesObject!
var child: ModernAllTypesObject!
let realm = try! Realm()
try! realm.write {
child = realm.create(ModernAllTypesObject.self)
}
let ex1 = expectation(description: "linking object notification")
let token1 = child.observe(keyPaths: ["linkingObjects"]) { _ in
ex1.fulfill()
}
try! realm.write {
parent = realm.create(ModernAllTypesObject.self)
parent.objectCol = child
}
waitForExpectations(timeout: 2, handler: nil)
token1.invalidate()
}
But this does not:
func testBacklinkPropertyKeyPathToSameClass() {
var parent: ModernAllTypesObject!
var child: ModernAllTypesObject!
let realm = try! Realm()
try! realm.write {
child = realm.create(ModernAllTypesObject.self)
}
let ex1 = expectation(description: "linking object notification")
let token1 = child.observe(keyPaths: ["linkingObjects"]) { _ in
ex1.fulfill()
}
try! realm.write {
parent = realm.create(ModernAllTypesObject.self)
}
try! realm.write {
parent.objectCol = child
}
waitForExpectations(timeout: 2, handler: nil)
token1.invalidate()
}
backlink_count is 0, then 1 (How I think it's expected). Though I'm still trying to figure out why the column isn't making it to change callback.
So the fact both the parent and child objects are of the same class is irrelevant. This is reproducible when target and origin properties are on different classes.
The actual issue is when reassigning the "objectCol", and by extension changing the "linkingObjects", is in a write transaction by itself. A transaction like:
try! realm.write {
parent.objectCol = child
}
would create a transaction log that's parsed with a "instr_set" case. The instr_set case only adds modifications to the changeset.
BUT linkingObject changes are delivered as insertions. So the insertion is never added to the callback.
In a write transaction like:
try! realm.write {
parent = realm.create(ModernAllTypesObject.self)
parent.objectCol = child
}
the transaction will also have a "instr_createObject" case because of the new object. Both the insertion for the new object, and the insertion representing the change to the "linkingObject" property are then added to the changeset.
This can be reproduce in core alone. So I'll get that and open an issue in core. Because I'm not sure if the solution is changing the transact_log or how we classify changes to a linkingObject property.
I've attached an example that uses valuePublisher that shows a short example of this issue happening. Hopefully it helps.
Any updates on this issue?
Would be nice to have a scary disclaimer about this in the docs for LinkingObject if this is going to remain an issue