tconbeer / textual-fastdatatable

A performance-focused reimplementation of Textual's DataTable widget, with a pluggable data storage backend.
MIT License
15 stars 2 forks source link

Allow unsorting data #121

Open alexmalins opened 2 months ago

alexmalins commented 2 months ago

Now I have some time to work on sort by column for Harlequin.

One component of sorting by column is the ability to unsort the datatable back to the rows' original ordering prior to sorting. For ex, restoring the datatable back to it's original state when a column's sort setting has clicked through "ascending" and "descending" back to no sort order.

A solution to enable via the backend this could be:

Advantages:

Disadvantages:

Any thoughts Ted? If you're happy for me to proceed, I'll start committing code for more discussion into a branch & draft PR. 🙌

tconbeer commented 1 month ago

Hey @alexmalins, Sorry it took me a minute to get back to you.

Because the backend data is largely immutable, we already maintain a few copies of it. I think a simpler approach here would be to just store a copy of the unsorted data before you sort it the first time. The basic change would be:

Class ArrowBackend:
    ...
    def sort(
        self, by: list[tuple[str, Literal["ascending", "descending"]]] | str
    ) -> None:
        """
        by: str sorts table by the data in the column with that name (asc).
        by: list[tuple] sorts the table by the named column(s) with the directions
            indicated.
        """
        if self._unsorted_data is None:
            self._unsorted_data = self.data
        self.data = self.data.sort_by(by)

    def unsort(self) -> None:
        """Mutate self.data to restore the original ordering, before sorting was applied."""
        if self._unsorted_data is not None:
            self.data = self._unsorted_data

Then there will be some other times when you have to invalidate the self._unsorted_data prop, like when adding/deleting rows/columns etc.

alexmalins commented 1 month ago

Thanks Ted - I guess I was being too precious in not wanting to store a copy due to the extra memory overhead. But the flipside is not storing & introducing a hidden index introduces more code complexity.

I just pushed #124 with some commits when I was playing around with this the weekend before last. I'll switch it over to your suggested solution and generally tidy it up, as there's some general small fixes and code improvements entwined with the commits adding the hidden index. 👍