use std::cmp::Ordering;
use std::collections::BTreeSet;
use rusqlite::Row;
use serde::Serialize;
use crate::applebooks::database::{ABDatabaseName, ABQuery};
use super::datetime::DateTimeUtc;
use super::epubcfi;
#[derive(Debug, Default, Clone, Eq, Serialize)]
pub struct Annotation {
pub body: String,
pub style: String,
pub notes: String,
pub tags: BTreeSet<String>,
pub metadata: AnnotationMetadata,
}
impl Annotation {
fn int_to_style(int: u8) -> String {
let style = match int {
0 => "underline",
1 => "green",
2 => "blue",
3 => "yellow",
4 => "pink",
5 => "purple",
_ => "",
};
style.to_owned()
}
}
impl ABQuery for Annotation {
const DATABASE_NAME: ABDatabaseName = ABDatabaseName::Annotations;
const QUERY: &'static str = {
"SELECT
ZANNOTATIONSELECTEDTEXT, -- 0 body
ZANNOTATIONNOTE, -- 1 notes
ZANNOTATIONSTYLE, -- 2 style
ZANNOTATIONUUID, -- 3 id
ZAEANNOTATION.ZANNOTATIONASSETID, -- 4 book_id
ZANNOTATIONCREATIONDATE, -- 5 created
ZANNOTATIONMODIFICATIONDATE, -- 6 modified
ZANNOTATIONLOCATION -- 7 location
FROM ZAEANNOTATION
WHERE ZANNOTATIONSELECTEDTEXT IS NOT NULL
AND ZANNOTATIONDELETED = 0
ORDER BY ZANNOTATIONASSETID;"
};
fn from_row(row: &Row<'_>) -> Self {
let notes: Option<String> = row.get_unwrap(1);
let style: u8 = row.get_unwrap(2);
let created: f64 = row.get_unwrap(5);
let modified: f64 = row.get_unwrap(6);
let epubcfi: String = row.get_unwrap(7);
Self {
body: row.get_unwrap(0),
style: Self::int_to_style(style),
notes: notes.unwrap_or_default(),
tags: BTreeSet::new(),
metadata: AnnotationMetadata {
id: row.get_unwrap(3),
book_id: row.get_unwrap(4),
created: created.into(),
modified: modified.into(),
location: epubcfi::parse(&epubcfi),
epubcfi,
},
}
}
}
impl Ord for Annotation {
fn cmp(&self, other: &Self) -> Ordering {
self.metadata.cmp(&other.metadata)
}
}
impl PartialOrd for Annotation {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.metadata.partial_cmp(&other.metadata)
}
}
impl PartialEq for Annotation {
fn eq(&self, other: &Self) -> bool {
self.metadata == other.metadata
}
}
#[derive(Debug, Default, Clone, Eq, Serialize)]
pub struct AnnotationMetadata {
pub id: String,
pub book_id: String,
pub created: DateTimeUtc,
pub modified: DateTimeUtc,
pub location: String,
pub epubcfi: String,
}
impl Ord for AnnotationMetadata {
fn cmp(&self, other: &Self) -> Ordering {
self.location.cmp(&other.location)
}
}
impl PartialOrd for AnnotationMetadata {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.location.partial_cmp(&other.location)
}
}
impl PartialEq for AnnotationMetadata {
fn eq(&self, other: &Self) -> bool {
self.location == other.location
}
}
#[cfg(test)]
mod test_annotations {
use super::*;
#[test]
fn test_cmp_annotations() {
let mut a1 = Annotation::default();
a1.metadata.location = epubcfi::parse("epubcfi(/6/10[c01]!/4/10/3,:335,:749)");
let mut a2 = Annotation::default();
a2.metadata.location = epubcfi::parse("epubcfi(/6/12[c02]!/4/26/3,:68,:493)");
assert!(a1 < a2);
}
}