Getting Started With ScriptDB

Sample scripts

You can find all the sample scripts discussed in this manual in the folder "Getting Started Scripts".

Each section indicates the name of the script that is relevant to that section.

The ScriptDB class

At the heart of Script DB lies a data class we call ScriptDB. ScriptDB is like a record that contains everything the scripting addition needs in order to perform database operations.

The ScriptDB class has three properties: DBName, DBFields and DBData.

DBName

The DBName property is a string that contains the name of the database.

 DBFields

The DBFields property contains a list of database fields. Each field is specified according to the ScriptDB Field class. It has a field name and a field type. The name is a string and the type is simply one of AppleScript's data classes. Currently ScriptDB Field support the following field types: String, Unicode, Real, Integer, Date and Boolean.

A typical field may be specified as follows: {"field name", string}. Once compiled, however, the ScriptDB class turns into a record: {DBFieldName: "field name", DBFieldClass: string}.

DBData

The DBData property contains the actual data. The DBData property is simply a list of lists. Each list inside DBData is a record in the database.

The commands

In order to make ScriptDB commands both easy to use and not conflict with other commands, we decided to start all of them with "DB". It may sound a bit funny at first, but it will grow on you. We also tried to make the commands sound as descriptive as possible. For instance, to sort a database, you use:

DB sort db the_script_db by the_sort_criteria

Since ScriptDB doesn't use a file to store the database, the ScriptDB class is all you have. For that reason, most commands will accept a ScriptDB as one of the parameters and return a new ScriptDB result. This means that if you want to sort a database stored in the variable my_db, for instance, you will use the following command:

set my_db to DB sort db my_db by {"first name"}

Or, to add records to a database, you will use:

set my_db to DB add records the_records_list to db my_db

This is a bit like doing this: set x to x + 1. You assign the result of an 0operation to a variable that is also used as one of the operands.

Creating a database

There are two ways to create a database: from file or from scratch. If you create a database from file, a single DB load command will supply both the fields and the data information. If you create a database to which you want to add records later on from the script itself, you can start by specifying the name and fields of the database, or you can also use the default DB name and start an empty database with no fields..

You can always add or remove fields after the database is created.

To create an empty database with the default name and a single field, use the db create command:

set my_db to DB create

Result:

my_db =

{class:ScriptDB, DBName:"SCRIPT_DB", DBFields:{{DBFieldClass:string, DBFieldName:"Field1"}}, DBData:{}}

Notice that the name used for the database is "SCRIPT_DB", and that there's a single field named "Field1" with a string class.

You can also start a database by specifying a name and fields. In the command below we create a database with the name "contacts" and with no fields:

set my_db to DB create with properties {DBName:"contacts", DBFields:{}}

Result:

my_db =

{class:ScriptDB, DBName:"contacts", DBFields:{}, DBData:{}}

Noticed that both the DBFields and DBData properties are empty lists.

We could start with a few fields, though. We will repeat the command but this time with an empty list for each field:

set my_db to DB create with properties {DBName:"contacts", DBFields:{{}, {}, {}}}

Result:

my_db =

{class:ScriptDB, DBName:"contacts", DBFields:{{DBFieldName:"Field1", DBFieldClass:string}, {DBFieldName:"Field2", DBFieldClass:string}, {DBFieldName:"Field3", DBFieldClass:string}}, DBData:{}}

Now, ScriptDB used its defaults: The fields are all of type string and are named "Fields1", "Field2", etc.

The following DB create command starts a database with two fields: name and age. This time, however, we will setup the fields earlier in a variable:

set my_fields to {{"name", string}, {"age", integer}}

set my_db to DB create with properties {DBName:"contacts", DBFields:my_fields}

Result:

my_db =

{class:ScriptDB, DBName:"contacts", DBFields:{{DBFieldName:"name", DBFieldClass:string}, {DBFieldName:"age", DBFieldClass:integer}}, DBData:{}}

Field names can't start with a dash or with a number, only an alpha character.

Adding records to the database

Next, we will add a few records to your database.

We will start by adding a single record. To do that, we will build on the contacts database we created above.

