use std::collections::HashMap;
use uuid::Uuid;
use crate::db::{CustomDataItem, Entry, Times};
#[derive(Debug, Default, Eq, PartialEq, Clone)]
#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
pub struct Group {
pub uuid: Uuid,
pub name: String,
pub notes: Option<String>,
pub icon_id: Option<usize>,
pub custom_icon_uuid: Option<Uuid>,
pub groups: Vec<Group>,
pub entries: Vec<Entry>,
pub times: Times,
pub custom_data: HashMap<String, CustomDataItem>,
pub is_expanded: bool,
pub default_autotype_sequence: Option<String>,
pub enable_autotype: Option<bool>,
pub enable_searching: Option<bool>,
pub last_top_visible_entry: Option<Uuid>,
}
impl Group {
pub fn new(name: &str) -> Group {
Group {
name: name.to_string(),
times: Times::new(),
uuid: Uuid::new_v4(),
..Default::default()
}
}
pub fn group_by_name(&self, name: &str) -> Option<&Group> {
self.groups.iter().find(|g| g.name == name)
}
pub fn group_by_name_mut(&mut self, name: &str) -> Option<&mut Group> {
self.groups.iter_mut().find(|g| g.name == name)
}
pub fn group_by_path(&self, path: &[&str]) -> Option<&Group> {
if path.is_empty() {
return Some(self);
}
self.groups.iter().find(|g| g.name == path[0]).and_then(|g| {
if path.len() > 1 {
g.group_by_path(&path[1..])
} else {
Some(g)
}
})
}
pub fn group_by_path_mut(&mut self, path: &[&str]) -> Option<&mut Group> {
if path.is_empty() {
return Some(self);
}
self.groups.iter_mut().find(|g| g.name == path[0]).and_then(|g| {
if path.len() > 1 {
g.group_by_path_mut(&path[1..])
} else {
Some(g)
}
})
}
pub fn group_by_uuid(&self, uuid: Uuid) -> Option<&Group> {
if self.uuid == uuid {
return Some(self);
}
for g in &self.groups {
if let Some(group) = g.group_by_uuid(uuid) {
return Some(group);
}
}
None
}
pub fn group_by_uuid_mut(&mut self, uuid: Uuid) -> Option<&mut Group> {
if self.uuid == uuid {
return Some(self);
}
for g in &mut self.groups {
if let Some(group) = g.group_by_uuid_mut(uuid) {
return Some(group);
}
}
None
}
pub fn entry_by_name(&self, name: &str) -> Option<&Entry> {
self.entries.iter().find(|e| e.get_title() == Some(name))
}
pub fn entry_by_name_mut(&mut self, name: &str) -> Option<&mut Entry> {
self.entries.iter_mut().find(|e| e.get_title() == Some(name))
}
pub fn entry_by_uuid(&self, uuid: Uuid) -> Option<&Entry> {
for e in &self.entries {
if e.uuid == uuid {
return Some(e);
}
}
for g in &self.groups {
if let Some(e) = g.entry_by_uuid(uuid) {
return Some(e);
}
}
None
}
pub fn entry_by_uuid_mut(&mut self, uuid: Uuid) -> Option<&mut Entry> {
for e in &mut self.entries {
if e.uuid == uuid {
return Some(e);
}
}
for g in &mut self.groups {
if let Some(e) = g.entry_by_uuid_mut(uuid) {
return Some(e);
}
}
None
}
pub fn get_name(&self) -> &str {
&self.name
}
}
#[cfg(test)]
mod group_tests {
use super::Group;
use crate::db::{fields, Entry};
use crate::Database;
#[test]
fn get() {
let mut db = Database::new(Default::default());
let mut general_group = Group::new("General");
let mut sample_entry = Entry::new();
sample_entry.set_unprotected(fields::TITLE, "Sample Entry #2");
general_group.entries.push(sample_entry);
db.root.groups.push(general_group);
assert!(db
.root
.group_by_path(&["General"])
.and_then(|g| g.entry_by_name("Sample Entry #2"))
.is_some());
assert!(db.root.group_by_name("General").is_some());
assert!(db.root.group_by_name("Invalid Group").is_none());
assert!(db.root.group_by_path(&[]).is_some());
}
#[test]
fn get_mut() {
let mut db = Database::new(Default::default());
let mut general_group = Group::new("General");
let mut sample_entry = Entry::new();
sample_entry.set_unprotected(fields::TITLE, "Sample Entry #2");
general_group.entries.push(sample_entry);
db.root.groups.push(general_group);
assert!(db
.root
.group_by_path_mut(&["General"])
.and_then(|g| g.entry_by_name_mut("Sample Entry #2"))
.is_some());
assert!(db.root.group_by_name_mut("General").is_some());
assert!(db.root.group_by_name_mut("Invalid Group").is_none());
assert!(db.root.group_by_path_mut(&[]).is_some());
}
#[test]
fn get_by_uuid() {
let mut db = Database::new(Default::default());
let mut general_group = Group::new("General");
let mut sample_entry = Entry::new();
sample_entry.set_unprotected(fields::TITLE, "Sample Entry #2");
general_group.entries.push(sample_entry.clone());
db.root.groups.push(general_group.clone());
let general_group_uuid = general_group.uuid;
let sample_entry_uuid = sample_entry.uuid;
let invalid_uuid = uuid::Uuid::new_v4();
assert!(db.root.group_by_uuid(general_group_uuid).is_some());
assert!(db.root.group_by_uuid(sample_entry_uuid).is_none());
assert!(db.root.group_by_uuid(invalid_uuid).is_none());
assert!(db.root.entry_by_uuid(general_group_uuid).is_none());
assert!(db.root.entry_by_uuid(sample_entry_uuid).is_some());
assert!(db.root.entry_by_uuid(invalid_uuid).is_none());
}
#[test]
fn get_by_uuid_mut() {
let mut db = Database::new(Default::default());
let mut general_group = Group::new("General");
let mut sample_entry = Entry::new();
sample_entry.set_unprotected(fields::TITLE, "Sample Entry #2");
general_group.entries.push(sample_entry.clone());
db.root.groups.push(general_group.clone());
let general_group_uuid = general_group.uuid;
let sample_entry_uuid = sample_entry.uuid;
let invalid_uuid = uuid::Uuid::new_v4();
assert!(db.root.group_by_uuid_mut(general_group_uuid).is_some());
assert!(db.root.group_by_uuid_mut(sample_entry_uuid).is_none());
assert!(db.root.group_by_uuid_mut(invalid_uuid).is_none());
assert!(db.root.entry_by_uuid_mut(general_group_uuid).is_none());
assert!(db.root.entry_by_uuid_mut(sample_entry_uuid).is_some());
assert!(db.root.entry_by_uuid_mut(invalid_uuid).is_none());
}
}