use macrodb::table;
use std::collections::{BTreeMap as Map, BTreeSet as Set};
type UserId = u64;
#[derive(Clone, Debug, PartialEq, Eq)]
struct User {
id: UserId,
first: String,
last: String,
age: u16,
city: String,
country: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Error {
UserIdExists,
UserNotFound,
UserNameExists,
}
#[derive(Clone, Debug, Default)]
struct Database {
users: Map<UserId, User>,
user_by_name: Map<(String, String), UserId>,
users_by_age: Map<u16, Set<UserId>>,
users_by_location: Map<(String, String), Set<UserId>>,
}
impl Database {
table!(
users: User,
id: UserId,
missing Error => Error::UserNotFound,
primary users id => Error::UserIdExists,
index users_by_location (city, country) => (),
unique user_by_name (first, last) => Error::UserNameExists,
index users_by_age age => ()
);
}
#[test]
fn can_insert_user() {
let mut database = Database::default();
let user = User {
id: database.users_next_id(),
first: "John".into(),
last: "Doe".into(),
age: 21,
city: "Atlantic City".into(),
country: "United States".into(),
};
database.users_insert(user.clone()).unwrap();
assert_eq!(database.users.get(&user.id), Some(&user));
assert!(database
.users_by_age
.get(&user.age)
.unwrap()
.contains(&user.id));
assert!(database
.users_by_location
.get(&(user.city.clone(), user.country.clone()))
.unwrap()
.contains(&user.id));
assert_eq!(
database
.user_by_name
.get(&(user.first.clone(), user.last.clone())),
Some(&user.id)
);
}
#[test]
fn cannot_insert_user_existing_name() {
let mut database = Database::default();
database
.users_insert(User {
id: database.users_next_id(),
first: "John".into(),
last: "Doe".into(),
age: 21,
city: "Atlantic City".into(),
country: "United States".into(),
})
.unwrap();
let result = database.users_insert(User {
id: database.users_next_id(),
first: "John".into(),
last: "Doe".into(),
age: 24,
city: "Elsewhere".into(),
country: "United States".into(),
});
assert_eq!(result, Err(Error::UserNameExists));
}
#[test]
fn can_update_user() {
let mut database = Database::default();
let id = database.users_next_id();
let mut user = User {
id,
first: "John".into(),
last: "Doe".into(),
age: 21,
city: "Atlantic City".into(),
country: "United States".into(),
};
database.users_insert(user.clone()).unwrap();
user.first = "Jack".into();
user.last = "Campbell".into();
user.city = "Neverland".into();
user.country = "Mexico".into();
database.users_update(user.clone()).unwrap();
assert_eq!(database.users.get(&id), Some(&user));
assert!(database.users_by_age.get(&user.age).unwrap().contains(&id));
assert!(database
.users_by_location
.get(&(user.city.clone(), user.country.clone()))
.unwrap()
.contains(&id));
assert_eq!(
database
.user_by_name
.get(&(user.first.clone(), user.last.clone())),
Some(&id)
);
}
#[test]
fn can_delete_user() {
let mut database = Database::default();
let user = User {
id: database.users_next_id(),
first: "John".into(),
last: "Doe".into(),
age: 21,
city: "Atlantic City".into(),
country: "United States".into(),
};
database.users_insert(user.clone()).unwrap();
database.users_delete(user.id).unwrap();
assert_eq!(database.users.get(&user.id), None);
assert!(database.users_by_age.get(&user.age).is_none());
assert!(database
.users_by_location
.get(&(user.city.clone(), user.country.clone()))
.is_none());
assert_eq!(
database
.user_by_name
.get(&(user.first.clone(), user.last.clone())),
None
);
}