realm / realm-swift

Realm is a mobile database: a replacement for Core Data & SQLite
https://realm.io
Apache License 2.0
16.32k stars 2.15k forks source link

Create SortDescriptor From NSSortDescriptor #7412

Open bdkjones opened 3 years ago

bdkjones commented 3 years ago

Problem

NSTableView and NSOutlineView use NSSortDescriptor to allow sorting the table's contents. (This is what powers the "click on a column header to sort by that column" feature)

Realm does not use NSSortDescriptor. Realm offers its own SortDescriptor, which you can use to sort a List<T>, Results<T>, etc.

If the NSSortDescriptor uses a single-level key, such as a property of the exact objects powering the tableView, you can do this:

    let tableDescriptor: NSSortDescriptor = someTableView.sortDescriptors.first!
    let realmDescriptor: RealmSwift.SortDescriptor = RealmSwift.SortDescriptor(keyPath: tableDescriptor.key, ascending: tableDescriptor.ascending)
    // Go sort the Results<T> or List<T> powering the table with 'realmDescriptor', then reload the table.

However, if the NSSortDescriptor powering the tableView is using a keypath instead of a single level key, the above approach will not work. The keypath property of NSSortDescriptor is an AnyKeyPath type, which is not convertible to String (what Realm requires in its initializer).

It would be ludicrously useful if I could tell Realm: "Here's an NSSortDescriptor. Make a SortDescriptor out of it and if you can't, tell me about it." I understand that you've got your own custom SortDescriptor type because you don't support all the functionality that NSSortDescriptor has. But the constant back-and-forth between the UI and Realm's types needs to be easier here.

Thank you.

Solution

I'd like this API:

RealmSwift.SortDescriptor.init(NSSortDescriptor: someNSSortDescriptor)

How important is this improvement for you?

Would be a major improvement

bdkjones commented 3 years ago

Another option would be an initializer that accepts AnyKeyPath:

RealmSwift.SortDescriptor.init(keyPath: AnyKeyPath, isAscending: Bool)

Then the conversion from AnyKeyPath to String becomes your problem internally.

The bottom line is that, right now, it's irritating to make Realm's sorting APIs play nicely with the sorting APIs in Apple's UI frameworks because there's constant friction in translating between the two. (I'm sure SwiftUI uses a different approach, but SwiftUI is still a hot mess for anything non-trivial, so it's not an option for large apps.)

dianaafanador3 commented 3 years ago

Hi @bdkjones like you said, because our SortDescriptor cannot fully equal an NSSortDescriptor we cannot create an initialiser that accepts it, and we cannot specify this behaviour for NSTableView's NSSortDescriptor. About the second question we do have an initialiser that accepts keypaths for SortDescriptor. public init<Element: ObjectBase>(keyPath: PartialKeyPath<Element>, ascending: Bool = true)

bdkjones commented 3 years ago

How does that help me take the NSSortDescriptors returned by an NSTableView and use them to sort my Realm collection? That's the end goal. (Right now, there's a huge amount of friction in something that should be really straightforward.)

jsflax commented 3 years ago

@bdkjones Why not just add an extension to your own project that does this?

extension SortDescriptor {
    init(sortDescriptor: NSSortDescriptor) {
        self.keyPath = sortDescriptor.key ?? ""
        self.ascending = sortDescriptor.ascending
    }
}

Then you can map the tableViews descriptors simply: someTableView.sortDescriptors.map(SortDescriptor.init)

I believe what Diana was trying to say is that it feels odd to us to add this as a first class conversion when the two types are similar but not equal.

bdkjones commented 3 years ago

@jsflax

I can't find any documentation to confirm, but I was under the impression that the "key" and "keyPath" properties of NSSortDescriptor are not interchangeable. That is, "key" is not simply a string version of "keyPath" because the latter can't necessarily be represented as a String, depending on the objects involved.

It's sort of a moot point, however, because of #7413. The things I need to sort via KeyPath can't be sorted via KeyPath due to Realm limitations in another area.

ianpward commented 3 years ago

It's sort of a moot point, however, because of #7413. The things I need to sort via KeyPath can't be sorted via KeyPath due to Realm limitations in another area.

@bdkjones What are the limitations in the other area?

dianaafanador3 commented 3 years ago

HI @bdkjones have you been able to make this work in a simpler way?, Is the extension initialiser helpful for your use case?

bdkjones commented 3 years ago

@dianaafanador3 Nope. Because of #7413, I can't sort Realm's data the way I need to sort it anyway, so this issue is a moot point right now.