///|
fn mask_set(mask : Int32, attrs : Array[Int32]) -> Array[Int32] {
let out = []
for i in 0.. Array[Array[Int32]] raise DesignError {
let count = 1 << attrs.length()
budget.charge_product([count, attrs.length() + 1, attrs.length() + 1])
let out = []
// Cardinality order makes minimal-key filtering deterministic.
for size in 0..<=attrs.length() {
for mask in 0.. Array[Array[Int32]] raise DesignError {
let keys : Array[Array[Int32]] = []
for seed in subsets(attrs, budget) {
budget.charge(keys.length() + 1)
if keys.any(k => subset(k, seed)) {
continue
}
if subset(attrs, self.close(seed, budget)) {
budget.result(keys.length() + 1)
keys.push(seed)
}
}
keys
}
///|
pub fn Schema::candidate_keys(
self : Schema,
relation~ : Array[Int32] = [],
limits~ : Limits = default_limits(),
) -> Array[Array[Int32]] raise DesignError {
let attrs = if relation.is_empty() {
full(self.attribute_count())
} else {
indices(relation, self.attribute_count())
}
self.keys_of(attrs, meter(limits))
}
///|
pub fn Schema::is_superkey(
self : Schema,
seed : Array[Int32],
relation : Array[Int32],
limits~ : Limits = default_limits(),
) -> Bool raise DesignError {
let attrs = indices(relation, self.attribute_count())
let key = indices(seed, self.attribute_count())
if !subset(key, attrs) {
raise Invalid("key must be within relation")
}
subset(attrs, self.close(key, meter(limits)))
}
///|
pub fn Schema::is_candidate_key(
self : Schema,
seed : Array[Int32],
relation : Array[Int32],
limits~ : Limits = default_limits(),
) -> Bool raise DesignError {
let attrs = indices(relation, self.attribute_count())
let key = indices(seed, self.attribute_count())
if !subset(key, attrs) {
raise Invalid("key must be within relation")
}
let budget = meter(limits)
if !subset(attrs, self.close(key, budget)) {
return false
}
for a in key {
if subset(attrs, self.close(difference(key, [a]), budget)) {
return false
}
}
true
}
///|
pub fn Schema::prime_attributes(
self : Schema,
relation : Array[Int32],
limits~ : Limits = default_limits(),
) -> Array[Int32] raise DesignError {
let attrs = indices(relation, self.attribute_count())
let mut prime = []
for key in self.keys_of(attrs, meter(limits)) {
prime = union(prime, key)
}
prime
}
///|
pub fn Schema::essential_attributes(self : Schema) -> Array[Int32] {
let mut rhs = []
for fd in self.dependencies() {
rhs = union(rhs, difference(fd.right, fd.left))
}
difference(full(self.attribute_count()), rhs)
}
///|
pub(all) struct KeyProfile {
keys : Array[Array[Int32]]
prime : Array[Int32]
essential : Array[Int32]
minimum_width : Int32
maximum_width : Int32
} derive(Eq, Debug)
///|
pub fn Schema::key_profile(
self : Schema,
limits~ : Limits = default_limits(),
) -> KeyProfile raise DesignError {
let keys = self.keys_of(full(self.attribute_count()), meter(limits))
let mut prime = []
let mut minimum_width = self.attribute_count()
let mut maximum_width = 0
for key in keys {
prime = union(prime, key)
if key.length() < minimum_width {
minimum_width = key.length()
}
if key.length() > maximum_width {
maximum_width = key.length()
}
}
{
keys,
prime,
essential: self.essential_attributes(),
minimum_width,
maximum_width,
}
}
///|
pub extend KeyProfile with Eq::{equal, not_equal}
///|
pub extend KeyProfile with Debug::{to_repr}