Add this line to the end of the script:

set my_db to DB add record {"George", 45} to db my_db

Result:

my_db =

{class:ScriptDB, DBName:"contacts", DBFields:{{DBFieldName:"name", DBFieldClass:string}, {DBFieldName:"age", DBFieldClass:integer}}, DBData:{{"George", 45}}}

To add a few (or many) records at the same time, use the db add records command with a list of lists. We will do that by first creating the list and assign it to a variable, and then add the list in the variable, like that:

set my_records to {{"George", 45}, {"Beth", 24}, {"Jack", 30}}

set my_db to DB add records my_records to db my_db

In reality, you will probably have your script create the records list.

You can easily get the number of fields or records in a certain database with these two commands:

set record_count to DB count records of db my_db

result: 3

set field_count to DB count fields of db my_db

result: 2

Sorting records

Now that we have a database with a few records we can sort them.

To sort the database we use the DB sort command followed by the field or fields you want to sort by..

You can specify the field you want to sort by using either the field name or number. You can also specify more than one field and specify whether you want the records sorted in ascending or descending order.

Sorting by one field

To sort the database stored in the my_db variable by the field "age", add the following line to your script:

set my_sorted_db to DB sort db my_db by "age"

Sorting by multiple fields

If you want to sort the database by one record first and then by another one, simply provide a list of the records:

set my_sorted_db to DB sort db my_db by {"age", "name"}

Sorting using field numbers

You can use the field numbers instead of their names:

set my_sorted_db to DB sort db my_db by {2, 1}

Sorting in descending order

To sort in descending order, add a minus sign before the field name or number:

set my_sorted_db to DB sort db my_db by {-2, 1}

or

set my_sorted_db to DB sort db my_db by {"-age", "name"}

Notice that the minus is inside the quotes.

Deleting records

There are a couple of ways to specify which records you want to remove from the database. The easiest way is by specifying the record number.

We will start from the eight-record database created in the sample script Deleting Records.

Specifying records in a list

To delete records by specifying numbers, use the 'number' parameter with the DB delete records command. In the following script we will delete record number 2:

set my_smaller_db to DB delete records from db my_db number 2

And here, we delete records 2 and 5 by using a list:

set my_smaller_db to DB delete records from db my_db number {2, 5}

Deleting record ranges

But, what if we want to delete records 2 through 5. Well, it would be nice to use the familiar AppleScript'thru' word, but unfortunately it can't be used in scripting additions. Instead, however, ScriptDB uses a string that allows you to mix non-consecutive ranges in a single delete command.

To delete records 2 through 5, use the following command:

set my_smaller_db to DB delete records from db my_db number "2-5"

If you really want to get fancy, you can mix commas and dashes to delete a few ranges at a time:

set my_smaller_db to DB delete records from db my_db number "1-3,5,7-8"

The script above deletes records 1, 2, 3, 5, 7 and 8

The nice thing here is that you can use AppleScript to create the 'number' parameter for you.

Specifying delete criteria

What if you don't know the numbers of the records you want to delete? For that, you can define the criteria you want ScriptDB to use for determining which records will be deleted.

ScriptDB uses a sophisticated parameter to allow you to pinpoint the records you want to delete. This 'where' parameter is the same one used to find records with the DB get data command, and is explained there in more detail.

Here are a couple of examples you can try.

The script below will delete all the records where the field "name" is "Olivia":

set my_smaller_db to DB delete records from db my_db where {"Field(name)", "=", "Olivia"}

The script below will delete all records where the field "age" is greater than 13

set my_smaller_db to DB delete records from db my_db where {"Field(age)", ">", "13"}

Updating a record

You can update a record in a database using the record number and the new data for the record.

The following line will replace the second record in the my_db database with the record indicated after the 'with data' parameter:

DB update record 2 in db my_db with data {"Beth", 25}

Finding records

To find records in a database you use the DB get data command.

This command can return one of three types of results: A database, a list of lists or the record numbers of the found fields.

There are a few ways for you to specify which data you want to get. You can restrict the search to a number of records, specify the fields you want to get data from, use a complex 'where' parameter, or a mix of any of the above.

