diff --git a/README.md b/README.md index f610753..5c2b69a 100644 --- a/README.md +++ b/README.md @@ -375,7 +375,7 @@ let value = query.execute().unwrap().any(); assert_eq!(value.bar, 16); ``` -Why is this true? Beacuse it is correct. +Why is this true? Because it is correct. Allowing it also to match the value `foo` would unfairly give more chances for `foo` to be selected over the _any_ value. @@ -401,7 +401,7 @@ use venndb::VennDB; #[derive(Debug, VennDB)] // These attributes are optional, // e.g. by default the database would be called `EmployeeDB` (name + 'DB'). -#[venndb(name = "EmployeeInMemDB")] +#[venndb(name = "EmployeeInMemDB", validator = employee_validator)] pub struct Employee { // you can use the `key` arg to be able to get an `Employee` instance // directly by this key. It will effectively establishing a mapping from key to a reference @@ -446,6 +446,10 @@ pub struct Employee { country: Option, } +fn employee_validator(employee: &Employee) -> bool { + employee.id > 0 +} + fn main() { let db = EmployeeInMemDB::from_iter([ RawCsvRow("1,John Doe,true,false,true,false,Engineering,USA"), @@ -554,15 +558,21 @@ fn main() { assert_eq!(usa_employees[0].id, 1); println!(">>> At any time you can also append new employees to the DB..."); - assert!(db + assert_eq!(EmployeeInMemDBErrorKind::DuplicateKey, db .append(RawCsvRow("8,John Doe,true,false,true,false,Engineering,")) - .is_err()); + .unwrap_err().kind()); println!(">>> This will fail however if a property is not correct (e.g. ID (key) is not unique in this case), let's try this again..."); assert!(db .append(RawCsvRow("9,John Doe,false,true,true,false,Engineering,")) .is_ok()); assert_eq!(db.len(), 9); + println!(">>> Rows are also validated prior to appending in case a validator is defined..."); + println!(" The next insertion will fail due to the id being zero, a condition defined in the custom validator..."); + assert_eq!(EmployeeInMemDBErrorKind::InvalidRow, db + .append(RawCsvRow("0,John Doe,true,false,true,false,Engineering,")) + .unwrap_err().kind()); + println!(">>> This new employee can now also be queried for..."); let mut query = db.query(); query.department(Department::Engineering).is_manager(false); @@ -690,7 +700,7 @@ In this chapter we'll list the API as generated by `VennDB` for the following ex ```rust,ignore #[derive(Debug, VennDB)] -#[venndb(name = "EmployeeInMemDB")] +#[venndb(name = "EmployeeInMemDB", validator = employee_validator)] pub struct Employee { #[venndb(key)] id: u32, @@ -734,7 +744,7 @@ Database: (e.g. `EmployeeInMemDB`): | `EmployeeInMemDB::from_rows(rows: ::std::vec::Vec) -> EmployeeInMemDB` or `EmployeeInMemDB::from_rows(rows: ::std::vec::Vec) -> Result>>` | constructor to create the database directly from a heap-allocated list of data instances. The second version is the one used if at least one `#[venndb(key)]` property is defined, otherwise it is the first one (without the `Result`). | | `EmployeeInMemDB::from_iter(iter: impl ::std::iter::IntoIterator>) -> EmployeeInMemDB` or `EmployeeInMemDB::from_rows(iter: impl ::std::iter::IntoIterator>) -> Result>>` | Same as `from_rows` but using an iterator instead. The items do not have to be an `Employee` but can be anything that can be turned into one. E.g. in our example above we defined a struct `RawCsvRow` that was turned on the fly into an `Employee`. This happens all at once prior to inserting the database, which is why the version with a result does return a `Vec` and not an iterator. | | `EmployeeInMemDB::append(&mut self, data: impl ::std::convert::Into)` or `EmployeeInMemDB::append(&mut self, data: impl ::std::convert::Into) -> Result<(), EmployeeInMemDBError>` | append a single row to the database. Depending on whether or not a `#[venndb(key)]` property is defined it will generate the `Result` version or not. Same as `from_rows` and `from_iter` | -| `EmployeeInMemDB::extend(&mut self, iter: I) where I: ::std::iter::IntoIterator, Item: ::std::convert::Into` or `EmployeeInMemDB::extend(&mut self, iter: I) -> Result<(), EmployeeInMemDBError<(Employee, I::IntoIter)>> where I: ::std::iter::IntoIterator, Item: ::std::convert::Into` | extend the database with the given iterator, once again returning a result in case such insertion can go wrong (e.g. because keys are used (duplication)). Otherwise this function will return nothing. | +| `EmployeeInMemDB::extend(&mut self, iter: I) where I: ::std::iter::IntoIterator, Item: ::std::convert::Into` or `EmployeeInMemDB::extend(&mut self, iter: I) -> Result<(), EmployeeInMemDBError<(Employee, I::IntoIter)>> where I: ::std::iter::IntoIterator, Item: ::std::convert::Into` | extend the database with the given iterator, once again returning a result in case such insertion can go wrong (e.g. because keys are used (duplication) or a row is invalid in case a validator is defined). Otherwise this function will return nothing. | | `EmployeeInMemDB::get_by_id(&self, data: impl ::std::convert::Into) -> Option<&Employee> where Employee ::std::borrow::Borrow, Q: ::std::hash::Hash + ::std::cmp::Eq + ?::std::marker::Sized` | look up a row by the `id` key property. This method will be generated for each property marked with `#[venndb(key)`. e.g. if you have key property named `foo: MyType` property there will be also a `get_by_foo(&self, ...)` method generated. | | `EmployeeInMemDB::query(&self) -> EmployeeInMemDBQuery` | create a `EmployeeInMemDBQuery` builder to compose a filter composition to query the database. The default builder will match all rows. See the method API for `EmployeeInMemDBQuery` for more information |