Skip to content

Commit

Permalink
support extend method + add tests for dup keys
Browse files Browse the repository at this point in the history
  • Loading branch information
GlenDC committed Apr 8, 2024
1 parent 11250c4 commit 85c2dba
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 1 deletion.
41 changes: 40 additions & 1 deletion venndb-macros/src/generate_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ fn generate_db_struct_method_append(
fields: &[FieldInfo],
) -> TokenStream {
let method_doc = format!("Append a new instance of [`{}`] to the database.", name);
let method_iter_doc = format!(
"Extend the database with the given iterator of items that can be turned into [`{}`] instances.",
name
);

let db_field_insert_checks: Vec<_> = fields
.iter()
Expand Down Expand Up @@ -368,6 +372,8 @@ fn generate_db_struct_method_append(
.collect();

let append_return_type = db_error.generate_fn_output(name_db, quote! { #name }, quote! { () });
let extend_return_type =
db_error.generate_fn_output(name_db, quote! { (#name, I::IntoIter) }, quote! { () });
let append_kind_return_type = db_error.generate_fn_kind_output(name_db, quote! { () });

let append_internal_call = db_error.generate_fn_error_kind_usage(
Expand All @@ -378,6 +384,14 @@ fn generate_db_struct_method_append(
quote! { data },
);

let extend_append_internal_call = db_error.generate_fn_error_kind_usage(
name_db,
quote! {
self.append_internal(&data, index)
},
quote! { (data, iter) },
);

let append_return_output = db_error.generate_fn_return_value_ok(quote! { () });

quote! {
Expand All @@ -390,6 +404,23 @@ fn generate_db_struct_method_append(
#append_return_output
}

#[doc=#method_iter_doc]
#vis fn extend<I, Item>(&mut self, iter: I) -> #extend_return_type
where
I: ::std::iter::IntoIterator<Item = Item>,
Item: ::std::convert::Into<#name>,
{
let mut index = self.rows.len();
let mut iter = iter.into_iter();
for item in &mut iter {
let data = item.into();
#extend_append_internal_call
self.rows.push(data);
index += 1;
}
#append_return_output
}

fn append_internal(&mut self, data: &#name, index: usize) -> #append_kind_return_type {
#(#db_field_insert_checks)*
#(#db_field_insert_commits)*
Expand Down Expand Up @@ -595,6 +626,10 @@ fn generate_query_struct_impl(
let filter_name: Ident = field.filter_name();
let filter_not_name: Ident = field.filter_not_name();
Some(quote! {
// Filter by the filter below. Only if it is defined as Some(_).
// Using negation if negation is desired, and
// the regular filter otherwise.

match self.#name {
Some(true) => filter &= &self.db.#filter_name,
Some(false) => filter &= &self.db.#filter_not_name,
Expand All @@ -607,10 +642,14 @@ fn generate_query_struct_impl(
let filter_map_name: Ident = field.filter_map_name();
let filter_vec_name: Ident = field.filter_vec_name();
Some(quote! {
// Filter by the filterm ap below, only if it is defined as Some(_).
// If there is no filter matched to the given value then the search is over,
// and we early return None.

if let Some(value) = &self.#name {
match self.db.#filter_map_name.get(value) {
Some(index) => filter &= &self.db.#filter_vec_name[*index],
None => filter.fill(false),
None => return None,
};
}
})
Expand Down
123 changes: 123 additions & 0 deletions venndb-usage/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,79 @@ mod tests {
assert_eq!(employee.department, Department::Engineering);
}

#[test]
fn test_extend() {
let mut db = EmployeeDB::default();
assert_eq!(db.len(), 0);
assert!(db.get_by_id(&1).is_none());
assert!(db.get_by_id(&2).is_none());
assert!(db.is_empty());

db.extend(vec![
L1Engineer {
id: 1,
name: "Alice".to_string(),
},
L1Engineer {
id: 2,
name: "Bob".to_string(),
},
])
.unwrap();
assert_eq!(db.len(), 2);

let employee: &Employee = db.get_by_id(&1).unwrap();
assert_eq!(employee.id, 1);
assert_eq!(employee.name, "Alice");

let employee: &Employee = db.get_by_id(&2).unwrap();
assert_eq!(employee.id, 2);
assert_eq!(employee.name, "Bob");
}

#[test]
fn test_extend_duplicate_key() {
let mut db = EmployeeDB::default();
db.extend(vec![
L1Engineer {
id: 1,
name: "Alice".to_string(),
},
L1Engineer {
id: 2,
name: "Bob".to_string(),
},
])
.unwrap();
assert_eq!(db.len(), 2);

let err = db
.extend(vec![
L1Engineer {
id: 2,
name: "Charlie".to_string(),
},
L1Engineer {
id: 3,
name: "David".to_string(),
},
])
.unwrap_err();
assert_eq!(EmployeeDBErrorKind::DuplicateKey, err.kind());

let (dup_employee, employee_iter) = err.into_input();
assert_eq!(dup_employee.id, 2);
assert_eq!(dup_employee.name, "Charlie");

let employees: Vec<_> = employee_iter.collect();
assert_eq!(employees.len(), 1);
assert_eq!(employees[0].id, 3);

db.extend(employees).unwrap();
assert_eq!(db.len(), 3);
assert_eq!(db.get_by_id(&3).unwrap().name, "David");
}

#[test]
fn test_employee_query_filters() {
let mut db = EmployeeDB::default();
Expand Down Expand Up @@ -278,6 +351,35 @@ mod tests {
assert_eq!(rows[1].id, 2);
}

#[test]
fn test_from_rows_duplicate_key() {
let err = EmployeeDB::from_rows(vec![
Employee {
id: 1,
name: "Alice".to_string(),
is_manager: true,
is_admin: false,
is_active: true,
department: Department::Engineering,
},
Employee {
id: 1,
name: "Bob".to_string(),
is_manager: false,
is_admin: false,
is_active: true,
department: Department::Engineering,
},
])
.unwrap_err();
assert_eq!(EmployeeDBErrorKind::DuplicateKey, err.kind());

let employees = err.into_input();
assert_eq!(employees.len(), 2);
assert_eq!(employees[0].name, "Alice");
assert_eq!(employees[1].name, "Bob");
}

#[test]
fn test_from_iter() {
let db = EmployeeDB::from_iter([
Expand Down Expand Up @@ -309,6 +411,27 @@ mod tests {
assert_eq!(results[1].id, 2);
}

#[test]
fn test_from_iter_duplicate_key() {
let err = EmployeeDB::from_iter([
L1Engineer {
id: 1,
name: "Alice".to_string(),
},
L1Engineer {
id: 1,
name: "Bob".to_string(),
},
])
.unwrap_err();
assert_eq!(EmployeeDBErrorKind::DuplicateKey, err.kind());

let employees = err.into_input();
assert_eq!(employees.len(), 2);
assert_eq!(employees[0].name, "Alice");
assert_eq!(employees[1].name, "Bob");
}

#[test]
fn test_query_reset() {
let mut db = EmployeeDB::default();
Expand Down

0 comments on commit 85c2dba

Please sign in to comment.