-
Notifications
You must be signed in to change notification settings - Fork 18
Description
Case #240 showed how complex constraints could be expressed as queries. But you have to spend a few seconds reading each query to see which of them are unique and foreign key constraints. Therefore in this case we propose syntactic sugar.
Case 240 gave the example
val database = {parts, shipments, suppliers}
check (forall s in suppliers
require s.status >= 1 andalso s.status)
check (forall s in suppliers
require s.city = 'London' implies s.status = 20)
check (exists p in parts)
implies (exists p in parts where p.color = "Blue")
check (forall s1 in suppliers, s2 in suppliers
require s1.key = s2.key implies s1 = s2)
check (forall sp in shipments
require (exists s in suppliers where s.key = sp.skey))
check (forall s in suppliers, sp in shipments
require s.key = sp.skey
implies (s.status >= 20 orelse sp.quantity <= 500));Unique constraint
In the example, the unique key on suppliers is
check (forall s1 in suppliers, s2 in suppliers
require s1.key = s2.key implies s1 = s2)We propose unique(collection, keyExtractor) as a shorthand function:
check Relational.unique(suppliers, s => s.key)The signature is as follows:
unique : 'a collection * ('a -> 'b) -> bool(where collection is either list or bag)
and it desugars to the forall query as above.
Using a template syntax for lambdas similar to Scala, the syntax could be
check unique(suppliers, _.key)Foreign key constraint
In the example, the foreign key from shipments to suppliers is
check (forall sp in shipments
require (exists s in suppliers where s.key = sp.skey))We propose Relational.references(collection, foreignKeyExtractor, targetCollection, unqiueKeyExtractor) as a shorthand:
check references(shipments, fn s => s.key, suppliers, fn sp => sp.skey)Its signature is as follows:
references: 'a collection * ('a -> 'b) * 'b collection * ('c -> 'b) -> bool
(where each collection is either list or bag) and it desugars to the forall query as above.