mirror of
https://github.com/lennart-k/rustical.git
synced 2026-01-30 14:08:23 +00:00
make calendar object id extrinsic
This commit is contained in:
@@ -21,7 +21,7 @@ pub async fn get_objects_calendar_multiget<C: CalendarStore>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
store: &C,
|
store: &C,
|
||||||
) -> Result<(Vec<CalendarObject>, Vec<String>), Error> {
|
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>), Error> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
let mut not_found = vec![];
|
let mut not_found = vec![];
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ pub async fn get_objects_calendar_multiget<C: CalendarStore>(
|
|||||||
let filename = filename.trim_start_matches('/');
|
let filename = filename.trim_start_matches('/');
|
||||||
if let Some(object_id) = filename.strip_suffix(".ics") {
|
if let Some(object_id) = filename.strip_suffix(".ics") {
|
||||||
match store.get_object(principal, cal_id, object_id, false).await {
|
match store.get_object(principal, cal_id, object_id, false).await {
|
||||||
Ok(object) => result.push(object),
|
Ok(object) => result.push((object_id.to_owned(), object)),
|
||||||
Err(rustical_store::Error::NotFound) => not_found.push(href.to_string()),
|
Err(rustical_store::Error::NotFound) => not_found.push(href.to_string()),
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ END:VCALENDAR";
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_comp_filter_matching() {
|
fn test_comp_filter_matching() {
|
||||||
let object = CalendarObject::from_ics(ICS.to_string(), None).unwrap();
|
let object = CalendarObject::from_ics(ICS.to_string()).unwrap();
|
||||||
|
|
||||||
let comp_filter = CompFilterElement {
|
let comp_filter = CompFilterElement {
|
||||||
is_not_defined: Some(()),
|
is_not_defined: Some(()),
|
||||||
@@ -231,7 +231,7 @@ END:VCALENDAR";
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_comp_filter_time_range() {
|
fn test_comp_filter_time_range() {
|
||||||
let object = CalendarObject::from_ics(ICS.to_string(), None).unwrap();
|
let object = CalendarObject::from_ics(ICS.to_string()).unwrap();
|
||||||
|
|
||||||
let comp_filter = CompFilterElement {
|
let comp_filter = CompFilterElement {
|
||||||
is_not_defined: None,
|
is_not_defined: None,
|
||||||
@@ -286,7 +286,7 @@ END:VCALENDAR";
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_match_timezone() {
|
fn test_match_timezone() {
|
||||||
let object = CalendarObject::from_ics(ICS.to_string(), None).unwrap();
|
let object = CalendarObject::from_ics(ICS.to_string()).unwrap();
|
||||||
|
|
||||||
let comp_filter = CompFilterElement {
|
let comp_filter = CompFilterElement {
|
||||||
is_not_defined: None,
|
is_not_defined: None,
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ pub async fn get_objects_calendar_query<C: CalendarStore>(
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
store: &C,
|
store: &C,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
let mut objects = store
|
let mut objects = store
|
||||||
.calendar_query(principal, cal_id, cal_query.into())
|
.calendar_query(principal, cal_id, cal_query.into())
|
||||||
.await?;
|
.await?;
|
||||||
if let Some(filter) = &cal_query.filter {
|
if let Some(filter) = &cal_query.filter {
|
||||||
objects.retain(|object| filter.matches(object.get_inner()));
|
objects.retain(|(_id, object)| filter.matches(object.get_inner()));
|
||||||
}
|
}
|
||||||
Ok(objects)
|
Ok(objects)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const FILTER_2: &str = r#"
|
|||||||
#[case(ICS_1, FILTER_1, true)]
|
#[case(ICS_1, FILTER_1, true)]
|
||||||
#[case(ICS_1, FILTER_2, false)]
|
#[case(ICS_1, FILTER_2, false)]
|
||||||
fn yeet(#[case] ics: &str, #[case] filter: &str, #[case] matches: bool) {
|
fn yeet(#[case] ics: &str, #[case] filter: &str, #[case] matches: bool) {
|
||||||
let obj = CalendarObject::from_ics(ics.to_owned(), None).unwrap();
|
let obj = CalendarObject::from_ics(ics.to_owned()).unwrap();
|
||||||
let filter = FilterElement::parse_str(filter).unwrap();
|
let filter = FilterElement::parse_str(filter).unwrap();
|
||||||
assert_eq!(matches, filter.matches(obj.get_inner()));
|
assert_eq!(matches, filter.matches(obj.get_inner()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl ReportRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn objects_response(
|
fn objects_response(
|
||||||
objects: Vec<CalendarObject>,
|
objects: Vec<(String, CalendarObject)>,
|
||||||
not_found: Vec<String>,
|
not_found: Vec<String>,
|
||||||
path: &str,
|
path: &str,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
@@ -60,11 +60,12 @@ fn objects_response(
|
|||||||
prop: &PropfindType<CalendarObjectPropWrapperName>,
|
prop: &PropfindType<CalendarObjectPropWrapperName>,
|
||||||
) -> Result<MultistatusElement<CalendarObjectPropWrapper, String>, Error> {
|
) -> Result<MultistatusElement<CalendarObjectPropWrapper, String>, Error> {
|
||||||
let mut responses = Vec::new();
|
let mut responses = Vec::new();
|
||||||
for object in objects {
|
for (object_id, object) in objects {
|
||||||
let path = format!("{}/{}.ics", path, object.get_id());
|
let path = format!("{path}/{object_id}.ics");
|
||||||
responses.push(
|
responses.push(
|
||||||
CalendarObjectResource {
|
CalendarObjectResource {
|
||||||
object,
|
object,
|
||||||
|
object_id,
|
||||||
principal: principal.to_owned(),
|
principal: principal.to_owned(),
|
||||||
}
|
}
|
||||||
.propfind(&path, prop, None, puri, user)?,
|
.propfind(&path, prop, None, puri, user)?,
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ pub async fn handle_sync_collection<C: CalendarStore>(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut responses = Vec::new();
|
let mut responses = Vec::new();
|
||||||
for object in new_objects {
|
for (object_id, object) in new_objects {
|
||||||
let path = format!("{}/{}.ics", path, object.get_id());
|
let path = format!("{}/{}.ics", path, &object_id);
|
||||||
responses.push(
|
responses.push(
|
||||||
CalendarObjectResource {
|
CalendarObjectResource {
|
||||||
object,
|
object,
|
||||||
|
object_id,
|
||||||
principal: principal.to_owned(),
|
principal: principal.to_owned(),
|
||||||
}
|
}
|
||||||
.propfind(&path, &sync_collection.prop, None, puri, user)?,
|
.propfind(&path, &sync_collection.prop, None, puri, user)?,
|
||||||
|
|||||||
@@ -78,8 +78,9 @@ impl<C: CalendarStore, S: SubscriptionStore> ResourceService for CalendarResourc
|
|||||||
.get_objects(principal, cal_id)
|
.get_objects(principal, cal_id)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|object| CalendarObjectResource {
|
.map(|(object_id, object)| CalendarObjectResource {
|
||||||
object,
|
object,
|
||||||
|
object_id,
|
||||||
principal: principal.to_owned(),
|
principal: principal.to_owned(),
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
@@ -91,7 +92,7 @@ impl<C: CalendarStore, S: SubscriptionStore> ResourceService for CalendarResourc
|
|||||||
file: Self::Resource,
|
file: Self::Resource,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.cal_store
|
self.cal_store
|
||||||
.update_calendar(principal.to_owned(), cal_id.to_owned(), file.into())
|
.update_calendar(principal, cal_id, file.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,13 +94,13 @@ pub async fn put_event<C: CalendarStore>(
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(object) = CalendarObject::from_ics(body.clone(), Some(object_id)) else {
|
let Ok(object) = CalendarObject::from_ics(body.clone()) else {
|
||||||
debug!("invalid calendar data:\n{body}");
|
debug!("invalid calendar data:\n{body}");
|
||||||
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
||||||
};
|
};
|
||||||
let etag = object.get_etag();
|
let etag = object.get_etag();
|
||||||
cal_store
|
cal_store
|
||||||
.put_object(principal, calendar_id, object, overwrite)
|
.put_object(&principal, &calendar_id, &object_id, object, overwrite)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use super::prop::{
|
use super::prop::{
|
||||||
CalendarData, CalendarObjectProp, CalendarObjectPropName, CalendarObjectPropWrapper,
|
CalendarData, CalendarObjectProp, CalendarObjectPropName, CalendarObjectPropWrapper,
|
||||||
CalendarObjectPropWrapperName,
|
CalendarObjectPropWrapperName,
|
||||||
@@ -14,16 +12,18 @@ use rustical_dav::{
|
|||||||
};
|
};
|
||||||
use rustical_ical::CalendarObject;
|
use rustical_ical::CalendarObject;
|
||||||
use rustical_store::auth::Principal;
|
use rustical_store::auth::Principal;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[derive(Clone, From, Into)]
|
#[derive(Clone, From, Into)]
|
||||||
pub struct CalendarObjectResource {
|
pub struct CalendarObjectResource {
|
||||||
pub object: CalendarObject,
|
pub object: CalendarObject,
|
||||||
|
pub object_id: String,
|
||||||
pub principal: String,
|
pub principal: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceName for CalendarObjectResource {
|
impl ResourceName for CalendarObjectResource {
|
||||||
fn get_name(&self) -> Cow<'_, str> {
|
fn get_name(&self) -> Cow<'_, str> {
|
||||||
Cow::from(format!("{}.ics", self.object.get_id()))
|
Cow::from(format!("{}.ics", self.object_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ impl<C: CalendarStore> ResourceService for CalendarObjectResourceService<C> {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(CalendarObjectResource {
|
Ok(CalendarObjectResource {
|
||||||
object,
|
object,
|
||||||
|
object_id: object_id.to_owned(),
|
||||||
principal: principal.to_owned(),
|
principal: principal.to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,13 +62,12 @@ impl rustical_xml::ValueDeserialize for CalendarObjectType {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CalendarObject {
|
pub struct CalendarObject {
|
||||||
id: String,
|
|
||||||
inner: IcalCalendarObject,
|
inner: IcalCalendarObject,
|
||||||
ics: String,
|
ics: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CalendarObject {
|
impl CalendarObject {
|
||||||
pub fn from_ics(ics: String, id: Option<String>) -> Result<Self, Error> {
|
pub fn from_ics(ics: String) -> Result<Self, Error> {
|
||||||
let mut parser: ComponentParser<_, IcalCalendarObject> =
|
let mut parser: ComponentParser<_, IcalCalendarObject> =
|
||||||
ComponentParser::new(ics.as_bytes());
|
ComponentParser::new(ics.as_bytes());
|
||||||
let inner = parser.next().ok_or(Error::MissingCalendar)??;
|
let inner = parser.next().ok_or(Error::MissingCalendar)??;
|
||||||
@@ -78,11 +77,7 @@ impl CalendarObject {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { inner, ics })
|
||||||
id: id.unwrap_or_else(|| inner.get_uid().to_owned()),
|
|
||||||
inner,
|
|
||||||
ics,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -95,11 +90,6 @@ impl CalendarObject {
|
|||||||
self.inner.get_uid()
|
self.inner.get_uid()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_id(&self) -> &str {
|
|
||||||
&self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_etag(&self) -> String {
|
pub fn get_etag(&self) -> String {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ END:VCALENDAR
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_calendar_object() {
|
fn parse_calendar_object() {
|
||||||
let object = CalendarObject::from_ics(MULTI_VEVENT.to_string(), None).unwrap();
|
let object = CalendarObject::from_ics(MULTI_VEVENT.to_string()).unwrap();
|
||||||
object.get_inner().expand_recurrence(None, None);
|
object.get_inner().expand_recurrence(None, None);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ pub trait CalendarStore: Send + Sync + 'static {
|
|||||||
|
|
||||||
async fn update_calendar(
|
async fn update_calendar(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
id: String,
|
id: &str,
|
||||||
calendar: Calendar,
|
calendar: Calendar,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
async fn insert_calendar(&self, calendar: Calendar) -> Result<(), Error>;
|
async fn insert_calendar(&self, calendar: Calendar) -> Result<(), Error>;
|
||||||
@@ -46,7 +46,7 @@ pub trait CalendarStore: Send + Sync + 'static {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
synctoken: i64,
|
synctoken: i64,
|
||||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error>;
|
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error>;
|
||||||
|
|
||||||
/// Since the <calendar-query> rules are rather complex this function
|
/// Since the <calendar-query> rules are rather complex this function
|
||||||
/// is only meant to do some prefiltering
|
/// is only meant to do some prefiltering
|
||||||
@@ -55,7 +55,7 @@ pub trait CalendarStore: Send + Sync + 'static {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
_query: CalendarQuery,
|
_query: CalendarQuery,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
self.get_objects(principal, cal_id).await
|
self.get_objects(principal, cal_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ pub trait CalendarStore: Send + Sync + 'static {
|
|||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
) -> Result<Vec<CalendarObject>, Error>;
|
) -> Result<Vec<(String, CalendarObject)>, Error>;
|
||||||
async fn get_object(
|
async fn get_object(
|
||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
@@ -79,20 +79,26 @@ pub trait CalendarStore: Send + Sync + 'static {
|
|||||||
) -> Result<CalendarObject, Error>;
|
) -> Result<CalendarObject, Error>;
|
||||||
async fn put_objects(
|
async fn put_objects(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
cal_id: String,
|
cal_id: &str,
|
||||||
objects: Vec<CalendarObject>,
|
objects: Vec<(String, CalendarObject)>,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
async fn put_object(
|
async fn put_object(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
cal_id: String,
|
cal_id: &str,
|
||||||
|
object_id: &str,
|
||||||
object: CalendarObject,
|
object: CalendarObject,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.put_objects(principal, cal_id, vec![object], overwrite)
|
self.put_objects(
|
||||||
.await
|
principal,
|
||||||
|
cal_id,
|
||||||
|
vec![(object_id.to_owned(), object)],
|
||||||
|
overwrite,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
async fn delete_object(
|
async fn delete_object(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::CalendarStore;
|
use crate::{Calendar, CalendarStore, calendar_store::CalendarQuery};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rustical_ical::CalendarObject;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub trait PrefixedCalendarStore: CalendarStore {
|
pub trait PrefixedCalendarStore: CalendarStore {
|
||||||
@@ -51,11 +52,11 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
|
|
||||||
async fn update_calendar(
|
async fn update_calendar(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
id: String,
|
id: &str,
|
||||||
calendar: crate::Calendar,
|
calendar: Calendar,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
self.store_for_id(&id)
|
self.store_for_id(id)
|
||||||
.update_calendar(principal, id, calendar)
|
.update_calendar(principal, id, calendar)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -88,7 +89,7 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
synctoken: i64,
|
synctoken: i64,
|
||||||
) -> Result<(Vec<rustical_ical::CalendarObject>, Vec<String>, i64), crate::Error> {
|
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), crate::Error> {
|
||||||
self.store_for_id(cal_id)
|
self.store_for_id(cal_id)
|
||||||
.sync_changes(principal, cal_id, synctoken)
|
.sync_changes(principal, cal_id, synctoken)
|
||||||
.await
|
.await
|
||||||
@@ -97,7 +98,7 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
async fn import_calendar(
|
async fn import_calendar(
|
||||||
&self,
|
&self,
|
||||||
calendar: crate::Calendar,
|
calendar: crate::Calendar,
|
||||||
objects: Vec<rustical_ical::CalendarObject>,
|
objects: Vec<CalendarObject>,
|
||||||
merge_existing: bool,
|
merge_existing: bool,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
self.store_for_id(&calendar.id)
|
self.store_for_id(&calendar.id)
|
||||||
@@ -109,8 +110,8 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
query: crate::calendar_store::CalendarQuery,
|
query: CalendarQuery,
|
||||||
) -> Result<Vec<rustical_ical::CalendarObject>, crate::Error> {
|
) -> Result<Vec<(String, CalendarObject)>, crate::Error> {
|
||||||
self.store_for_id(cal_id)
|
self.store_for_id(cal_id)
|
||||||
.calendar_query(principal, cal_id, query)
|
.calendar_query(principal, cal_id, query)
|
||||||
.await
|
.await
|
||||||
@@ -141,7 +142,7 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
) -> Result<Vec<rustical_ical::CalendarObject>, crate::Error> {
|
) -> Result<Vec<(String, CalendarObject)>, crate::Error> {
|
||||||
self.store_for_id(cal_id)
|
self.store_for_id(cal_id)
|
||||||
.get_objects(principal, cal_id)
|
.get_objects(principal, cal_id)
|
||||||
.await
|
.await
|
||||||
@@ -149,12 +150,12 @@ impl CalendarStore for CombinedCalendarStore {
|
|||||||
|
|
||||||
async fn put_objects(
|
async fn put_objects(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
cal_id: String,
|
cal_id: &str,
|
||||||
objects: Vec<rustical_ical::CalendarObject>,
|
objects: Vec<(String, CalendarObject)>,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), crate::Error> {
|
) -> Result<(), crate::Error> {
|
||||||
self.store_for_id(&cal_id)
|
self.store_for_id(cal_id)
|
||||||
.put_objects(principal, cal_id, objects, overwrite)
|
.put_objects(principal, cal_id, objects, overwrite)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,16 +34,19 @@ fn benchmark(c: &mut Criterion) {
|
|||||||
cal_store
|
cal_store
|
||||||
});
|
});
|
||||||
|
|
||||||
let object = CalendarObject::from_ics(include_str!("ical_event.ics").to_owned(), None).unwrap();
|
let row = (
|
||||||
|
"asd".to_owned(),
|
||||||
|
CalendarObject::from_ics(include_str!("ical_event.ics").to_owned()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
let batch_size = 1000;
|
let batch_size = 1000;
|
||||||
let objects: Vec<_> = std::iter::repeat_n(object.clone(), batch_size).collect();
|
let objects: Vec<_> = std::iter::repeat_n(row.clone(), batch_size).collect();
|
||||||
|
|
||||||
c.bench_function("put_batch", |b| {
|
c.bench_function("put_batch", |b| {
|
||||||
b.to_async(&runtime).iter(async || {
|
b.to_async(&runtime).iter(async || {
|
||||||
// yeet
|
// yeet
|
||||||
cal_store
|
cal_store
|
||||||
.put_objects("user".to_owned(), "okwow".to_owned(), objects.clone(), true)
|
.put_objects("user", "okwow", objects.clone(), true)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
@@ -54,7 +57,7 @@ fn benchmark(c: &mut Criterion) {
|
|||||||
// yeet
|
// yeet
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
cal_store
|
cal_store
|
||||||
.put_object("user".to_owned(), "okwow".to_owned(), object.clone(), true)
|
.put_object("user", "okwow", &row.0, row.1.clone(), true)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::addressbook_store::SqliteAddressbookStore;
|
use crate::addressbook_store::SqliteAddressbookStore;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use rustical_ical::{AddressObject, CalendarObject, CalendarObjectType};
|
use rustical_ical::{CalendarObject, CalendarObjectType};
|
||||||
use rustical_store::{
|
use rustical_store::{
|
||||||
Addressbook, AddressbookStore, Calendar, CalendarMetadata, CalendarStore, CollectionMetadata,
|
Addressbook, AddressbookStore, Calendar, CalendarMetadata, CalendarStore, CollectionMetadata,
|
||||||
Error, PrefixedCalendarStore,
|
Error, PrefixedCalendarStore,
|
||||||
@@ -268,10 +268,11 @@ impl CalendarStore for SqliteAddressbookStore {
|
|||||||
#[instrument]
|
#[instrument]
|
||||||
async fn update_calendar(
|
async fn update_calendar(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
id: String,
|
id: &str,
|
||||||
mut calendar: Calendar,
|
mut calendar: Calendar,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
assert_eq!(principal, calendar.principal);
|
||||||
assert_eq!(id, calendar.id);
|
assert_eq!(id, calendar.id);
|
||||||
calendar.id = calendar
|
calendar.id = calendar
|
||||||
.id
|
.id
|
||||||
@@ -323,7 +324,7 @@ impl CalendarStore for SqliteAddressbookStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
synctoken: i64,
|
synctoken: i64,
|
||||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
|
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error> {
|
||||||
let cal_id = cal_id
|
let cal_id = cal_id
|
||||||
.strip_prefix(BIRTHDAYS_PREFIX)
|
.strip_prefix(BIRTHDAYS_PREFIX)
|
||||||
.ok_or(Error::NotFound)?;
|
.ok_or(Error::NotFound)?;
|
||||||
@@ -356,7 +357,7 @@ impl CalendarStore for SqliteAddressbookStore {
|
|||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
todo!()
|
todo!()
|
||||||
// let cal_id = cal_id
|
// let cal_id = cal_id
|
||||||
// .strip_prefix(BIRTHDAYS_PREFIX)
|
// .strip_prefix(BIRTHDAYS_PREFIX)
|
||||||
@@ -397,9 +398,9 @@ impl CalendarStore for SqliteAddressbookStore {
|
|||||||
#[instrument]
|
#[instrument]
|
||||||
async fn put_objects(
|
async fn put_objects(
|
||||||
&self,
|
&self,
|
||||||
_principal: String,
|
_principal: &str,
|
||||||
_cal_id: String,
|
_cal_id: &str,
|
||||||
_objects: Vec<CalendarObject>,
|
_objects: Vec<(String, CalendarObject)>,
|
||||||
_overwrite: bool,
|
_overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Err(Error::ReadOnly)
|
Err(Error::ReadOnly)
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ struct CalendarObjectRow {
|
|||||||
uid: String,
|
uid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<CalendarObjectRow> for CalendarObject {
|
impl TryFrom<CalendarObjectRow> for (String, CalendarObject) {
|
||||||
type Error = rustical_store::Error;
|
type Error = rustical_store::Error;
|
||||||
|
|
||||||
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
||||||
let object = Self::from_ics(value.ics, Some(value.id))?;
|
let object = CalendarObject::from_ics(value.ics)?;
|
||||||
if object.get_uid() != value.uid {
|
if object.get_uid() != value.uid {
|
||||||
return Err(rustical_store::Error::IcalError(
|
return Err(rustical_store::Error::IcalError(
|
||||||
rustical_ical::Error::InvalidData(format!(
|
rustical_ical::Error::InvalidData(format!(
|
||||||
@@ -35,7 +35,7 @@ impl TryFrom<CalendarObjectRow> for CalendarObject {
|
|||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(object)
|
Ok((value.id, object))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +280,8 @@ impl SqliteCalendarStore {
|
|||||||
|
|
||||||
async fn _update_calendar<'e, E: Executor<'e, Database = Sqlite>>(
|
async fn _update_calendar<'e, E: Executor<'e, Database = Sqlite>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
principal: String,
|
principal: &str,
|
||||||
id: String,
|
id: &str,
|
||||||
calendar: Calendar,
|
calendar: Calendar,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let comp_event = calendar.components.contains(&CalendarObjectType::Event);
|
let comp_event = calendar.components.contains(&CalendarObjectType::Event);
|
||||||
@@ -379,7 +379,7 @@ impl SqliteCalendarStore {
|
|||||||
executor: E,
|
executor: E,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
CalendarObjectRow,
|
CalendarObjectRow,
|
||||||
"SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
"SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
||||||
@@ -398,7 +398,7 @@ impl SqliteCalendarStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
query: CalendarQuery,
|
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
|
// 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
|
// miss any objects because of timezone differences
|
||||||
// I've previously tried NaiveDate::MIN,MAX, but it seems like sqlite cannot handle these
|
// I've previously tried NaiveDate::MIN,MAX, but it seems like sqlite cannot handle these
|
||||||
@@ -434,7 +434,7 @@ impl SqliteCalendarStore {
|
|||||||
object_id: &str,
|
object_id: &str,
|
||||||
show_deleted: bool,
|
show_deleted: bool,
|
||||||
) -> Result<CalendarObject, Error> {
|
) -> Result<CalendarObject, Error> {
|
||||||
sqlx::query_as!(
|
let (row_id, object) = sqlx::query_as!(
|
||||||
CalendarObjectRow,
|
CalendarObjectRow,
|
||||||
"SELECT id, uid, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
"SELECT id, uid, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
||||||
principal,
|
principal,
|
||||||
@@ -445,7 +445,9 @@ impl SqliteCalendarStore {
|
|||||||
.fetch_one(executor)
|
.fetch_one(executor)
|
||||||
.await
|
.await
|
||||||
.map_err(crate::Error::from)?
|
.map_err(crate::Error::from)?
|
||||||
.try_into()
|
.try_into()?;
|
||||||
|
assert_eq!(object_id, row_id);
|
||||||
|
Ok(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
@@ -453,10 +455,11 @@ impl SqliteCalendarStore {
|
|||||||
executor: E,
|
executor: E,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
|
object_id: &str,
|
||||||
object: &CalendarObject,
|
object: &CalendarObject,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let (object_id, uid, ics) = (object.get_id(), object.get_uid(), object.get_ics());
|
let (uid, ics) = (object.get_uid(), object.get_ics());
|
||||||
|
|
||||||
let first_occurence = object
|
let first_occurence = object
|
||||||
.get_inner()
|
.get_inner()
|
||||||
@@ -562,7 +565,7 @@ impl SqliteCalendarStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
synctoken: i64,
|
synctoken: i64,
|
||||||
) -> Result<(Vec<CalendarObject>, Vec<String>, i64), Error> {
|
) -> Result<(Vec<(String, CalendarObject)>, Vec<String>, i64), Error> {
|
||||||
struct Row {
|
struct Row {
|
||||||
object_id: String,
|
object_id: String,
|
||||||
synctoken: i64,
|
synctoken: i64,
|
||||||
@@ -589,7 +592,7 @@ impl SqliteCalendarStore {
|
|||||||
|
|
||||||
for Row { object_id, .. } in changes {
|
for Row { object_id, .. } in changes {
|
||||||
match Self::_get_object(&mut *conn, principal, cal_id, &object_id, false).await {
|
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(rustical_store::Error::NotFound) => deleted_objects.push(object_id),
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
@@ -629,8 +632,8 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
#[instrument]
|
#[instrument]
|
||||||
async fn update_calendar(
|
async fn update_calendar(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
id: String,
|
id: &str,
|
||||||
calendar: Calendar,
|
calendar: Calendar,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Self::_update_calendar(&self.db, principal, id, calendar).await
|
Self::_update_calendar(&self.db, principal, id, calendar).await
|
||||||
@@ -698,14 +701,23 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
|
|
||||||
let mut sync_token = None;
|
let mut sync_token = None;
|
||||||
for object in objects {
|
for object in objects {
|
||||||
Self::_put_object(&mut *tx, &calendar.principal, &calendar.id, &object, false).await?;
|
let object_id = object.get_uid();
|
||||||
|
Self::_put_object(
|
||||||
|
&mut *tx,
|
||||||
|
&calendar.principal,
|
||||||
|
&calendar.id,
|
||||||
|
object_id,
|
||||||
|
&object,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
sync_token = Some(
|
sync_token = Some(
|
||||||
Self::log_object_operation(
|
Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&calendar.principal,
|
&calendar.principal,
|
||||||
&calendar.id,
|
&calendar.id,
|
||||||
object.get_id(),
|
object_id,
|
||||||
ChangeOperation::Add,
|
ChangeOperation::Add,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
@@ -731,7 +743,7 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
query: CalendarQuery,
|
query: CalendarQuery,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
Self::_calendar_query(&self.db, principal, cal_id, query).await
|
Self::_calendar_query(&self.db, principal, cal_id, query).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +774,7 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
&self,
|
&self,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<(String, CalendarObject)>, Error> {
|
||||||
Self::_get_objects(&self.db, principal, cal_id).await
|
Self::_get_objects(&self.db, principal, cal_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,9 +792,9 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
#[instrument]
|
#[instrument]
|
||||||
async fn put_objects(
|
async fn put_objects(
|
||||||
&self,
|
&self,
|
||||||
principal: String,
|
principal: &str,
|
||||||
cal_id: String,
|
cal_id: &str,
|
||||||
objects: Vec<CalendarObject>,
|
objects: Vec<(String, CalendarObject)>,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self
|
let mut tx = self
|
||||||
@@ -798,18 +810,21 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut sync_token = None;
|
let mut sync_token = None;
|
||||||
for object in objects {
|
for (object_id, object) in objects {
|
||||||
sync_token = Some(
|
sync_token = Some(
|
||||||
Self::log_object_operation(
|
Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&principal,
|
&principal,
|
||||||
&cal_id,
|
&cal_id,
|
||||||
object.get_id(),
|
&object_id,
|
||||||
ChangeOperation::Add,
|
ChangeOperation::Add,
|
||||||
)
|
)
|
||||||
.await?,
|
.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)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
@@ -887,7 +902,7 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
synctoken: i64,
|
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
|
Self::_sync_changes(&self.db, principal, cal_id, synctoken).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user