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
- Writing an M2M Transformation
- Printing a Database Schema
- Constructing Schemas
- Creating a Database
- Reading a Database
- Reading a Table
- Reading Tuples of a Table and its Subtables
- Filtering Tuples from Tables
- Group By Queries
- Taking Cross Products of Schemas
- Table Joins
- Self Joins
- Reading and Writing Individual Prolog and CSV Tables
- Collecting Streamed tuples into a Table
- Copying data from a Tuple of one Schema to Another
- 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.txt
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:
- inputFileName -- the name of the input database (X.do.pl)
- outputFileName -- the name of the output database (X.pet.pl) or whatever is specified on the command line (e.g. output.txt)
- appName -- if "X.do.pl" is the input database, appName = "X".
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---