mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-29 07:09:08 +00:00
Make CalendarObject id an extrinsic property
This commit is contained in:
@@ -34,10 +34,14 @@ fn benchmark(c: &mut Criterion) {
|
||||
cal_store
|
||||
});
|
||||
|
||||
let object = CalendarObject::from_ics(include_str!("ical_event.ics").to_owned(), None).unwrap();
|
||||
let object = CalendarObject::from_ics(include_str!("ical_event.ics").to_owned()).unwrap();
|
||||
|
||||
let batch_size = 1000;
|
||||
let objects: Vec<_> = std::iter::repeat_n(object.clone(), batch_size).collect();
|
||||
let objects: Vec<_> = std::iter::repeat_n(
|
||||
(object.get_inner().get_uid().to_owned(), object.clone()),
|
||||
batch_size,
|
||||
)
|
||||
.collect();
|
||||
|
||||
c.bench_function("put_batch", |b| {
|
||||
b.to_async(&runtime).iter(async || {
|
||||
@@ -54,7 +58,12 @@ fn benchmark(c: &mut Criterion) {
|
||||
// yeet
|
||||
for _ in 0..1000 {
|
||||
cal_store
|
||||
.put_object("user".to_owned(), "okwow".to_owned(), object.clone(), true)
|
||||
.put_object(
|
||||
"user".to_owned(),
|
||||
"okwow".to_owned(),
|
||||
(object.get_inner().get_uid().to_owned(), object.clone()),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use rustical_store::{
|
||||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use std::collections::HashMap;
|
||||
use tracing::instrument;
|
||||
|
||||
pub const BIRTHDAYS_PREFIX: &str = "_birthdays_";
|
||||
@@ -312,7 +311,7 @@ impl CalendarStore for SqliteAddressbookStore {
|
||||
async fn import_calendar(
|
||||
&self,
|
||||
_calendar: Calendar,
|
||||
_objects: Vec<CalendarObject>,
|
||||
_objects: Vec<(String, CalendarObject)>,
|
||||
_merge_existing: bool,
|
||||
) -> Result<(), Error> {
|
||||
Err(Error::ReadOnly)
|
||||
@@ -324,17 +323,19 @@ impl CalendarStore for SqliteAddressbookStore {
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
synctoken: i64,
|
||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
|
||||
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error> {
|
||||
let cal_id = cal_id
|
||||
.strip_prefix(BIRTHDAYS_PREFIX)
|
||||
.ok_or(Error::NotFound)?;
|
||||
let (objects, deleted_objects, new_synctoken) =
|
||||
AddressbookStore::sync_changes(self, principal, cal_id, synctoken).await?;
|
||||
let objects: Result<Vec<Option<CalendarObject>>, rustical_ical::Error> = objects
|
||||
let objects = objects
|
||||
.iter()
|
||||
.map(AddressObject::get_birthday_object)
|
||||
.map(AddressObject::get_significant_dates)
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect();
|
||||
let objects = objects?.into_iter().flatten().collect();
|
||||
|
||||
Ok((objects, deleted_objects, new_synctoken))
|
||||
}
|
||||
@@ -356,22 +357,18 @@ impl CalendarStore for SqliteAddressbookStore {
|
||||
&self,
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
) -> Result<Vec<CalendarObject>, Error> {
|
||||
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||
let cal_id = cal_id
|
||||
.strip_prefix(BIRTHDAYS_PREFIX)
|
||||
.ok_or(Error::NotFound)?;
|
||||
let objects: Result<Vec<HashMap<&'static str, CalendarObject>>, rustical_ical::Error> =
|
||||
AddressbookStore::get_objects(self, principal, cal_id)
|
||||
.await?
|
||||
.iter()
|
||||
.map(AddressObject::get_significant_dates)
|
||||
.collect();
|
||||
let objects = objects?
|
||||
Ok(AddressbookStore::get_objects(self, principal, cal_id)
|
||||
.await?
|
||||
.iter()
|
||||
.map(AddressObject::get_significant_dates)
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.flat_map(HashMap::into_values)
|
||||
.collect();
|
||||
|
||||
Ok(objects)
|
||||
.flatten()
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
@@ -386,11 +383,14 @@ impl CalendarStore for SqliteAddressbookStore {
|
||||
.strip_prefix(BIRTHDAYS_PREFIX)
|
||||
.ok_or(Error::NotFound)?;
|
||||
let (addressobject_id, date_type) = object_id.rsplit_once('-').ok_or(Error::NotFound)?;
|
||||
AddressbookStore::get_object(self, principal, cal_id, addressobject_id, show_deleted)
|
||||
.await?
|
||||
.get_significant_dates()?
|
||||
.remove(date_type)
|
||||
.ok_or(Error::NotFound)
|
||||
let addr_object =
|
||||
AddressbookStore::get_object(self, principal, cal_id, addressobject_id, show_deleted)
|
||||
.await?;
|
||||
match date_type {
|
||||
"birthday" => addr_object.get_birthday_object()?.ok_or(Error::NotFound),
|
||||
"anniversary" => addr_object.get_anniversary_object()?.ok_or(Error::NotFound),
|
||||
_ => Err(Error::NotFound),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
@@ -398,7 +398,7 @@ impl CalendarStore for SqliteAddressbookStore {
|
||||
&self,
|
||||
_principal: String,
|
||||
_cal_id: String,
|
||||
_objects: Vec<CalendarObject>,
|
||||
_objects: Vec<(String, CalendarObject)>,
|
||||
_overwrite: bool,
|
||||
) -> Result<(), Error> {
|
||||
Err(Error::ReadOnly)
|
||||
|
||||
@@ -21,11 +21,21 @@ struct CalendarObjectRow {
|
||||
uid: String,
|
||||
}
|
||||
|
||||
impl TryFrom<CalendarObjectRow> for (String, CalendarObject) {
|
||||
type Error = rustical_store::Error;
|
||||
|
||||
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
||||
let object_id = value.id.clone();
|
||||
|
||||
Ok((object_id, value.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<CalendarObjectRow> for CalendarObject {
|
||||
type Error = rustical_store::Error;
|
||||
|
||||
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
||||
let object = Self::from_ics(value.ics, Some(value.id))?;
|
||||
let object = Self::from_ics(value.ics)?;
|
||||
if object.get_inner().get_uid() != value.uid {
|
||||
return Err(rustical_store::Error::IcalError(
|
||||
rustical_ical::Error::InvalidData(format!(
|
||||
@@ -379,7 +389,7 @@ impl SqliteCalendarStore {
|
||||
executor: E,
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
) -> Result<Vec<CalendarObject>, Error> {
|
||||
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||
sqlx::query_as!(
|
||||
CalendarObjectRow,
|
||||
"SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
||||
@@ -389,7 +399,7 @@ impl SqliteCalendarStore {
|
||||
.fetch_all(executor)
|
||||
.await.map_err(crate::Error::from)?
|
||||
.into_iter()
|
||||
.map(std::convert::TryInto::try_into)
|
||||
.map(TryInto::try_into)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -398,7 +408,7 @@ impl SqliteCalendarStore {
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
query: CalendarQuery,
|
||||
) -> Result<Vec<CalendarObject>, Error> {
|
||||
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||
// We extend our query interval by one day in each direction since we really don't want to
|
||||
// miss any objects because of timezone differences
|
||||
// I've previously tried NaiveDate::MIN,MAX, but it seems like sqlite cannot handle these
|
||||
@@ -423,7 +433,7 @@ impl SqliteCalendarStore {
|
||||
.await
|
||||
.map_err(crate::Error::from)?
|
||||
.into_iter()
|
||||
.map(std::convert::TryInto::try_into)
|
||||
.map(TryInto::try_into)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -453,14 +463,11 @@ impl SqliteCalendarStore {
|
||||
executor: E,
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
object_id: &str,
|
||||
object: &CalendarObject,
|
||||
overwrite: bool,
|
||||
) -> Result<(), Error> {
|
||||
let (object_id, uid, ics) = (
|
||||
object.get_id(),
|
||||
object.get_inner().get_uid(),
|
||||
object.get_ics(),
|
||||
);
|
||||
let (uid, ics) = (object.get_inner().get_uid(), object.get_ics());
|
||||
|
||||
let first_occurence = object
|
||||
.get_inner()
|
||||
@@ -567,7 +574,7 @@ impl SqliteCalendarStore {
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
synctoken: i64,
|
||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
|
||||
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error> {
|
||||
struct Row {
|
||||
object_id: String,
|
||||
synctoken: i64,
|
||||
@@ -594,7 +601,7 @@ impl SqliteCalendarStore {
|
||||
|
||||
for Row { object_id, .. } in changes {
|
||||
match Self::_get_object(&mut *conn, principal, cal_id, &object_id, false).await {
|
||||
Ok(object) => objects.push(object),
|
||||
Ok(object) => objects.push((object_id, object)),
|
||||
Err(rustical_store::Error::NotFound) => deleted_objects.push(object_id),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
@@ -679,7 +686,7 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
async fn import_calendar(
|
||||
&self,
|
||||
calendar: Calendar,
|
||||
objects: Vec<CalendarObject>,
|
||||
objects: Vec<(String, CalendarObject)>,
|
||||
merge_existing: bool,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx = self
|
||||
@@ -702,15 +709,23 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
}
|
||||
|
||||
let mut sync_token = None;
|
||||
for object in objects {
|
||||
Self::_put_object(&mut *tx, &calendar.principal, &calendar.id, &object, false).await?;
|
||||
for (object_id, object) in objects {
|
||||
Self::_put_object(
|
||||
&mut *tx,
|
||||
&calendar.principal,
|
||||
&calendar.id,
|
||||
&object_id,
|
||||
&object,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
sync_token = Some(
|
||||
Self::log_object_operation(
|
||||
&mut tx,
|
||||
&calendar.principal,
|
||||
&calendar.id,
|
||||
object.get_id(),
|
||||
&object_id,
|
||||
ChangeOperation::Add,
|
||||
)
|
||||
.await?,
|
||||
@@ -736,7 +751,7 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
query: CalendarQuery,
|
||||
) -> Result<Vec<CalendarObject>, Error> {
|
||||
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||
Self::_calendar_query(&self.db, principal, cal_id, query).await
|
||||
}
|
||||
|
||||
@@ -767,7 +782,7 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
&self,
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
) -> Result<Vec<CalendarObject>, Error> {
|
||||
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||
Self::_get_objects(&self.db, principal, cal_id).await
|
||||
}
|
||||
|
||||
@@ -787,7 +802,7 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
&self,
|
||||
principal: String,
|
||||
cal_id: String,
|
||||
objects: Vec<CalendarObject>,
|
||||
objects: Vec<(String, CalendarObject)>,
|
||||
overwrite: bool,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx = self
|
||||
@@ -803,18 +818,21 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
}
|
||||
|
||||
let mut sync_token = None;
|
||||
for object in objects {
|
||||
for (object_id, object) in objects {
|
||||
sync_token = Some(
|
||||
Self::log_object_operation(
|
||||
&mut tx,
|
||||
&principal,
|
||||
&cal_id,
|
||||
object.get_id(),
|
||||
&object_id,
|
||||
ChangeOperation::Add,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
Self::_put_object(&mut *tx, &principal, &cal_id, &object, overwrite).await?;
|
||||
Self::_put_object(
|
||||
&mut *tx, &principal, &cal_id, &object_id, &object, overwrite,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
tx.commit().await.map_err(crate::Error::from)?;
|
||||
@@ -892,7 +910,7 @@ impl CalendarStore for SqliteCalendarStore {
|
||||
principal: &str,
|
||||
cal_id: &str,
|
||||
synctoken: i64,
|
||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
|
||||
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error> {
|
||||
Self::_sync_changes(&self.db, principal, cal_id, synctoken).await
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user