pub struct Relation { /* private fields */ }Expand description
Represents a relation with a heading and a set of tuples.
§Example
use darwen::prelude::{AttributeName, HeadingBuilder, Relation, ScalarType};
let relation = Relation::new(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
);
assert_eq!(
relation,
Relation::new_from_iter(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
Vec::new(),
)?,
);Implementations§
Source§impl Relation
impl Relation
Sourcepub fn difference(&self, other: &Relation) -> Result<Relation, Error>
pub fn difference(&self, other: &Relation) -> Result<Relation, Error>
Returns tuples that exist in self but not in other (−).
a
value |
|---|
1 |
2 |
3 |
b
value |
|---|
2 |
Output
value |
|---|
1 |
3 |
§Errors
Returns Error::HeadingMismatch if the relations do not have the same
heading.
§Example
use darwen::prelude::{AttributeName, Heading, Relation, Scalar, ScalarType, Tuple};
let a = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(3))])?,
],
)?;
let b = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?],
)?;
let difference = a.difference(&b)?;
assert_eq!(
difference,
Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(3))])?,
],
)?
);Source§impl Relation
impl Relation
Sourcepub fn divide(&self, other: &Relation) -> Result<Relation, Error>
pub fn divide(&self, other: &Relation) -> Result<Relation, Error>
Divides one relation by another (÷).
students
name | course |
|---|---|
Alice | Rust |
Alice | Math |
Bob | Rust |
Bob | Math |
Ann | Math |
courses
course |
|---|
Rust |
Math |
Output
name |
|---|
Alice |
Bob |
§Errors
Returns Error::HeadingMismatch if the divisor heading is not a
subset of the dividend heading.
§Example
use darwen::{
heading,
tuple,
prelude::{RelationBuilder, ScalarType},
};
let students = RelationBuilder::new()
.with_heading(heading!(name = ScalarType::String, course = ScalarType::String)?)
.with_body(vec![
tuple!(name = "Alice", course = "Rust")?,
tuple!(name = "Alice", course = "Math")?,
tuple!(name = "Bob", course = "Rust")?,
tuple!(name = "Bob", course = "Math")?,
tuple!(name = "Ann", course = "Math")?,
])
.build()?;
let courses = RelationBuilder::new()
.with_heading(heading!(course = ScalarType::String)?)
.with_body(vec![
tuple!(course = "Rust")?,
tuple!(course = "Math")?,
])
.build()?;
let result = students.divide(&courses)?;
let expected = RelationBuilder::new()
.with_heading(heading!(name = ScalarType::String)?)
.with_body(vec![
tuple!(name = "Alice")?,
tuple!(name = "Bob")?,
])
.build()?;
assert_eq!(result, expected);Source§impl Relation
impl Relation
Sourcepub fn intersect(&self, other: &Relation) -> Result<Relation, Error>
pub fn intersect(&self, other: &Relation) -> Result<Relation, Error>
Returns tuples common to both relations (∩).
a
value |
|---|
1 |
2 |
b
value |
|---|
2 |
3 |
Output
value |
|---|
2 |
§Errors
Returns Error::HeadingMismatch if the relations do not have the same
heading.
§Example
use darwen::prelude::{AttributeName, Heading, Relation, Scalar, ScalarType, Tuple};
let a = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
],
)?;
let b = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(3))])?,
],
)?;
let intersection = a.intersect(&b)?;
assert_eq!(
intersection,
Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?],
)?
);Source§impl Relation
impl Relation
Sourcepub fn join(&self, other: &Relation) -> Result<Relation, Error>
pub fn join(&self, other: &Relation) -> Result<Relation, Error>
Performs a natural join on attributes shared by both relations (⋈).
users
id | score |
|---|---|
1 | 10 |
2 | 20 |
cities
id | level |
|---|---|
1 | 100 |
3 | 300 |
Output
id | score | level |
|---|---|---|
1 | 10 | 100 |
§Errors
Returns Error::ScalarTypeMismatch if shared attribute names exist in
both relations with different scalar types.
§Example
use darwen::prelude::{AttributeName, Heading, Relation, Scalar, ScalarType, Tuple};
let users = Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("score"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("score"), Scalar::Integer(10)),
])?,
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(2)),
(AttributeName::from("score"), Scalar::Integer(20)),
])?,
],
)?;
let cities = Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("level"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("level"), Scalar::Integer(100)),
])?,
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(3)),
(AttributeName::from("level"), Scalar::Integer(300)),
])?,
],
)?;
let users_with_levels = users.join(&cities)?;
assert_eq!(
users_with_levels,
Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("score"), ScalarType::Integer),
(AttributeName::from("level"), ScalarType::Integer),
])?,
vec![Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("score"), Scalar::Integer(10)),
(AttributeName::from("level"), Scalar::Integer(100)),
])?],
)?
);Source§impl Relation
impl Relation
Sourcepub fn product(&self, other: &Relation) -> Result<Relation, Error>
pub fn product(&self, other: &Relation) -> Result<Relation, Error>
Returns the Cartesian product of two relations (×).
colors
left |
|---|
1 |
2 |
sizes
right |
|---|
10 |
20 |
Output
left | right |
|---|---|
1 | 10 |
1 | 20 |
2 | 10 |
2 | 20 |
§Errors
Returns Error::AttributeAlreadyExists if both relations contain the
same attribute name, making the Cartesian product ambiguous.
§Example
use darwen::prelude::{AttributeName, Heading, Relation, Scalar, ScalarType, Tuple};
let colors = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("left"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("left"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("left"), Scalar::Integer(2))])?,
],
)?;
let sizes = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("right"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("right"), Scalar::Integer(10))])?,
Tuple::try_from(vec![(AttributeName::from("right"), Scalar::Integer(20))])?,
],
)?;
let combinations = colors.product(&sizes)?;
assert_eq!(
combinations,
Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("left"), ScalarType::Integer),
(AttributeName::from("right"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("left"), Scalar::Integer(1)),
(AttributeName::from("right"), Scalar::Integer(10)),
])?,
Tuple::try_from(vec![
(AttributeName::from("left"), Scalar::Integer(1)),
(AttributeName::from("right"), Scalar::Integer(20)),
])?,
Tuple::try_from(vec![
(AttributeName::from("left"), Scalar::Integer(2)),
(AttributeName::from("right"), Scalar::Integer(10)),
])?,
Tuple::try_from(vec![
(AttributeName::from("left"), Scalar::Integer(2)),
(AttributeName::from("right"), Scalar::Integer(20)),
])?,
],
)?
);Source§impl Relation
impl Relation
Sourcepub fn project(&self, attributes: &[AttributeName]) -> Result<Relation, Error>
pub fn project(&self, attributes: &[AttributeName]) -> Result<Relation, Error>
Projects a relation onto a subset of attributes (π).
people
id | age |
|---|---|
1 | 19 |
2 | 24 |
Output
id |
|---|
1 |
2 |
§Errors
Returns Error::AttributeNotFound if one of the requested attributes
does not exist in the relation heading.
Returns Error::AttributeAlreadyExists if the projection list repeats
the same attribute name more than once.
§Example
use darwen::prelude::{
AttributeName, Heading, Relation, Scalar, ScalarType, Tuple,
};
let people = Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("age"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("age"), Scalar::Integer(19)),
])?,
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(2)),
(AttributeName::from("age"), Scalar::Integer(24)),
])?,
],
)?;
let ids = people.project(&[AttributeName::from("id")])?;
assert_eq!(
ids,
Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("id"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("id"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("id"), Scalar::Integer(2))])?,
],
)?
);Source§impl Relation
impl Relation
Sourcepub fn rename(
&self,
mapping: &[(AttributeName, AttributeName)],
) -> Result<Relation, Error>
pub fn rename( &self, mapping: &[(AttributeName, AttributeName)], ) -> Result<Relation, Error>
Renames relation attributes according to a mapping (ρ).
people
id | age |
|---|---|
1 | 19 |
2 | 24 |
Output
user_id | age |
|---|---|
1 | 19 |
2 | 24 |
§Errors
Returns Error::AttributeNotFound if the rename mapping references an
unknown attribute.
Returns Error::InvalidRenameMapping if the rename mapping repeats
the same source attribute.
Returns Error::AttributeAlreadyExists if the rename result would
produce duplicate target names.
§Example
use darwen::prelude::{
AttributeName, Heading, Relation, Scalar, ScalarType, Tuple,
};
let people = Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("age"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("age"), Scalar::Integer(19)),
])?,
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(2)),
(AttributeName::from("age"), Scalar::Integer(24)),
])?,
],
)?;
let renamed_people = people.rename(&[(
AttributeName::from("id"),
AttributeName::from("user_id"),
)])?;
assert_eq!(
renamed_people,
Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("user_id"), ScalarType::Integer),
(AttributeName::from("age"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("user_id"), Scalar::Integer(1)),
(AttributeName::from("age"), Scalar::Integer(19)),
])?,
Tuple::try_from(vec![
(AttributeName::from("user_id"), Scalar::Integer(2)),
(AttributeName::from("age"), Scalar::Integer(24)),
])?,
],
)?
);Examples found in repository?
18fn main() {
19 let contacts = contacts();
20
21 println!(
22 "{}",
23 contacts
24 .rename(&[(
25 AttributeName::from("phone"),
26 AttributeName::from("red_phone")
27 )])
28 .unwrap()
29 );
30}Source§impl Relation
impl Relation
Sourcepub fn restrict(&self, predicate: &Predicate) -> Result<Relation, Error>
pub fn restrict(&self, predicate: &Predicate) -> Result<Relation, Error>
Restricts a relation to tuples that satisfy a predicate (σ).
people
id | age |
|---|---|
1 | 19 |
2 | 24 |
Output
id | age |
|---|---|
2 | 24 |
§Errors
Returns Error::AttributeNotFound if the predicate references an
attribute that does not exist in the relation tuples.
Returns Error::ScalarTypeMismatch if the predicate uses Eq to
compare values of different scalar types.
Returns Error::NonComparableTypes if the predicate uses < or >
with non-integer operands.
§Example
use darwen::prelude::{
AttributeName, Heading, Predicate, Relation, Scalar, ScalarType, Tuple,
};
let people = Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("age"), ScalarType::Integer),
])?,
vec![
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(1)),
(AttributeName::from("age"), Scalar::Integer(19)),
])?,
Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(2)),
(AttributeName::from("age"), Scalar::Integer(24)),
])?,
],
)?;
let adults = people.restrict(&Predicate::eq(
AttributeName::from("age"),
Scalar::Integer(24),
))?;
assert_eq!(
adults,
Relation::new_from_iter(
Heading::try_from(vec![
(AttributeName::from("id"), ScalarType::Integer),
(AttributeName::from("age"), ScalarType::Integer),
])?,
vec![Tuple::try_from(vec![
(AttributeName::from("id"), Scalar::Integer(2)),
(AttributeName::from("age"), Scalar::Integer(24)),
])?],
)?
);Examples found in repository?
More examples
22fn main() {
23 let users = users();
24
25 println!(
26 "{}",
27 users
28 .restrict(&Predicate::gt(
29 Expression::Attribute(AttributeName::from("age")),
30 Expression::Const(Scalar::Integer(20))
31 ))
32 .unwrap()
33 )
34}Source§impl Relation
impl Relation
Sourcepub fn union(&self, other: &Relation) -> Result<Relation, Error>
pub fn union(&self, other: &Relation) -> Result<Relation, Error>
Returns the union of two compatible relations (⋃).
a
value |
|---|
1 |
2 |
b
value |
|---|
2 |
3 |
Output
value |
|---|
1 |
2 |
3 |
§Errors
Returns Error::HeadingMismatch if the relations do not have the same
heading.
§Example
use darwen::prelude::{AttributeName, Heading, Relation, Scalar, ScalarType, Tuple};
let a = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
],
)?;
let b = Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(3))])?,
],
)?;
let union = a.union(&b)?;
assert_eq!(
union,
Relation::new_from_iter(
Heading::try_from(vec![(AttributeName::from("value"), ScalarType::Integer)])?,
vec![
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(1))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(2))])?,
Tuple::try_from(vec![(AttributeName::from("value"), Scalar::Integer(3))])?,
],
)?
);Source§impl Relation
impl Relation
Sourcepub fn new(heading: Heading) -> Self
pub fn new(heading: Heading) -> Self
Creates an empty relation with the given heading.
§Example
use darwen::prelude::{AttributeName, HeadingBuilder, Relation, ScalarType};
let relation = Relation::new(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
);
assert_eq!(
relation,
Relation::new_from_iter(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
Vec::new(),
)?,
);Sourcepub fn new_from_iter<T>(heading: Heading, body: T) -> Result<Self, Error>where
T: IntoIterator<Item = Tuple>,
pub fn new_from_iter<T>(heading: Heading, body: T) -> Result<Self, Error>where
T: IntoIterator<Item = Tuple>,
Builds a relation from a heading and an iterator of tuples.
§Example
use darwen::prelude::{
AttributeName, HeadingBuilder, Relation, Scalar, ScalarType, TupleBuilder,
};
let relation = Relation::new_from_iter(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
vec![
TupleBuilder::new()
.with_value(AttributeName::from("id"), Scalar::Integer(1))
.build()?,
],
)?;
let _ = relation;§Errors
Returns Error::InvalidWidth if any tuple has a different arity than
the provided heading degree.
Returns Error::AttributeNotFound if any tuple is missing an
attribute required by the provided heading.
Returns Error::ScalarTypeMismatch if any tuple contains a value with
a different scalar type than the provided heading requires.
Sourcepub fn insert(&mut self, tuple: Tuple) -> Result<(), Error>
pub fn insert(&mut self, tuple: Tuple) -> Result<(), Error>
Inserts a tuple into the relation.
§Example
use darwen::prelude::{
AttributeName, HeadingBuilder, Relation, Scalar, ScalarType, TupleBuilder,
};
let mut relation = Relation::new(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
);
relation.insert(
TupleBuilder::new()
.with_value(AttributeName::from("id"), Scalar::Integer(1))
.build()?,
)?;
assert_eq!(
relation,
Relation::new_from_iter(
HeadingBuilder::new()
.with_attribute(AttributeName::from("id"), ScalarType::Integer)
.build()?,
vec![
TupleBuilder::new()
.with_value(AttributeName::from("id"), Scalar::Integer(1))
.build()?,
],
)?,
);§Errors
Returns Error::InvalidWidth if the tuple arity does not match the
relation heading degree.
Returns Error::AttributeNotFound if the tuple is missing an
attribute required by the relation heading.
Returns Error::ScalarTypeMismatch if the tuple contains a value with
a different scalar type than the relation heading requires.
Sourcepub fn iter(&self) -> impl Iterator<Item = &Tuple>
pub fn iter(&self) -> impl Iterator<Item = &Tuple>
Iterates over relation tuples in key order.
§Example
use darwen::{
heading,
tuple,
prelude::{RelationBuilder, ScalarType},
};
let relation = RelationBuilder::new()
.with_heading(heading!(id = ScalarType::Integer)?)
.with_body(vec![
tuple!(id = 2)?,
tuple!(id = 1)?,
])
.build()?;
let tuples = relation.iter().cloned().collect::<Vec<_>>();
assert_eq!(tuples.len(), 2);
assert_eq!(tuples[0], tuple!(id = 1)?);
assert_eq!(tuples[1], tuple!(id = 2)?);