We will start with a simple example.

The script below assumes that the variable my_db has the eight-record database we looked at earlier. This database has two fields: name and age.

You can find these examples in the 'Find and Get Data' example script.

Getting a range of records and fields

The scripts below allow you to get data from specific fields and specific record ranges.

set my_data to DB get data from db my_db in records "3-6"

result: {{"Jack", 30}, {"Olivia", 10}, {"Jordan", 15}, {"Sophia", 27}}

Now, we will just get the data from a certain field:

set my_data to DB get data from db my_db fields "age"

result: {45, 24, 30, 10, 15, 27, 3, 13}

Now, we will mix the two. We will get the field 'age' from records 3 through 6:

set my_data to DB get data from db my_db in records "3-6" fields "age"

result: {30, 10, 15, 27}

You can also use a number or list of numbers to specify the fields you want to use:

set my_data to DB get data from db my_db in records "3-6" fields {1, 3}

Transposing data

If we look at the result we got from the first DB get data command, it looked like this:

{{"Jack", 30}, {"Olivia", 10}, {"Jordan", 15}, {"Sophia", 27}}

Four lists, each is a record that has two items.

But what if instead, we want two lists, each with four items. We want a field's content in every list, not a record's content. All we have to do is include the 'transposed' parameter. By default, the transposed parameter is false.

Here's the command with the transposed parameter and the result you get:

set my_data to DB get data from db my_db in records "3-6" with transposed

result: {{"Jack", "Olivia", "Jordan", "Sophia"}, {30, 10, 15, 27}}

Using find criteria

Until now we just got data based on records and fields that we knew of in advance. Using the 'where' parameter you can specify real database searches.

The values you use in the 'where' parameter may appear to be a bit confusing at first. The reason for their structure has to do with both the scripting addition code restrictions and our strive to create the most open format that will allow you to create search parameters on the fly using AppleScript.

OK now, enough explaining, lets get going.

The following DB get data command will look for the record where the field "name" has the value "Olivia":

set my_data to DB get data from db my_db where {"Field(name)", "=", "Olivia"}

result: {"Olivia", 10}

But what if all we want is Olivia's age? Here's how we do that:

set my_data to DB get data from db my_db fields "age" where {"Field(name)", "=", "Olivia"}

result: {10}

Next, we will get the names of all people in our database who are between the ages of 10 and 18:

set my_data to DB get data from db my_db fields "name" where {"Field(age)", "³", 10, "AND", "Field(age)", "²", 18}

result: {"Olivia", "Jordan", "Harry"}

Getting the results in other forms

By default, the DB get data command will return a list of lists. You can use the 'as' parameter to request the result as a ScriptDB database or as a list or record numbers. Example:

set my_data to DB get data from db my_db where {"Field(name)", "=", "Olivia"} as row numbers

result: {4}

set my_data to DB get data from db my_db where {"Field(name)", "=", "Olivia"} as database

result:

{class:ScriptDB, DBName:"contacts", DBFields:{{DBFieldName:"name", DBFieldClass:string}, {DBFieldName:"age", DBFieldClass:integer}}, DBData:{{"Olivia", 10}}}

Adding and removing fields

To add fields to a database you need to supply the name and data type of the field you want to add. You may also supply the data for the new field in a form of a list and the default value to be used for unsupplied data.

The sample below can be found in the Adding and Removing Fields sample

Adding a field

In the first example we will add a 'member' field of type Boolean.

set new_field_specs to {"member", boolean}

set my_db to DB add field new_field_specs to db my_db

result:

{class:ScriptDB, DBName:"contacts", DBFields:{{DBFieldName:"name", DBFieldClass:string}, {DBFieldName:"age", DBFieldClass:integer}, {DBFieldName:"member", DBFieldClass:boolean}}, DBData:{{"Beth", 24, false}, {"Jack", 30, false}, {"Olivia", 10, false}, {"Pikachu", 3, false}, {"Harry", 13, false}}}

Notice that the default data used is false. To change the default, use the 'using default' parameter:

set my_db to DB add field new_field_specs to db my_db using default {true}

