Data modeling & Iterator creation

As part of my Master's thesis, I'm arguing that the problems that tree-structured databases had also affect in-memory data layout. To show this, I've translated the example Codd used in his relational algebra paper into Rust. It consists of five different data models of the same problem, and a single query method for each.

The more idiomatic the implementations are, the better. Does anyone have thoughts on how this could be improved?

pub struct QueryResult {
    part_id: usize,
    part_name: String,
    quantity_committed: usize,
}

/// Projects subordinate to parts
mod struct1 {
    use super::QueryResult;
    use std::collections::BTreeMap;

    struct Part {
        id: usize,
        name: String,
        description: String,
        quantity_on_hand: usize,
        quantity_on_order: usize,
        projects: BTreeMap<usize, Project>,
    }

    struct Project {
        id: usize,
        name: String,
        description: String,
        quantity_committed: usize,
    }

    pub struct Inventory(BTreeMap<usize, Part>);

    impl Inventory {
        pub fn query_parts_by_project_name<'a>(
            &'a self,
            project: &'a str,
        ) -> impl Iterator<Item = QueryResult> + 'a {
            self.0.values().flat_map(move |part| {
                part.projects
                    .values()
                    .filter(move |proj| proj.name == project)
                    .map(move |proj| QueryResult {
                        part_id: part.id,
                        part_name: part.name.clone(),
                        quantity_committed: proj.quantity_committed,
                    })
            })
        }
    }
}

/// Parts subordinate to projects
mod struct2 {
    use super::QueryResult;
    use std::collections::BTreeMap;

    struct Project {
        id: usize,
        name: String,
        description: String,
        parts: BTreeMap<usize, Part>,
    }

    struct Part {
        id: usize,
        name: String,
        description: String,
        quantity_on_hand: usize,
        quantity_on_order: usize,
        quantity_committed: usize,
    }

    pub struct Inventory(BTreeMap<usize, Project>);

    impl Inventory {
        pub fn query_parts_by_project_name<'a>(
            &'a self,
            project: &'a str,
        ) -> impl Iterator<Item = QueryResult> + 'a {
            self.0
                .values()
                .filter(move |proj| proj.name == project)
                .flat_map(move |proj| {
                    proj.parts.values().map(|part| QueryResult {
                        part_id: part.id,
                        part_name: part.name.clone(),
                        quantity_committed: part.quantity_committed,
                    })
                })
        }
    }
}

/// Parts and projects as peers
/// Commitment relationship subordinate to projects
mod struct3 {
    use super::QueryResult;
    use std::collections::BTreeMap;

    struct Project {
        id: usize,
        name: String,
        description: String,
        parts_committed: BTreeMap<usize, usize>,
    }

    struct Part {
        id: usize,
        name: String,
        description: String,
        quantity_on_hand: usize,
        quantity_on_order: usize,
    }

    pub struct Inventory {
        parts: BTreeMap<usize, Part>,
        projects: BTreeMap<usize, Project>,
    }

    impl Inventory {
        pub fn query_parts_by_project_name<'a>(
            &'a self,
            project: &'a str,
        ) -> impl Iterator<Item = QueryResult> + 'a {
            self.projects
                .values()
                .filter(move |proj| proj.name == project)
                .flat_map(move |proj| {
                    proj.parts_committed
                        .iter()
                        .map(move |(&part_id, &quantity_committed)| QueryResult {
                            part_id,
                            part_name: self.parts[&part_id].name.clone(),
                            quantity_committed,
                        })
                })
        }
    }
}

/// Parts and projects as peers
/// Commitment relationship subordinate to parts
mod struct4 {
    use super::QueryResult;
    use std::collections::BTreeMap;

    struct Project {
        id: usize,
        name: String,
        description: String,
    }

    struct Part {
        id: usize,
        name: String,
        description: String,
        quantity_on_hand: usize,
        quantity_on_order: usize,
        projects_committed: BTreeMap<usize, usize>,
    }

    pub struct Inventory {
        parts: BTreeMap<usize, Part>,
        projects: BTreeMap<usize, Project>,
    }

    impl Inventory {
        pub fn query_parts_by_project_name<'a>(
            &'a self,
            project: &'a str,
        ) -> impl Iterator<Item = QueryResult> + 'a {
            self.parts.values().flat_map(move |part| {
                part.projects_committed
                    .iter()
                    .filter(move |&(proj, _)| self.projects[proj].name == project)
                    .map(move |(_, &quantity_committed)| QueryResult {
                        part_id: part.id,
                        part_name: part.name.clone(),
                        quantity_committed,
                    })
            })
        }
    }
}

/// Parts, projects, and commitment relationship as peers
mod struct5 {
    use super::QueryResult;
    use std::collections::BTreeMap;

    struct Project {
        id: usize,
        name: String,
        description: String,
    }

    struct Part {
        id: usize,
        name: String,
        description: String,
        quantity_on_hand: usize,
        quantity_on_order: usize,
    }

    struct Commit {
        part_id: usize,
        project_id: usize,
        quantity_committed: usize,
    }

    pub struct Inventory {
        parts: BTreeMap<usize, Part>,
        projects: BTreeMap<usize, Project>,
        commitments: BTreeMap<(usize, usize), Commit>, // (part_id, project_id)
    }

    impl Inventory {
        pub fn query_parts_by_project_name<'a>(
            &'a self,
            project: &'a str,
        ) -> impl Iterator<Item = QueryResult> + 'a {
            self.projects
                .values()
                .filter(move |proj| proj.name == project)
                .flat_map(move |proj| {
                    self.commitments
                        .values()
                        .filter(move |commit| commit.project_id == proj.id)
                        .map(move |commit| QueryResult {
                            part_id: commit.part_id,
                            part_name: self.parts[&commit.part_id].name.clone(),
                            quantity_committed: commit.quantity_committed,
                        })
                })
        }
    }
}

(Playground)

1 Like