Programs that Read and Write MDELite Databases


Start with these imports, not all of which are needed for every program below.  They represent the union required to run all demo programs.
---imports---
Later we will use the dog-owner database, shown below:
:::test/DML/PrologDB/TestData/dogOwner.do.pl:::
Table of Contents
  1. Writing an M2M Transformation
  2. Printing a Database Schema
  3. Constructing Schemas
  4. Creating a Database
  5. Reading a Database
  6. Reading a Table
  7. Reading Tuples of a Table and its Subtables
  8. Filtering Tuples from Tables
  9. Group By Queries
  10. Taking Cross Products of Schemas
  11. Table Joins
  12. Self Joins
  13. Reading and Writing Individual Prolog and CSV Tables
  14. Collecting Streamed tuples into a Table
  15. Copying data from a Tuple of one Schema to Another
  16. Sorting Tables

1: Writing a M2M Transformation

All MDELite Model-to-Model (or database-to-database) transformation programs have the following prelude and structure:
---tmplate---
The first step executes boilerplate code to process the command line.  This particular M2M program translates ".do.pl" database to ".pet.pl" databases.  That is, to invoke the above program you would type:
> java DocExamplesTest  X.do.pl
or
> java DocExamplesTest X.do.pl output.tx
t
The first call will produce pet database file X.pet.pl.  That is, given X.do.pl as input, the translated database will be named X.pet.pl. The second call will ignore the standard output (X.pet.pl) and will produce its contents in file output.txt. Other points worth noting are variables:
The second step reads the input database (whose name is in variable inputFileName), and extracts its tables.

The third step is to read the schema for the pet database, in this case it is file "pet.schema.pl" which is local file or a file that is hardwired to a particular directory.  It is also possible to hardwire the contents of a schema as amultiline String which is in the program itself.  To do this, use:
String defOfSchema = "dbase(a,[b,c]).\ntable(b,[id,x,y]).\ntable(c,[z]).\nsubtable(b,[c]).";
DBSchema sch = DBSchema.readSchema("a",defOfSchema);
Also part of the third step is to create an empty pet database.

The rest of the program is code to translate a ".do.pl" database into a pet database.  The end of the program writes the produced database to its output file.

The following examples illustrate how to read, write, and create MDELite databases.

2: Printing a Database Schema

This program takes an ooschema declaration and flattens it into a schema declaration.  The distinction between ooschemas and schemas is that attributes of supertables are propagated to each of its subtables, recursively.  The program prints a database schema one table at a time.  Printing subtable declarations of the database conclude the program.
---printSchema--- 
Here is the output of this program:
:::test/DML/PrologDB/Correct/printSchema.txt:::

3: Constructing Schemas

This program creates a starTrek ooschema programmatically and prints it out using standard utilities.  Different ways of creating a table schema are shown.
---schemaBuild---

4: Creating a Database

This program creates the enterprise database which has 3 tuples, one tuple per table.  An ooschema for the database is created and then converted into a true schema (shown above).  At this point, a database instance of the schema can be created, one table and one tuple at a time.  Different ways of creating a tuple are shown.
---DBBuild--- 
Here is the output of this program:
:::test/DML/PrologDB/Correct/dbBuild.txt:::

5: Reading a Database

This program reads a database given its file, prints the database using available utilities and also a harder way by extracting out its individual tables and printing its tuples.
---DBread--- 
Here is the output of this program:
:::test/DML/PrologDB/Correct/dbread.txt:::

6: Reading a Table