Note that the value 'true' is in a list just to prevent if from being seen as a Boolean value but rather as any value.

Using defaults is OK if we don't have the data, but if we do, we can use it right away.

Lets assume that we have a list of Booleans that we want to use as the data for the field:

set member_data_list to {true, true, false, true}

set my_db to DB add field new_field_specs to db my_db with data member_data_list

Removing a field

To remove a field we have to specify the field's name:

set my_db to DB remove field "member" from db my_db

Loading and saving database files

ScriptDB allows you to load databases from files and to save databases to files. ScriptDB uses two ASCII-based file formats for saving and loading databases: tab delimited text and XML.

For saving and later loading any database you create using AppleScript, you will want to use XML. When saved as XML, a database retains all of its attributes, including field names, field types and database name.

The tab-delimited format is mainly good for importing exiting text files and for greater compatibility with other applications.

The XML format is based on FileMaker Pro XML format. This allows ScriptDB to load FileMaker databases that were exported as XML, and for FileMaker Pro to import or open databases created with ScriptDB.

The script below will create a database, save it to a file, and later load it to another database:

-- create the database

set my_fields to {{"name", string}, {"age", integer}}

set my_db to DB create with properties {DBName:"contacts", DBFields:my_fields}

-- add records

set my_records to {{"Beth", 24}, {"Jack", 30}, {"Olivia", 10}, {"Pikachu", 3}, {"Harry", 13}}

set my_db to DB add records my_records to db my_db

-- save to file

set db_file_path to (path to desktop) & "database.txt" as string

DB save my_db to file db_file_path

The database is saved as XML by default. The contents of the XML file looks like this:

<?xml version="1.0" encoding="UTF-8"?><FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult"><ERRORCODE>0</ERRORCODE><PRODUCT BUILD="02/24/2004" NAME="Script DB" VERSION="1.01"/><DATABASE DATEFORMAT="yyyy/MM/dd" LAYOUT="" NAME="contacts" RECORDS="5" TIMEFORMAT="hh:mm:ss"/><METADATA><FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="name" TYPE="TEXT"/><FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="age" TYPE="NUMBER"/></METADATA><RESULTSET FOUND="5"><ROW MODID="1" RECORDID="1"><COL><DATA>Beth</DATA></COL><COL><DATA>24</DATA></COL></ROW><ROW MODID="1" RECORDID="2"><COL><DATA>Jack</DATA></COL><COL><DATA>30</DATA></COL></ROW><ROW MODID="1" RECORDID="3"><COL><DATA>Olivia</DATA></COL><COL><DATA>10</DATA></COL></ROW><ROW MODID="1" RECORDID="4"><COL><DATA>Pikachu</DATA></COL><COL><DATA>3</DATA></COL></ROW><ROW MODID="1" RECORDID="5"><COL><DATA>Harry</DATA></COL><COL><DATA>13</DATA></COL></ROW></RESULTSET></FMPXMLRESULT>

ScriptDB's XML format is compatible with FileMaker pro and therefore FileMaker Pro can open or import databases exported from ScriptDB as XML.

Exporting to XML requires the pro version of ScriptDB.

We could also choose to save the database as a tab delimited file, by using the as parameter, like this:

-- create the database

set my_fields to {{"name", string}, {"age", integer}}

set my_db to DB create with properties {DBName:"contacts", DBFields:my_fields}

-- add records

set my_records to {{"Beth", 24}, {"Jack", 30}, {"Olivia", 10}, {"Pikachu", 3}, {"Harry", 13}}

set my_db to DB add records my_records to db my_db

-- save to file

set db_tab_file_path to (path to desktop) & "database.txt" as string

DB save my_db to file db_tab_file_path format txt

-- load tab delimited to another database

set my_fields to {{"name", string}, {"age", integer}}

set new_db_2 to DB load file db_tab_file_path with properties {DBFields:my_fields} format txt

Notice that when we loaded the tab delimited text file back into a database, we redefined the database properties. If we wouldn't have done that, ScriptDB would have just used the default fields names (Field1, Field2, etc.) and assigned them all a text type.

When you save and load XML, all the settings are there for you.