From 808deabad3b32aab7c6d92962da93ef260a4c553 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 15 Jan 2025 21:33:25 +0100 Subject: [PATCH] breaking(sqlite): Add metadata into calendar store for more efficient queries in the future --- ...08dec56c6910d1fb1d0811c005e3aa51dce5f.json | 12 +++++ ...994f38f079c93d8240acbda10bb7a3f066d20.json | 12 +++++ ...b69e6c0603e73e383bc040735c5d39376408d.json | 12 ----- ...2fd840165e807d17dd99078e54732f8d009c7.json | 12 ----- crates/store/src/calendar/object.rs | 14 ++++-- crates/store_sqlite/migrations/1_calendar.sql | 14 ++++++ .../store_sqlite/migrations/2_addressbook.sql | 2 + crates/store_sqlite/src/calendar_store.rs | 44 ++++++++++++++----- 8 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 .sqlx/query-2068bc20fbe8a95bccb9910b62408dec56c6910d1fb1d0811c005e3aa51dce5f.json create mode 100644 .sqlx/query-450d5f1324ef2bcbded66215e37994f38f079c93d8240acbda10bb7a3f066d20.json delete mode 100644 .sqlx/query-754b0274e0d180f39c3d4bcf4f0b69e6c0603e73e383bc040735c5d39376408d.json delete mode 100644 .sqlx/query-f158acc3d2de055093df796d1712fd840165e807d17dd99078e54732f8d009c7.json diff --git a/.sqlx/query-2068bc20fbe8a95bccb9910b62408dec56c6910d1fb1d0811c005e3aa51dce5f.json b/.sqlx/query-2068bc20fbe8a95bccb9910b62408dec56c6910d1fb1d0811c005e3aa51dce5f.json new file mode 100644 index 0000000..e39c35e --- /dev/null +++ b/.sqlx/query-2068bc20fbe8a95bccb9910b62408dec56c6910d1fb1d0811c005e3aa51dce5f.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "REPLACE INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 8 + }, + "nullable": [] + }, + "hash": "2068bc20fbe8a95bccb9910b62408dec56c6910d1fb1d0811c005e3aa51dce5f" +} diff --git a/.sqlx/query-450d5f1324ef2bcbded66215e37994f38f079c93d8240acbda10bb7a3f066d20.json b/.sqlx/query-450d5f1324ef2bcbded66215e37994f38f079c93d8240acbda10bb7a3f066d20.json new file mode 100644 index 0000000..8e7df0c --- /dev/null +++ b/.sqlx/query-450d5f1324ef2bcbded66215e37994f38f079c93d8240acbda10bb7a3f066d20.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 8 + }, + "nullable": [] + }, + "hash": "450d5f1324ef2bcbded66215e37994f38f079c93d8240acbda10bb7a3f066d20" +} diff --git a/.sqlx/query-754b0274e0d180f39c3d4bcf4f0b69e6c0603e73e383bc040735c5d39376408d.json b/.sqlx/query-754b0274e0d180f39c3d4bcf4f0b69e6c0603e73e383bc040735c5d39376408d.json deleted file mode 100644 index 89f4211..0000000 --- a/.sqlx/query-754b0274e0d180f39c3d4bcf4f0b69e6c0603e73e383bc040735c5d39376408d.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO calendarobjects (principal, cal_id, id, ics) VALUES (?, ?, ?, ?)", - "describe": { - "columns": [], - "parameters": { - "Right": 4 - }, - "nullable": [] - }, - "hash": "754b0274e0d180f39c3d4bcf4f0b69e6c0603e73e383bc040735c5d39376408d" -} diff --git a/.sqlx/query-f158acc3d2de055093df796d1712fd840165e807d17dd99078e54732f8d009c7.json b/.sqlx/query-f158acc3d2de055093df796d1712fd840165e807d17dd99078e54732f8d009c7.json deleted file mode 100644 index 05310f5..0000000 --- a/.sqlx/query-f158acc3d2de055093df796d1712fd840165e807d17dd99078e54732f8d009c7.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "REPLACE INTO calendarobjects (principal, cal_id, id, ics) VALUES (?, ?, ?, ?)", - "describe": { - "columns": [], - "parameters": { - "Right": 4 - }, - "nullable": [] - }, - "hash": "f158acc3d2de055093df796d1712fd840165e807d17dd99078e54732f8d009c7" -} diff --git a/crates/store/src/calendar/object.rs b/crates/store/src/calendar/object.rs index b399f76..1d03dd4 100644 --- a/crates/store/src/calendar/object.rs +++ b/crates/store/src/calendar/object.rs @@ -8,9 +8,9 @@ use std::{collections::HashMap, io::BufReader}; #[derive(Debug, Clone)] // specified in https://datatracker.ietf.org/doc/html/rfc5545#section-3.6 pub enum CalendarObjectType { - Event, - Journal, - Todo, + Event = 0, + Todo = 1, + Journal = 2, } #[derive(Debug, Clone)] @@ -114,6 +114,14 @@ impl CalendarObject { } } + pub fn get_object_type(&self) -> CalendarObjectType { + match self.data { + CalendarObjectComponent::Todo(_) => CalendarObjectType::Todo, + CalendarObjectComponent::Event(_) => CalendarObjectType::Event, + CalendarObjectComponent::Journal(_) => CalendarObjectType::Journal, + } + } + pub fn get_first_occurence(&self) -> Result, Error> { match &self.data { CalendarObjectComponent::Event(event) => event.get_first_occurence(), diff --git a/crates/store_sqlite/migrations/1_calendar.sql b/crates/store_sqlite/migrations/1_calendar.sql index fa27e9b..20af6ed 100644 --- a/crates/store_sqlite/migrations/1_calendar.sql +++ b/crates/store_sqlite/migrations/1_calendar.sql @@ -21,11 +21,23 @@ CREATE TABLE calendarobjects ( ics TEXT NOT NULL, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, deleted_at DATETIME, + + -- For more efficient calendar-queries + first_occurence DATE, + last_occurence DATE, + etag TEXT, + object_type INTEGER NOT NULL, -- VEVENT(0)/VTODO(1)/VJOURNAL(2) + PRIMARY KEY (principal, cal_id, id), FOREIGN KEY (principal, cal_id) REFERENCES calendars (principal, id) ON DELETE CASCADE ); +CREATE INDEX idx_calobjs_first_occurence ON calendarobjects (first_occurence); +CREATE INDEX idx_calobjs_last_occurence ON calendarobjects (last_occurence); +CREATE INDEX idx_calobjs_etag ON calendarobjects (etag); +CREATE INDEX idx_calobjs_obj_type ON calendarobjects (object_type); + CREATE TABLE calendarobjectchangelog ( principal TEXT NOT NULL, cal_id TEXT NOT NULL, @@ -37,3 +49,5 @@ CREATE TABLE calendarobjectchangelog ( FOREIGN KEY (principal, cal_id) REFERENCES calendars (principal, id) ON DELETE CASCADE ); + +CREATE INDEX idx_calobj_log_cal ON calendarobjectchangelog (cal_id); diff --git a/crates/store_sqlite/migrations/2_addressbook.sql b/crates/store_sqlite/migrations/2_addressbook.sql index 9ed621a..83cf273 100644 --- a/crates/store_sqlite/migrations/2_addressbook.sql +++ b/crates/store_sqlite/migrations/2_addressbook.sql @@ -32,3 +32,5 @@ CREATE TABLE addressobjectchangelog ( FOREIGN KEY (principal, addressbook_id) REFERENCES addressbooks (principal, id) ON DELETE CASCADE ); + +CREATE INDEX idx_addrobj_log_cal ON addressobjectchangelog (addressbook_id); diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 91814e2..c3ca341 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -1,6 +1,7 @@ use super::ChangeOperation; use async_trait::async_trait; use derive_more::derive::Constructor; +use rustical_store::calendar::CalDateTime; use rustical_store::synctoken::format_synctoken; use rustical_store::{Calendar, CalendarObject, CalendarStore, Error}; use rustical_store::{CollectionOperation, CollectionOperationType}; @@ -277,22 +278,45 @@ impl CalendarStore for SqliteCalendarStore { let (object_id, ics) = (object.get_id(), object.get_ics()); + let first_occurence = object + .get_first_occurence() + .ok() + .flatten() + .as_ref() + .map(CalDateTime::date); + let last_occurence = object + .get_last_occurence() + .ok() + .flatten() + .as_ref() + .map(CalDateTime::date); + let etag = object.get_etag(); + let object_type = object.get_object_type() as u8; + (if overwrite { sqlx::query!( - "REPLACE INTO calendarobjects (principal, cal_id, id, ics) VALUES (?, ?, ?, ?)", - principal, - cal_id, - object_id, - ics - ) - } else { - // If the object already exists a database error is thrown and handled in error.rs - sqlx::query!( - "INSERT INTO calendarobjects (principal, cal_id, id, ics) VALUES (?, ?, ?, ?)", + "REPLACE INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", principal, cal_id, object_id, ics, + first_occurence, + last_occurence, + etag, + object_type, + ) + } else { + // If the object already exists a database error is thrown and handled in error.rs + sqlx::query!( + "INSERT INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + principal, + cal_id, + object_id, + ics, + first_occurence, + last_occurence, + etag, + object_type, ) }) .execute(&mut *tx)