<html>

<head>

<title>uBASE</title>

<body bgcolor="#FFFFFF" text="#000000" link="#0000CC" vlink="#AA0000">


<h4>[<a href="http://www.hotwired.com/userland/aretha/">Home</a>] Created 5/23/95 by <a href="mailto:dwiner@well.com">dwiner@well.com</a> (Dave Winer)</h4>

<h1><img src = "plain.gif" alt = "" align=top> uBASE</h1>

<blockquote>
<b>What is uBASE?<p></b>

uBASE is a fast flat-file database for script writers.<p>

Unlike FileMaker, 4th Dimension and FoxBase, uBASE is designed to serve scripts, not users. It has almost no user interface. It's a very small program that loads quickly. It has a very simple scripting interface. uBASE is ideal for the data storage needs of many scripts.<p>

In terms of its Apple Event interface, nothing as fancy as the object model here, just a few simple verbs to create a new file, open an existing file, add a record, lookup a record, close a file. <p>

<b>Creating a new file<p></b>

The following sections review the scripting verbs for uBASE. If you want to follow along in Frontier, navigate to system.verbs.apps.ubase and open the examples table. Also, all of uBASE's verbs are documented in the DocServer database.<p>

To create a new uBASE file, use the ubase.newFile verb. It takes a single parameter, the full path to the file it creates. The file is created initially with no fields and no records. Here's an example:<p>

<table>
<td><code><pre>
fnum = ubase.newFile ("System:States Database")
</pre></code></td>
</table><p>

ubase.newFile returns a file refnum -- a number between 1 and 99. Save the refnum in a local variable. All subsequent calls to uBASE will use this number. This allows uBASE to manage more than a single open database, and allows scripts to move information from one database to another.<p>

<b>Opening an existing file; closing files<p></b>

To open an existing file use ubase.openFile. It takes a full path to the file to open, and returns a file refnum:<p>

<code><pre>
fnum = ubase.openFile ("System:States Database")
</pre></code><p>

To close a uBASE file, use ubase.closeFile:
<code><pre>
ubase.closeFile (fnum)
</pre></code><p>

<b>Adding fields to a uBASE file<p></b>

After creating a new file or opening an existing file, you can add fields to the database using the ubase.addField verb.<p>

ubase.addField takes three parameters:<p>

1.	a file refnum indicating which file the field is to be added to.<p>

2.	fieldName, a four-character string, the name of the field. See note below.<p>

3.	fieldType, a four-character string, indicating the type of the new field.<p>

For performance, we limited field names to four characters so that records could flow quickly between uBASE and Frontier using the Apple Event Manager.<p>

<b>Field types<p></b>

The set of field types supported by uBASE is a subset of the types supported by Frontier. <p>

Here's a list of field types:
<pre><code>
booleanType   true or false.
longType      32-bit signed number.
dateType      the number of seconds since Jan 1, 1904.
stringType    a variable length text handle.
doubleType    double-precision floating point number.
binaryType    unformatted data, variable-length.
</code></pre><p>

<b>Example<p></b>

Here's an example that launches uBASE, creates a new file in the same folder as the Frontier application, adds two string fields to it, and then closes the file:
<code><pre>
local (ubasefolder, fnum)
ubase.launch () &lt;&lt;make sure uBASE is ready to talk to us
fnum = ubase.newFile (Frontier.pathstring + "States Database")
ubase.addField (fnum, 'capi', stringType) &lt;&lt;the state's capital
ubase.addField (fnum, 'abbr', stringType) &lt;&lt;the abbreviation for the state
ubase.closeFile (fnum) &lt;&lt;the database has two fields, no records
</code></pre><p>

<b>Each record has a key<p></b>

Every record in a uBASE file has a unique key, a string of any number of characters. In an address book application, for example, the key could be a user's email account name. Or in an application database, it could be the creator ID of the application.<p>

