Selections and Sorting

Back to index


A selection is a sorted list of records.

It owns and copies a sorter object which specifies the sort order.

A dbTable implicitly has a current selection, and can be regarded as an iterator over the selection.

dbTable::cloneSharingSelection() allows you to get another iterator over the same selection, which implies the same sort order.

A selection can be a lightweight way to preserve the set of records on which you are working, or to react to users highlighting items in a list.

You can perform typical set operations (union, intersection, difference) with selections and dbTables intermingled.

 

GENERAL SORTING THEORY

Sorts in OOFILE are declarative - you specify a sort order and the database will appear in that order until you cancel or suspend the sort.

Re-sorting is lazily evaluated. It doesn't matter in which order you perform a succession of searches, selectXX or setSortOrder, the sorting only takes place at the last possible point.

This means, if you change a selection then the next start() or access to a field will trigger a re-sort. eg: searching, adding a record or deleting a record all make the sort "dirty".

The lazy evaluation means it is safe to perform a sequence like:

People.setSortOrder(People.OtherNames);
                                  People.search(People.salary > 50000);
                                  cout << People.count() << " people earn over $50,000" << endl;
                                  People.searchSelection(People.LastName == "Dent"); if (People.count()) cout << "Dent family high-earners are: " << endl << People << endl;

The only re-sort that occurs is on the final cout ... << People.
The count() function has no need to access any data so does not trigger a re-sort.

CONTROLLING SORTS

You can control sorting with
People.suspendSorting(), resumeSorting() and unSorted().

Suspends and resumes are nested, and it is safe to call resumeSorting more times than a suspension has occurred.

If you want to force a sort to occur at a predictable time, you can trigger the sorter directly, eg:

People.sorter()->sortNow();

Be careful with code like the above, sorter() returns a dbSorter* and will return 0 if no sort is specified. Thus, you can tell if a sort has been specified by:

if (People.sorter())
                                  blah;

SIMPLE SORTS

Simple single field sorts are specified by passing in a field, eg:

People.setSortOrder(People.LastName);
                                  People.setReverseSortOrder(People.Salary);

MULTIPLE FIELD SORTS

Multiple field sorts require a dbSorter. This can be created in advance, and might even be a static member of your class or a local variable. This is useful if you want to reset the sort order several times, eg:

dbSorter() PeoplePaid;
PeoplePaid << People.LastName << reversed(People.Salary);
People.setSortOrder(PeoplePaid);
...
People.setSortOrder(People.LastName);
...
People.setSortOrder(PeoplePaid);

Creating the dbSorter on the fly is quite safe also, eg:
People.setSortOrder(dbSorter() << People.LastName << reverse(People.Salary));

USING COMPOUND FIELDS

If you will be sorting selections of all records, the fastest sort is using an indexed field. Thus, it may be worth the overhead of declaring a compound field that is indexed. Note that such fields incur a space penalty (for the extra index) and have a significant impact on the speed of adding records.

 

SORTING PROPAGATION & STATE CHANGES

The sorter is owned by the selection and hidden by it from the dbTable(s) iterating across the selection.

The sorter is either sorting, needing to sort, or happily sorted.

Changes to the selection put the sorter in a 'needs to sort' state.

Sorting is triggered explicitly by a dbTable::sortSelectionNow() or by changes in the dbTable state that require a sorted selection. For example, going to the first record requires the selection be sorted so we know exactly which is first!

dbTable state changes all involve a call to dbTable::ContextChange() which calls a similar routine in the database backend. The backend is responsible for passing this call on to the sorter. At no time does a sorter retain information on the table it is sorting, but is passed in that information at the time it is told to sort. This handles the situation where a selection may be shared amongst several cloned tables, each serving as iterators across the selection. No matter which table triggers the sort, all will feel the benefit as the shared selection is sorted once.

STATE-PRESERVING STACK CLASSES

Classes with an st prefix are stack classes, intended to preserve a state through some local scope. For saving a selection or affecting sorting we have several such:

stSaveSelection
Frequently used, this preserves the current selection (implying sort order) and allows you to perform searches etc. with impunity. The sorted selection is restored as the object goes out of scope.
stSuspendSorting
Just a quick way to prevent resorts if you are in a complex loop through a selection, and don't need sorting to occur.
stSaveSelectionAndSuspendSorting
A convenient way to accomplish the above two actions in a single line.


Back to index


(c) Copyright A.D. Software 1994-1997 (All Rights Reserved).
Last Updated: 8th March 1997