This program reads a dog-owner database, which has a table of dogs.  Using Java Streams, the stream of all aussie (Australian Shepherd) tuples is created and then printed.  A similar stream is reconstituted (remember: once you use a stream, it's done and has to be recreated) and then filtered further, and printed.
---TableRetrieve---

7: Reading Tuples of a Table and its Subtables

This program reads the tuples of the table pet and all of its subtables.  If you want to retrieve tuples of only that table (and not its subtables), use the getLocalTuples() method.  A couple queries are illustrated.  
---InheritanceRetrieve--- 

8:  Filtering Tuples from Tables

This program illustrates several ways in which you can filter tuples from tables.   The first uses a loop with an if-statement.  The second creates a stream of tuples that are filtered and printed. The third creates a table of only filtered tuples that is then printed.  The only difference between the latter two is that stream implementations process one tuple at a time as opposed to one table at a time.
---filter---
Here is the output of this program:
:::test/DML/PrologDB/Correct/ftest.txt:::

9: Group By Queries

This program illustrates group-by facilities.  A table is "grouped by" a particular column, producing a stream of subtables (of the same type as the original table) containing all tuples that have the same column value. 
---GroupBy---

10: Taking Cross Products of SchemasCopying data from a Tuple of one Schema to Another

Table joins take cross products of schemas automatically.  Occasionally you might need to do this yourself.  The following program illustrates how cross products of schemas are taken and printed.
---crossSchema--- 
Here is the output of this program:
:::test/DML/PrologDB/Correct/cross.txt:::

11: Table Joins

This program reads a dog-owner database, finds the dog, when, and owner tables, joins the dog table with the when table over dog.did = when.did join predicate (i.e., the did columns of both tuples must have the same value) to produce a new table dogXwhen.  

Note: the attributes of the joined relation are renamed.  What used to be attribute T in the dog table is now renamed dog.T.  Same for all other attributes, so that one can always distinguish attributes with similar names. Continuing, this table is printed, and then it is joined with the owner table over predicate when.oid = owner.oid, and then the table is printed out.
---TableJoins--- 
Here is the output of this program:
:::test/DML/PrologDB/Correct/join.txt:::

12: Self Joins

Here is a program that joins the dog table with itself over dog identifiers (did).  The key to self-joins is that a copy of a table for each self-join must be made.  If a dog table is to be joined with itself, the dog table is really joined with a copy.  If a dog table is to be joined with itself, followed by itself, the dog table and two distinct copies of the dog table must be joined.  Now, this particular example, of joining a dog table with itself isn't particularly useful, but when you have a table that encodes (parent, child) relationships, joining such tables multiple times allows you to relate parents to grandchildren, and so on.
---SelfJoins---

13:  Reading and Writing Individual Prolog and CSV Tables

You can read and write individual tables, either in the standard Prolog format or as a CSV (comma separated value) file.  The name of the file (whether it ends or not in ".csv") determines whether the file is to be read/written as a CSV file.
---csvfile---
Here is the simple.csv file -- all CSV tables are assumed to have quoted attributes (and hence quoted values):
:::test/DML/PrologDB/TestData/simple.csv:::
And here it's Prolog formatted output:
:::test/DML/PrologDB/Correct/simple.pl:::
And what it looks like written out:
:::test/DML/PrologDB/TestData/simple.csv:::

14: Collecting Streamed Tuples into a Table

This program shows how a stream of tuples can be collected into table, and then the collected table is compared with the original (and found to be the same).
---toTable---

15: Copying Data from a Tuple of one Schema to Another

A common task is copying data from one tuple of one schema to a tuple of another.  It's not hard, but tedious.  Look at the first step of the code below -- it is a series of assignment statements.  The second step defines a ColumnCorrespondence among the fields of the left schema with fields or computations in the right.  Not all fields of the left schema need be considered/updated in a correspondence.  Also, when a correspondence is defined, it can be subsequently changed by adding and deleting column correspondences.
---corresp---
As an aside, the manual way has a debug option that tests if a tuple is complete -- this means that a tuple has its full complement of column-value pairs.  In this example all longhorn tuples do.  If a tuple is incomplete, an RuntimeException is thrown if not all attributes of a tuple have values.  This is a way that you can debug a program -- and once you're convinced you have all columns, you can remove the isComplete test.

16: Sorting Tables

Sorting is obvious.  Let T be a table with column "key".  What does T.sort("key") produce? Clearly a sorted table.  But do we want a sorted copy of T to be output, or do we want T itself to be sorted?  That's the purpose of sort(table,boolean).  If the boolean is true, the input table is updated by being sorted.  If false, a sorted copy of T is produced.
---sort---