Skip to content

Commit

Permalink
implement from/to rows + minor improvements and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GlenDC committed Apr 6, 2024
1 parent 15eb5e9 commit 50b6873
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
bitvec = "1.0.1"
hashbrown = "0.14.3"
rand = "0.8.5"
venndb-macros = { version = "0.1.0", path = "venndb-macros" }
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ pub mod __internal {
pub use bitvec::{bitvec, order::Lsb0, slice::IterOnes, vec::BitVec};
pub use hashbrown::HashMap;

/// Generate a random `usize`.
pub fn rand_usize() -> usize {
use rand::Rng;

rand::thread_rng().gen()
}

pub mod hash_map {
//! Internal types related to hash map.

Expand Down
67 changes: 65 additions & 2 deletions venndb-macros/src/generate_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ fn generate_db_struct_methods(
) -> TokenStream {
let method_new = generate_db_struct_method_new(name, name_db, vis, fields);
let method_with_capacity = generate_db_struct_method_with_capacity(name, name_db, vis, fields);
let method_from_rows = generate_db_struct_method_from_rows(name, name_db, vis, fields);
let field_methods = generate_db_struct_field_methods(name, name_db, vis, fields);
let method_append = generate_db_struct_method_append(name, name_db, vis, fields);

Expand All @@ -84,6 +85,8 @@ fn generate_db_struct_methods(

#method_with_capacity

#method_from_rows

/// Return the number of rows in the database.
#vis fn len(&self) -> usize {
self.rows.len()
Expand All @@ -103,6 +106,11 @@ fn generate_db_struct_methods(
#field_methods

#method_append

/// Consumes the database and returns the rows.
#vis fn into_rows(self) -> Vec<#name> {
self.rows
}
}
}
}
Expand Down Expand Up @@ -191,6 +199,30 @@ pub fn generate_db_struct_method_with_capacity(
}
}

pub fn generate_db_struct_method_from_rows(
name: &Ident,
_name_db: &Ident,
vis: &syn::Visibility,
_fields: &[FieldInfo],
) -> TokenStream {
let method_doc = format!(
"Construct a new database from the given set of [`{}`] rows.",
name
);

quote! {
#[doc=#method_doc]
#vis fn from_rows(rows: Vec<#name>) -> Self {
let mut db = Self::with_capacity(rows.len());
for (index, row) in rows.iter().enumerate() {
db.append_internal(row, index);
}
db.rows = rows;
db
}
}
}

pub fn generate_db_struct_method_append(
name: &Ident,
_name_db: &Ident,
Expand Down Expand Up @@ -248,11 +280,15 @@ pub fn generate_db_struct_method_append(
#vis fn append(&mut self, data: #name) {
let index = self.rows.len();

#(#db_field_insert_checks)*
#(#db_field_insert_commits)*
self.append_internal(&data, index);

self.rows.push(data);
}

fn append_internal(&mut self, data: &#name, index: usize) {
#(#db_field_insert_checks)*
#(#db_field_insert_commits)*
}
}
}

Expand Down Expand Up @@ -391,6 +427,19 @@ fn generate_query_struct_impl(
})
.collect();

let filter_resetters: Vec<_> = fields
.iter()
.filter_map(|info| match info {
FieldInfo::Filter(field) => {
let name = field.name();
Some(quote! {
self.#name = None;
})
}
FieldInfo::Key(_) => None,
})
.collect();

let filters: Vec<_> = fields
.iter()
.filter_map(|info| match info {
Expand Down Expand Up @@ -428,6 +477,14 @@ fn generate_query_struct_impl(
impl<'a> #name_query<'a> {
#(#filter_setters)*

/// Reset the query to its initial values.
#vis fn reset(&mut self) -> &mut Self {
#(#filter_resetters)*
self
}

// TODO: support a filter on the result based on a predicate

/// Execute the query on the database, returning an iterator over the results.
#vis fn execute(&self) -> Option<#name_query_result<'a>> {
let mut filter = ::venndb::__internal::bitvec![1; self.db.rows.len()];
Expand Down Expand Up @@ -458,6 +515,12 @@ fn generate_query_struct_impl(
&self.rows[index]
}

#vis fn any(&self) -> &'a #name {
let n = ::venndb::__internal::rand_usize() % self.v.count_ones();
let index = self.v.iter_ones().nth(n).unwrap();
&self.rows[index]
}

#vis fn iter(&self) -> #name_query_result_iter<'a, '_> {
#name_query_result_iter {
rows: self.rows,
Expand Down
117 changes: 117 additions & 0 deletions venndb-usage/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,121 @@ mod tests {

// TODO: add test to ensure that no other keys
// have already been inserted!

#[test]
fn test_into_from_rows() {
let rows = vec![
Employee {
id: 1,
name: "Alice".to_string(),
is_manager: true,
is_admin: false,
is_active: true,
department: Department::Engineering,
},
Employee {
id: 2,
name: "Bob".to_string(),
is_manager: false,
is_admin: false,
is_active: true,
department: Department::Engineering,
},
];

let db = EmployeeDB::from_rows(rows);

assert_eq!(db.len(), 2);
assert_eq!(db.capacity(), 2);

let mut query = db.query();
query.is_manager(true);
let results: Vec<_> = query.execute().unwrap().iter().collect();
assert_eq!(results.len(), 1);
assert_eq!(results[0].id, 1);

let rows = db.into_rows();
assert_eq!(rows.len(), 2);
assert_eq!(rows[0].id, 1);
assert_eq!(rows[1].id, 2);
}

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

db.append(Employee {
id: 1,
name: "Alice".to_string(),
is_manager: true,
is_admin: false,
is_active: true,
department: Department::Engineering,
});
db.append(Employee {
id: 2,
name: "Bob".to_string(),
is_manager: false,
is_admin: false,
is_active: true,
department: Department::Engineering,
});
db.append(Employee {
id: 3,
name: "Charlie".to_string(),
is_manager: true,
is_admin: true,
is_active: true,
department: Department::Sales,
});

let mut query = db.query();
query.is_manager(true);
let results: Vec<_> = query.execute().unwrap().iter().collect();
assert_eq!(results.len(), 2);
assert_eq!(results[0].id, 1);
assert_eq!(results[1].id, 3);

query.reset();
let results: Vec<_> = query.execute().unwrap().iter().collect();
assert_eq!(results.len(), 3);
assert_eq!(results[0].id, 1);
assert_eq!(results[1].id, 2);
assert_eq!(results[2].id, 3);
}

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

db.append(Employee {
id: 1,
name: "Alice".to_string(),
is_manager: true,
is_admin: false,
is_active: true,
department: Department::Engineering,
});
db.append(Employee {
id: 2,
name: "Bob".to_string(),
is_manager: false,
is_admin: false,
is_active: true,
department: Department::Engineering,
});
db.append(Employee {
id: 3,
name: "Charlie".to_string(),
is_manager: true,
is_admin: true,
is_active: true,
department: Department::Sales,
});

let mut query = db.query();
query.is_active(true);
let result = query.execute().unwrap().any();
assert!(result.id == 1 || result.id == 2 || result.id == 3);
}
}

0 comments on commit 50b6873

Please sign in to comment.