TODO
* TODO:
* Create a module to allow methods to be added to existing Attribute objects
in such a way that the same methods can be easily mixed into other
things, like functions or relations.
* Replace the explicit mix-into-relation with something that adds the
methods to Axiom::Attribute::Relation, and then have Axiom::Relation
"inherit" those by declaring it's own relation methods as being of that
type.
* Move all Axiom::Algebra classes under Axiom::Relation::Operation
* Change Algebra::Extension#extensions to be a non-primtive
* May also change EvaluationContext#functions to return a set of functions.
* Add key minimization to Header
* When unioning two keys together it is really simple to end up
with indexes that overlap and cause an exception.
* Make Equalizer handle subclasses without having to specify the attribtues
again in each descendant.
* Allow Evaluator::Context to be used like:
relation.extend { new_extensions }
This will require the return value from the block to become useful.
* Add domain object for Extensions and Summarizers
* Add Evaluator::Context subclasses for Extensions and Summarizers, and return
those as instances rather than Hashes of attributes and functions.
* Convert Tuple to a Struct
* Make Header a "Struct Class", and copy all the Header instance methods to
the class level. Move all the Tuple instance methods into the Header
instance.
* Rename Header as Tuple
* Make sure the Tuple has a class level method called #header that returns
the set of attributes.
* Use a class variable to store each "Tuple class" so that anything with a
similar header will be reused.
* Remove Sorted, Reverse, Limit and Offset from the Relation inheritance chain
* Instead make it so they are proxy classes that wrap Relations, but
proxy method calls to the Relation methods, and then wrap the return
value (assuming it's a Relation) in a copy of itself.
* Also this will allow knowledge of #directions to be removed from
all the Relation classes. Only the Ranking classes will need to know
about directions.
* The Reverse class will probably not be needed either. All we need is
for the #reverse method to create a new Sorted with the directions
reversed.
* Remove the knowledge of directions from materialized relations
and instead wrap materialized relations in the Sorted object
if any.
* Update Attributes so that constraints are modelled using predicates,
so that when "join-ability" is tested, the predicates can just be
compared for equality.
* Create an object that can wrap a predicate, and if it fails it will
set the object's error state, and then propagate the status to the
caller. This will allow a "complex" predicate to set the errors
on tuples, while still allowing all the same objects to be used.
* Within the restriction context, make sure the attributes have aliases for:
* Alias #== to #eq (may break alot)
* Alias #!= to #ne (in 1.9 only)
* Alias #>= to #gte
* Alias #> to #gt
* Alias #<= to #lte
* Alias #< to #lt
* Alias #=~ to #match
* Within the sort_by context, make sure the attributes have aliases for:
* Alias #@+ to #asc
* Alias #@- to #desc
* Handle case where one attribute is required, and the other is not, when joined
(or other ops), the resulting attribute should always be required.
* In other operations, the resulting attribute may be something else, but will
need to research to know how to handle this.
* Current behaviour is to require both attributes are equivalent all the way
around to allow them to be joined. This constraint will need to be relaxed
to implement this new behaviour.
* Add operations for efficiently determining the following Enumerable properties
of a relation, when no block is provided:
* all?
* any?
* empty?
* one?
* none?
* many?
* include? / member?
* min / max / minmax (when the tuples are sorted)
* Add Axiom::Relation aggregate methods:
* count
* count(attribute)
* sum(attribute)
* minimum(attribute)
* maximum(attribute)
* mean(attribute)
* standard_deviation(attribute)
* variance(attribute)