If you add a record that has the same key as an existing record, the new record replaces the previous record. The key is unique, that's an absolute rock-hard rule.<p>

<b>How to add a record to a uBASE file<p></b>

ubase.addRecord takes three parameters:<p>

1.	a file refnum;<br>
2.	the record's key;<br>
3.	the address of a Frontier table containing the values for the record.<br><p>

Here's an example that opens the database created in the previous example and adds a record describing Wisconsin:
<code><pre>
local (fnum, holder)
new (tableType, @holder)
holder.capi = "Madison"
holder.abbr = "WI"
ubase.launch ()
fnum = ubase.openFile (Frontier.pathstring + "States Database")
ubase.addRecord (fnum, "Wisconsin", @holder)
ubase.closeFile (fnum) &lt;&lt;the database has two fields, one record
</code></pre><p>

See ubase.examples.addStates for an example that adds all 50 states to the database.<p>

<b>ubase.lookupRecord<p></b>

The flipside of ubase.addRecord is ubase.lookupRecord. It takes three parameters: a file refnum, the record's key and the address of a Frontier table to receive the values for the record with the indicated key.<p>

Here's an example that opens the database and looks up information about Wisconsin:
<code><pre>
local (fnum, holder)
ubase.launch ()
fnum = ubase.openFile (Frontier.pathstring + "States Database")
ubase.lookupRecord (fnum, "Wisconsin", @holder)
ubase.closeFile (fnum)
dialog.alert ("Wisconsin's capital is " + holder.capi + ", abbreviation is " + holder.abbr + ".")
</code></pre><p>

See ubase.examples.checkStates for another example.<p>

<b>Visiting all the records in a database<p></b>

Use ubase.countRecords, ubase.getFirstRecord and ubase.getNextRecord. <p>

The records are not sorted. The first record is not necessarily the first record in alphabetic order. It would be much slower to return them in sorted order. Even so, visiting all the records in a database is not a fast operation when compared to a single call to ubase.lookupRecord.<p>

Here's an example that displays the names of all 50 states in Frontier's main window:
<code><pre>
local (ubasefolder, fnum, count, key, i)
ubase.launch ()
fnum = ubase.openFile (Frontier.pathstring + "States Database")
count = ubase.countRecords (fnum)
key = ubase.getFirstRecord (fnum)
for i = 1 to count 
msg (key)
key = ubase.getNextRecord (fnum, key)
ubase.closeFile (fnum)
</code></pre><p>

For another example, see ubase.examples.reportStates.<p>

<b>How uBASE is implemented<p></b>

Records are variable-length. There's no need to set a maximum length for string fields. Only the number of characters present in an individual field are stored in the database. The same is true for binary fields.<p>

Garbage collection is incremental, when you delete a record, uBASE attempts to merge it with adjacent free blocks. uBASE will re-use space released by deleted records, but the file will never decrease in size.<p>

uBASE is an ordinary Apple Event-aware Macintosh application.<p>

<b>Version 1.1b1 -- 1/4/96 DW<p></b>

uBASE now flushes the default volume after every addRecord, deleteRecord and addField call. Since uBASE often runs on web servers, and web servers sometimes crash, we need to be extra careful with the databases. People were working around this by closing and then re-opening the databases after every addRecord call. It should be faster than closing and reopening the file and safer against system crashes.<p>
</blockquote>

<h6>
<hr size=3>
<center>
<center><img src = "frondoc.gif" alt = "" align=center></center><p><p>&copy; copyright 1995-96 UserLand Software Inc. All rights reserved.<p>This page was last updated on Thu, Jan 4, 1996 at 10:51:58 AM. It was created with UserLand Software's <a href = "http://www.hotwired.com/userland/yabbadabba/">Clay Basket</a> website management software.This comment was generated by a <a href = "http://www.hotwired.com/userland/aretha/">Frontier</a> script.
</center>
<hr size=3>
</h6>

</body>

</html>
