Chapter 35. Theon’ifying the "World"

This recipe will run through the process of converting to Theon management the World demonstration database. This example will assume that it will be a personal database so that Theon can be added as an extension module to the live database.

This recipe can be run from anywhere on a machine with the necessary packages installed and suitable configuration of PostgreSQL (see configuration recipe).

(1) Download World and build the sample database.

cd /tmp
wget http://pgfoundry.org/frs/download.php/527/world-1.0.tar.gz
tar zxvf world-1.0.tar.gz
createdb world
psql world < dbsamples-0.1/world/world.sql

(2) Install Theon Schema Management into the World database as an extension module. First pre-requisite extensions need installed. These must be installed in the public schema (default).

psql world -c "CREATE EXTENSION dblink;"
psql world -c "CREATE EXTENSION file_fdw;"
psql world -c "CREATE EXTENSION pgcrypto;"
psql world -c "CREATE EXTENSION \"uuid-ossp\";"

Now install the Theon extension module. The schema search path must include public when running this, however subsequently this is no longer necessary.

psql world -c "CREATE EXTENSION theon;"

(3) Start a new ModelLibrary to represent World within Theon.

ttkm world launch at .

(4) Change into the created ModelLibrary directory so we don’t need to prefix actions with the relevant model name.

cd world

(5) Create a suitable custom LiveProfile to use for connecting to the Theon Schema Management catalog within the World database. We will call this world to keep things consistent. Within the World database the Theon extension will have been installed under the theon schema so this needs specified in the connnection options.

This is a bit chicken and egg as we need a Theon Schema Management catalog in order to create a LiveProfile for a Theon Schema Management catalog. So first create the default standard one in its own database, create the custom profile for the one embedded in our *World" database, then remove it. Note that create and delete actions below are destructive and we are assuming there is not one already in use (in which case the create and delete actions would not be necessary).

ttkm create aok
ttkm self attach upon world using database=world host=/disk/scratch schema=theon
ttkm delete aok

(6) Now we can use our own Theon* Schema Management catalog within the World database to create a suitable default LiveProfile to use for connecting to the World database itself. We have to specify the LiveProfile to use for our own Theon* Schema Management catalog.

ttkm attach using database=world host=/disk/scratch self=world

(7) Set default LiveProfile for the ModelLibrary. We do this so that whenever we use this ModelLibrary for managaing World we don’t have to always specify the LiveProfile for the Theon Schema Management catalog (as in doing self=world above) and instead the LiveProfile associated with the ModelLibrary is used as the default. This is done by a configuration option so (re)launch in order to set this.

ttkm launch using theon=world

(8) Load the existing World database schema into Theon.

ttkm import

(9) Export the SchemaTree for world.

ttkm export

This will create content in the schemat directory.

(10) Now we can do a test build of another World database from our SchemaTree. This will be a "managed" instance as it will contain the current SchemaTree for the model within it. Will call this OtherWorld. First derive the installation DDL.

ttkm derive ddl

This will put content in "derived/model/ddl". Now create an alternative LiveProfile for the new database.

ttkm attach upon otherworld using database=otherworld host=/disk/scratch

Install the new database.

ttkm install upon otherworld

(11) Now lets make a live change in World and then upgrade OtherWorld so it corresponds. First make the change.

psql world -c "ALTER TABLE city ADD COLUMN area FLOAT;"

Re-import, export.

ttkm import
ttkm export

Now do the upgrade. This will build a "differential DDL" between the SchemaTree in OtherWorld and the SchemaTree we have just exported from World and then apply that.

ttkm upgrade upon otherworld aok

Note that there are considerable limitations in what upgrade natively supports doing, see Appendix. Where operations are not supported install must be used instead with, if necessary, manual data dump/restore.

(12) Now will make a similar change via the UI and upgrade OtherWorld. First start the UI server, but at the moment we need to handcraft a suitable config file that points at the Theon Schema Management Database" in *World.

cat >ui.conf <<EOF
config = {
  "session_secure": False,
  "database" : {
    "dbname" : "world",
    "host" : "/disk/scratch",
    "options" : "--search_path=theon"
  },
  "metadata" : {
    "/api": [ "/usr/share/theon/self/ui/data", ],
  }
}
EOF
ttkm self server ui using config=ui.conf

Navigate a locally running browser to localhost:8000 and follow the following steps to add a column.

Open the "Dictionary" desktop.
On the first panel ("Model") ensure the right model is shown.
Open the "Entity" panel.
Query for the "city" record.
Add the following rows in the "Attributes" box:
  Position      Name[Realised]  Type    Content
  7             lastupdate      Column  Date/Time

Control-C the server process.

Export the changes, do the upgrade and check.

ttkm export
ttkm upgrade upon otherworld aok
psql otherworld -c "\d city"

(13) Note that the original database World will now be inconsistent as the change has not been applied to that (the previous change was made live and imported so it was unnecessary to run an upgrade, and in fact would have caused an error as the change had already been made). We cannot just upgrade World as it was not installed as a Theon managed database, so we should turn it into that now so that it can then always be upgraded in-situ from changes made by the UI and hence the SchemaTree. One way would be to simply destroy it and then install it again from Theon then add the theon extension. Below is an example of not doing this. The process is to simply apply the upgrade for OtherWorld to World to make it consistent - by doing the upgrade it will be converted into a Theon managed database (the upgrade needs to apply some kind of change, but we have this through the added column above). First we need to make a clean SchemaTree to update from, so we need to remove the column we added in the UI and export this to a temporary location.

ttkm self server ui using config=ui.conf

Navigate a locally running browser to localhost:8000 and follow the following steps to add a column.

Open the "Dictionary" desktop.
On the first panel ("Model") ensure the right model is shown.
Open the "Entity" panel.
Query for the "city" record.
Delete the following row from the "Attributes" box:
  Position      Name[Realised]  Type    Content
  7             lastupdate      Column  Date/Time

Create a temporary new ModelLibrary to contain the current state.

ttkm launch into /tmp/oldworld

Export the current state into the temporary ModelLibrary.

ttkm export into /tmp/oldworld

Upgrade World by comoparing the above original SchemaTree to the current one which was set after the previous change. This will add the column and also add the Theon meta data so that World can be managed directly in the future (checked below).

ttkm upgrade using current=/tmp/oldworld
psql world -c "\d _th_theon"

Now re-import, re-export and do a schema diff check for reassurance.

ttkm import
ttkm export
diff -qr schemat /tmp/oldworld/schemat

(14) Build the UI data, connect and browse.

ttkm derive ui
cat >world.conf <<EOF
config = {
  "session_secure": False,
  "database" : {
    "dbname" : "world",
    "host" : "/disk/scratch",
  },
  "metadata" : {
    "/api": [ "/tmp/world/derived/ui/data", ],
  }
}
EOF
ttkm server ui using config=world.conf

Navigate a locally running browser to localhost:8000 and choose the Browser to peruse table content.