OOFILE | Downloads | Purchasing | Press | Services | Company Information | Soapbox | References | F.A.Q. | HOME

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. A database can be sorted by any field or combination of fields.


Simple sorts

Simple single field sorts are specified by passing a field to either setSortOrder() -> ascending sort or setReverseSortOrder() -> gives descending sort. Any field can be sorted as it is overridden for the different field types (eg a char field wil be sorted alphabetically while a numeric field will be sorted in numerical order).

For example:
People.setSortOrder(People.LastName);
People.setReverseSortOrder(People.Salary);


Multple field sorts

We can also sort by multiple fields. For example, a telephone book is sorted by last name, but those people with the same last name are sorted by their first initial.

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. dbSorters are simply a variable type and are declared thus:

	dbSorter() PeopleSort;  

We then pass in the fields we wish to sort by. The order in which we pass the fields is the order the fields wil be sorted by. So, for our telephone book example, we wish to sort first by last name, then by initials.

	PeopleSort << People.LastName << People.Initials;  

Then we must set the sort order calling our dbSorter"

	People.setSortOrder(PeopleSort);  

We can also change the sort order without having to change the structure of our sorter.

	People.setSortOrder(People.LastName);  

Lets also say that if there is some people with the same lastname and initials that we'd like to sort them by their telephone number, but we'd like to do it in reverse order (ie descending) using the reverse() function. We can easily alter our sorter by passing in the new field thus:

	PeopleSort << reverse(People.TelephoneNum)  

Creating the dbSorter on the fly is quite safe also, eg:

	People.setSortOrder(dbSorter() << People.LastName << People.initials 
                                       << reverse(People.TelephoneNum));   

Controlling sorts

You can control sorting with the functions suspendSorting(), resumeSorting() and unSorted() (for example: People.suspendSorting() ).

Suspend temporarily ignores the sorter, returning it to its previous state. The sort can be returned by using resumeSorting(). Suspends and resumes are nested, and it is safe to call resumeSorting() more times than a suspension has occurred. unSorted() causes the sorter to return back to the state it was before the sort -> it deletes the sort state entirely and cannot be resumed.

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 testing:

	if (People.sorter())
           {}  

Timing

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.

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. These all make the sort "dirty" (ie requiring a resort).

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.


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. See Indices for the indices available.


Sorting propagation

A dbSorter is a dependent of the dbTable that it sorts.

It responds to the following messages from the dbTable, in 3 cases:

whenever the current record is about to be changed by going to a new one or other existing record

	OOFmsg_UnloadRecord & OOFmsg_ChangeContext
	if (mNeedsToSort)
	   sortNow();   

when the selection is replaced by an insert (importing data) or search

	OOFmsg_ChangeSelection
	mNeedsToSort = true;   

when a record is saved, potentially changing the data it is sorted by and so affecting its order in the sorted selection

	OOFmsg_SaveRecord  
	if (mSortOnSaves)
 	  sortNow();  

Feature index

(c) Copyright A.D. Software 1994-2000 (All Rights Reserved).
Last Updated: 9th September 2001