diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index df6c522e1..2d7472b63 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -4,4 +4,6 @@ - [Working with table collections](./working_with_table_collections.md) - [Creation](./table_collection_creation.md) - [Adding rows](./table_collection_adding_rows.md) + - [Accessing table columns](./table_collection_column_access.md) + - [Accessing table rows](./table_collection_row_access.md) - [Validating table collection contents](./table_collection_validation.md) diff --git a/book/src/table_collection_column_access.md b/book/src/table_collection_column_access.md new file mode 100644 index 000000000..465253aed --- /dev/null +++ b/book/src/table_collection_column_access.md @@ -0,0 +1,14 @@ +## Accessing table columns + +We can access table rows using either the relevant newtype or `i32` (which is identical to the `tskit-c` typedef `tsk_id_t`). +The following snippet adds and edge and then validates the data for that row of the table: + +```rust, noplaygound, ignore +{{#include ../../tests/book_table_collection.rs:get_edge_table_columns}} +``` + +The return type of the getters is the [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) enum. The `None` variant is returned when row indexes are out of range: + +```rust, noplaygound, ignore +{{#include ../../tests/book_table_collection.rs:get_edge_table_columns_out_of_range}} +``` diff --git a/book/src/table_collection_row_access.md b/book/src/table_collection_row_access.md new file mode 100644 index 000000000..e2f06c8e4 --- /dev/null +++ b/book/src/table_collection_row_access.md @@ -0,0 +1,15 @@ +## Accessing table rows + +We may also access entire table rows by a row id: + +```rust, noplaygound, ignore +{{#include ../../tests/book_table_collection.rs:get_edge_table_row_by_id}} +``` + +The row types are rust structures. The table data are *copied* into these structures, making them relatively more expensive to work with. We are looking into removing the copies and returning slices, but doing so currently impacts the design of table row iterators such as: + +```rust, noplaygound, ignore +{{#include ../../tests/book_table_collection.rs:get_edge_table_rows_by_iterator}} +``` + +These iterators are rust iterator types--they `impl Iterator`, where `X` is a table row type. diff --git a/tests/book_table_collection.rs b/tests/book_table_collection.rs index b53988ecb..f180e7e02 100644 --- a/tests/book_table_collection.rs +++ b/tests/book_table_collection.rs @@ -66,3 +66,72 @@ fn add_node_handle_error() { .check_integrity(tskit::TableIntegrityCheckFlags::default()) .is_err()); } + +#[test] +fn get_data_from_edge_table() { + use rand::distributions::Distribution; + let sequence_length = tskit::Position::from(100.0); + let mut rng = rand::thread_rng(); + let random_pos = rand::distributions::Uniform::new::(0., sequence_length.into()); + let mut tables = tskit::TableCollection::new(sequence_length).unwrap(); + let child = tables.add_node(0, 0.0, -1, -1).unwrap(); + let parent = tables.add_node(0, 1.0, -1, -1).unwrap(); + let mut left = tskit::Position::from(random_pos.sample(&mut rng)); + let mut right = tskit::Position::from(random_pos.sample(&mut rng)); + if left > right { + std::mem::swap(&mut left, &mut right); + } + + // ANCHOR: get_edge_table_columns + if let Ok(edge_id) = tables.add_edge(left, right, parent, child) { + // Take a reference to an edge table (& tskit::EdgeTable) + let edges = tables.edges(); + if let Some(p) = edges.parent(edge_id) { + assert_eq!(p, parent); + } + if let Some(c) = edges.child(edge_id) { + assert_eq!(c, child); + } + if let Some(l) = edges.left(edge_id) { + assert_eq!(l, left); + } + if let Some(r) = edges.right(edge_id) { + assert_eq!(r, right); + } + } else { + panic!("that should have worked..."); + } + // ANCHOR_END: get_edge_table_columns + + // ANCHOR: get_edge_table_columns_out_of_range + assert!(tables.edges().parent(tskit::EdgeId::NULL).is_none()); + // ANCHOR_END: get_edge_table_columns_out_of_range + + let edge_id = tskit::EdgeId::from(0); + // ANCHOR: get_edge_table_row_by_id + if let Some(row) = tables.edges().row(edge_id) { + assert_eq!(row.id, 0); + assert_eq!(row.left, left); + assert_eq!(row.right, right); + assert_eq!(row.parent, parent); + assert_eq!(row.child, child); + } else { + panic!("that should have worked..."); + } + // ANCHOR_END: get_edge_table_row_by_id + + // ANCHOR: get_edge_table_rows_by_iterator + for row in tables.edges_iter() { + // there is only one row! + assert_eq!(row.id, 0); + assert_eq!(row.left, left); + assert_eq!(row.right, right); + assert_eq!(row.parent, parent); + assert_eq!(row.child, child); + } + // ANCHOR_END: get_edge_table_rows_by_iterator + + assert!(tables + .check_integrity(tskit::TableIntegrityCheckFlags::default()) + .is_ok()); +}