MDELite Constraint Programs
Consider the following database. There is an m-n association between tables student and course. Association normalization creates a third table takes that pairs each student with each course that student takes.
dbase(sc,[course,student,takes]).
table(course,[cid,"name"]).
table(student,[sid,"name"]).
table(takes,[tid,cid,sid]).
There are many unique structural constraints to be verified in this database:
- No two students have the same name.
- Every takes tuple has a non-null student ID and a non-null course ID.
- Every takes tuple requires its student ID to correspond to a tuple in the student table; same for course ID.
- No takes (cid,sid) is duplicated.
But also some that are application specific:
- The compilers and database courses must have a minimum enrollment of 2 students.
- Every student should take one course.
The examples in this document illustrate how each of these constraints can be evaluated.
Remember, Java
Streams are stateless, so one has to create an operation that updates a
stateful object which retains the list of errors that have been
encountered. This is an ErrorReport object, whose usage is:
ErrorReport er = new ErrorReport();
... er.add("this is error1");
... er.add("this is error2");
er.printReportEH(System.out); // throw exception if errors are reported
Table of Contents
- Writing an MDELite Constraint Program
- Checking Unique Tuple IDs
- Checking Field Value Uniqueness Constraints
- Checking Non-Null Fields
- Checking Existence Constraints
- No Field-value Combinations are Duplicate
- Multi-Table Constraints
- Multi-Table Constraints -- Joins
1: Writing an MDELite Constraint Program
All MDELite Constraint-checking programs have the following prelude and structure:
---Check---
The first step is to read the command-line arguments. The Marquee4Conform does the work with the following arguments
- the Java class object, which is in this case DocCons.class
- the pattern of the databases to process, in this case ".school.pl" is the database suffix. (So accepted database file names are "X.school.pl")
- the command line arguments, which usualy is args.
Next, two values are extracted from the command-lines:
- inputFileName -- the name of the database file, typically of the form "blah/blah/Blah/X.school.pl"
- AppName -- if the above is the input file, then AppName = "X"
The second step is to open the database (inputFileName), extract the tables needed, and to create an error reporter to collect all discovered errors.
The third step is to evaluate constraints. The examples below show code fragments that implement common constraints.
The last statement of a Constraint checking program is one of the following:
- er.printReport(ps) -- print the error report to PrintStream ps; do not terminate program if errors are found
or more typically:
- er.printReportEH(ps)
-- like printReport(ps) above, except that a RuntimeException is thrown
if errors are found, halting any computation in which this constraint
program is run.
2: Checking Unique Tuple IDs
This
is a test that is generally unneeded, given that tuple IDs are
generated. Unique is a class whose
sole purpose is to register values and report duplicates and null values. A
standard use is verifying every course tuple has a unique ID.
---UniqueID---
3: Checking Field Value Uniqueness Constraints
Another common constraint is that a column should have unique values for each tuple in a table, such as no two students have the same name (and that names cannot be null). Again, a Unique report object is used for this task.
---UniqueName---
4: Checking Non-Null Fields
Every takes tuple has a non-null student ID and a non-null course ID. A single parameterized method, testNull, can be
used to verify that particular fields of a table are non-null.
---NonNull---
5: Checking Existence Constraints
An existence constraint asserts a tuple-id value in one table corresponds
to an existing tuple in another. Example: the student ID in each takes tuple corresponds to a tuple in the student table. Existence is checked by the exists method of MDELite.
---Existence---
6: No Field-Value Combinations are Duplicate
This
is a slight variation on unique field values. The trick is to
create a virtual field whose value is the concatenation of its
underlying multiple concrete fields. Here is how Constraint 4
could be written:
---UniqueCombo---
7: Multi-Table Constraints
Constraint 5 counts the number of takes (really student)
tuples enrolled in each database and compiler course and checks that at
least 2 students are enrolled. This is the first use of the
tuple.map() method which converts a tuple, 'this', into a subtable of
existing tuples to which it is related. The number of tuples in
this subtable is counted and tested whether or not it is < 2.
---attendance---
8: Multi-Table Constraints -- Joins
Constraint 6 joins tables student, takes, and courses
to evaluate a required condition that every student is enrolled in one
course. This constraint is complicated enough to have multiple
reasonable implementations. The first is:
---jConstraint---
The second is:
---jConstraint2---