TOP | UP: Interface | NEXT: Border Crossings |
The Frontier database is a remarkable thing: a hierarchical name-value storage system, with hash-indexed access that stays rapid as tables get large, and with efficient memory management both in RAM and on disk. (In fact, the database is such cool technology that UserLand distributes it separately as a cross-platform library for C and Java applications.1)
As with other things, so with the database: if it's good to have one of them, you might, not unreasonably, want two. Frontier.root is the "working" database, constantly being accessed for verbs and other pieces of Frontier's "system." The storage for a sizeable storage task might preferably be separated from the working database, out of considerations of convenience, speed, safety, and size.
For this reason, it is possible to open a second database simultaneously with the first, and communicate with it manually or in UserTalk. This chapter explains the process.
Another option for storing data outside the database is to drive a serious, dedicated database application such as FileMaker or FoxPro, or even a small flat-file database application such as uBASE which is included with the Frontier distribution. This involves inter-application communication, which might mean a speed hit, but such an application might have capacities that a Frontier database does not provide. For example, uBASE provides a flatfile structure of records with identically named fields. A serious database application might provide indexing and rapid search of fields, ability to work with very large numbers of records, relational structure, and so forth. On such matters, see Chapter 32, Driving Other Applications.
You can open a second database manually. There is little point to doing this except to examine or alter data by typing, copying and pasting, and so forth. That's because the second database is very minimal: it has a restricted set of verbs (just the kernel, in system.compiler) and no custom menus (just the built-in File, Edit, and Window menus).
You could add scripts and an interface to the second database, but this would be rather against the spirit of the thing. The second database isn't intended as a place to work. It contains sufficient functionality to enable the manipulation of data in an edit window, and no more.2
To create and open a second database manually, choose New from the File menu; to open an existing second database manually, choose Open from the File menu. You can perform these actions programmatically with filemenu.new() and filemenu.open().
When a second database is opened in this way, there is a second Main Window representing it. This Main Window's popup menu gives access to an agent which shows the pathname of the database; this is useful so that you know which Main Window goes with which database. For instance, you might wish to close the second database by clicking in the go-away box of its Main Window; you'll want to be sure you're closing the right database.
Frontier keeps track of what database owns any window you bring to the front; this determines which database you are "in," and the menus at the top of the screen change accordingly, as does the repertory of verbs available to you.
To work with a second database programmatically, the db verbs are provided. These verbs do not cause any windows to open on the second database, and they communicate with the second database through a completely different mechanism than if the second database were opened manually. (For example, a database that is opened with Open from the File menu is not necessarily open in the db.open() sense.)
References to entries in the second database must be strings, because if they were addresses their validity would be checked against the main database, which might not work. These strings must be full paths: they cannot be partial paths, and they cannot be abbreviated by means of with constructions. Hence it makes sense to create tables at or close to root level.
db.new (pathname)
db.open (pathname, readOnly?)
The advantage of opening a database read-only is that it remains possible for another thread, or another copy of Frontier, also to open it read-only.
db.newTable (pathname, tablePathString)
To set a database entry value, possibly creating the entry:
db.setValue (pathname, entryPathString, value)
To learn a database entry value:
db.getValue (pathname, entryPathString)
To learn whether a database entry exists:
db.defined (pathname, entryPathString)
To learn whether an existing database entry is a table:
db.isTable (pathname, entryPathString)
To learn the number of entries in a table:
db.countItems (pathname, entryPathString)
To obtain the value of the n th item of a table:
db.getNthItem (pathname, entryPathString, n)
db.getNthItem() makes up for the fact that, in the absence of direct references, array notation is impossible.
db.delete (pathname, entryPathString)
db.save (pathname)
db.save() returns true or false, as the database was saved or not. It is well to check this value, just to be certain that Frontier realized the database was dirty. If you call db.close() without saving first, changes will be lost.
To close a database without saving:
db.close (pathname)
In this example, we create a second database, make a table at root level called myTable, and copy into it all the entries in the main database's workspace table.
The whole operation is embedded in a try so that, if something goes wrong, the second database is not left open; this approach is useful when working with second databases, as there is no way to learn the pathnames of open databases.
As mentioned in Chapter 29, Import/Export, one can take advantage of the ability to open multiple databases as a way of migrating to a clean root. Imagine that as you customize the database you note the address of each customized entry in an outline at, for example, workspace.myMigrateList.3 So workspace.myMigrateList might look like this:
people.man.customcommands
system.verbs.apps.MORE
system.verbs.apps.Eudora.examples.man
people.man.notepad
user.hooks.closewindow
And so forth. Then, having renamed your old root and migrated to a clean Frontier.root, you could run a script like the following.
1. For more information, and to obtain the database SDK, see http://www.scripting.com/Gimme5/odb/.
TOP | UP: Interface | NEXT: Border Crossings |