use serde::{Deserialize, Serialize};
use strum_macros::Display;
use crate::{Pak, builder::PakBuilder, group::{Defer, Pointer}, index::{Indices, PakIndexIdentifier, PakSearchable}, pointer::PakPointer, query::PakQuery, value::{IntoPakValue, PakValue}};
#[derive(Serialize, Deserialize, Debug, Display, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum PersonalityTrait {
Friendly,
Intelligent,
Curious,
Brave,
Kind,
Creative,
Adventurous,
Responsible,
Organized,
Patient,
Extroverted,
Introverted,
}
impl IntoPakValue for PersonalityTrait {
fn into_pak_value(self) -> PakValue {
PakValue::String(self.to_string())
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Person {
pub first_name: String,
pub last_name: String,
pub age: u32,
pub personallity_traits : Vec<PersonalityTrait>
}
impl PakSearchable for Person {
fn get_indices(&self, indices : &mut Indices) {
indices.add("first_name", self.first_name.clone());
indices.add("last_name", self.last_name.clone());
indices.add("age", self.age.clone());
indices.add("personallity_traits", self.personallity_traits.clone());
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Pet {
pub name : String,
pub age: u32,
pub owner: PakPointer,
pub kind: PetKind,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum PetKind {
Dog,
Cat,
}
impl IntoPakValue for PetKind {
fn into_pak_value(self) -> crate::value::PakValue {
match self {
PetKind::Dog => "dog".into(),
PetKind::Cat => "cat".into(),
}
}
}
impl PakSearchable for Pet {
fn get_indices(&self, indices : &mut Indices) {
indices.add("name", self.name.clone());
indices.add("age", self.age.clone());
indices.add("kind", self.kind.clone());
}
}
pub(crate) fn john_doe() -> Person {
Person {
first_name: "John".to_string(),
last_name: "Doe".to_string(),
age: 30,
personallity_traits: vec![PersonalityTrait::Patient, PersonalityTrait::Creative, PersonalityTrait::Extroverted]
}
}
pub(crate) fn jane_doe() -> Person {
Person {
first_name: "Jane".to_string(),
last_name: "Doe".to_string(),
age: 25,
personallity_traits: vec![PersonalityTrait::Responsible, PersonalityTrait::Introverted, PersonalityTrait::Intelligent]
}
}
pub(crate) fn alice_smith() -> Person {
Person {
first_name: "Alice".to_string(),
last_name: "Smith".to_string(),
age: 28,
personallity_traits: vec![PersonalityTrait::Brave, PersonalityTrait::Adventurous, PersonalityTrait::Curious]
}
}
pub(crate) fn bob_johnson() -> Person {
Person {
first_name: "Bob".to_string(),
last_name: "Johnson".to_string(),
age: 35,
personallity_traits: vec![PersonalityTrait::Patient, PersonalityTrait::Creative, PersonalityTrait::Extroverted]
}
}
pub(crate) fn charlie_brown() -> Person {
Person {
first_name: "Charlie".to_string(),
last_name: "Brown".to_string(),
age: 40,
personallity_traits: vec![PersonalityTrait::Responsible, PersonalityTrait::Introverted, PersonalityTrait::Intelligent]
}
}
pub(crate) fn john_jacob() -> Person {
Person {
first_name: "John".to_string(),
last_name: "Jacob".to_string(),
age: 45,
personallity_traits: vec![PersonalityTrait::Patient, PersonalityTrait::Creative, PersonalityTrait::Extroverted]
}
}
pub(crate) fn ajax_burnahm() -> Person {
Person {
first_name: "Ajax".to_string(),
last_name: "Burnahm".to_string(),
age: 30,
personallity_traits: vec![PersonalityTrait::Responsible, PersonalityTrait::Introverted, PersonalityTrait::Intelligent]
}
}
pub(crate) fn build_data_base() -> (Pak, PakPointer, PakPointer) {
let mut builder = PakBuilder::new();
let person1 = john_doe();
let person2 = jane_doe();
let person3 = alice_smith();
let person4 = bob_johnson();
let person5 = charlie_brown();
let person6 = john_jacob();
let person7 = ajax_burnahm();
let owner1 = builder.pak(&person1).unwrap();
let owner2 = builder.pak(&person2).unwrap();
builder.pak(&person3).unwrap();
builder.pak(&person4).unwrap();
builder.pak(&person5).unwrap();
builder.pak(&person6).unwrap();
builder.pak(&person7).unwrap();
let pet1 = Pet {
name: "Fido".to_string(),
age: 5,
owner: owner1.clone(),
kind: PetKind::Dog,
};
let pet2 = Pet {
name: "Whiskers".to_string(),
age: 3,
owner: owner2.clone(),
kind: PetKind::Cat,
};
let pet3 = Pet {
name: "Bella".to_string(),
age: 7,
owner: owner1.clone(),
kind: PetKind::Dog,
};
builder.pak(&pet1).unwrap();
builder.pak(&pet2).unwrap();
builder.pak(&pet3).unwrap();
(builder.build_in_memory().unwrap(), owner1, owner2)
}
#[test]
fn pak_read() {
let (pak, john_doe, _) = build_data_base();
let person = pak.read_err::<Person>(&john_doe).unwrap();
assert_eq!(person.first_name, "John");
assert_eq!(person.last_name, "Doe");
}
#[test]
fn pak_query_equal() {
let (pak, _, _) = build_data_base();
let people = pak.query::<(Person, )>("first_name".equals("John")).unwrap();
assert_eq!(people.len(), 2);
}
#[test]
fn pak_query_ref() {
let (pak, _, _) = build_data_base();
let mut people = pak.query::<(Defer<Person>, )>("first_name".equals("John")).unwrap();
assert_eq!(people.len(), 2);
let mut person = people.pop().unwrap();
assert!(!person.is_loaded());
person.get().unwrap();
assert!(person.is_loaded())
}
#[test]
fn pak_query_pointer() {
let (pak, _, _) = build_data_base();
let people = pak.query::<(Pointer<Person>, )>("first_name".equals("John")).unwrap();
assert_eq!(people.len(), 2);
}
#[test]
fn pak_query_less_than() {
let (pak, _, _) = build_data_base();
let (people, pets) = pak.query::<(Person, Pet)>("age".less_than_or_equal(26)).unwrap();
assert_eq!(people.len(), 1);
assert_eq!(pets.len(), 3);
}
#[test]
fn pak_query_greater_than() {
let (pak, _, _) = build_data_base();
let (people, pets) = pak.query::<(Person, Pet)>("age".greater_than(26)).unwrap();
assert_eq!(people.len(), 6);
assert_eq!(pets.len(), 0);
}
#[test]
fn pak_query_greater_than_equal() {
let (pak, _, _) = build_data_base();
let (people, pets) = pak.query::<(Person, Pet)>("age".greater_than_or_equal(25)).unwrap();
assert_eq!(people.len(), 7);
assert_eq!(pets.len(), 0);
}
#[test]
fn pak_query_less_than_equal() {
let (pak, _, _) = build_data_base();
let (people, pets) = pak.query::<(Person, Pet)>("age".less_than_or_equal(25)).unwrap();
assert_eq!(people.len(), 1);
assert_eq!(pets.len(), 3);
}
#[test]
fn pak_query_contains() {
let (pak, _, _) = build_data_base();
let query = "personallity_traits".contains_value(PersonalityTrait::Creative);
let people = pak.query::<(Person,)>(query).unwrap();
assert_eq!(people.len(), 3);
}
#[test]
fn pak_query_all() {
let (pak, _, _) = build_data_base();
let query = PakQuery::All;
let (pets, people) = pak.query::<(Pet, Person)>(query).unwrap();
assert_eq!(people.len(), 7);
assert_eq!(pets.len(), 3);
}
#[test]
fn compound_union_query() {
let (pak, _, _) = build_data_base();
let query = "age".less_than(30) | "first_name".equals("John");
let (people, pets) = pak.query::<(Person, Pet)>(query).unwrap();
assert_eq!(people.len(), 4);
assert_eq!(pets.len(), 3);
assert!(people.contains(&john_doe()));
assert!(people.contains(&john_jacob()));
assert!(people.contains(&alice_smith()));
assert!(people.contains(&jane_doe()));
}
#[test]
fn compound_intersection_query() {
let (pak, _, _) = build_data_base();
let query = "age".greater_than(25) & "first_name".equals("John");
let (people, pets) = pak.query::<(Person, Pet)>(query).unwrap();
assert_eq!(people.len(), 2);
assert_eq!(pets.len(), 0);
}
#[test]
fn pak_file_read_write() {
let mut builder = PakBuilder::new();
builder.pak(&john_doe()).unwrap();
builder.pak(&jane_doe()).unwrap();
builder.pak(&alice_smith()).unwrap();
builder.pak(&bob_johnson()).unwrap();
builder.pak(&charlie_brown()).unwrap();
builder.pak(&john_jacob()).unwrap();
builder.pak(&ajax_burnahm()).unwrap();
{
let pak = builder.build_file("temp.pak").unwrap();
let people = pak.query::<(Person, )>("first_name".equals("John")).unwrap();
assert_eq!(people.len(), 2);
assert!(people.contains(&john_doe()));
assert!(people.contains(&john_jacob()));
}
let pak = Pak::new_from_file("temp.pak").unwrap();
let people = pak.query::<(Person, )>("first_name".equals("John")).unwrap();
assert_eq!(people.len(), 2);
assert!(people.contains(&john_doe()));
assert!(people.contains(&john_jacob()));
std::fs::remove_file("temp.pak").unwrap();
}
#[test]
fn extra_meta() {
let mut builder = PakBuilder::new();
#[derive(Serialize, Deserialize)]
struct ExtraMeta {
test : String
}
builder.set_extra(&ExtraMeta {
test : "Test".to_string()
}).unwrap();
let pak = builder.build_in_memory().unwrap();
let extra = pak.get_extra::<ExtraMeta>().unwrap();
assert_eq!(extra.test, "Test")
}