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.
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.
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 single field sorts are specified by passing in a field, eg:
People.setSortOrder(People.LastName);
People.setReverseSortOrder(People.Salary);
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));
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.
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.
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
stSuspendSorting
stSaveSelectionAndSuspendSorting