feat: implement sync group merge, unsync and devices by sync group
parent
4a45bebc9f
commit
158910a61f
|
@ -3,7 +3,7 @@ use diesel::prelude::*;
|
|||
|
||||
use super::SqliteRepository;
|
||||
use crate::{
|
||||
db::{self, schema::*},
|
||||
db::{self, schema::*, SyncGroup},
|
||||
gpodder,
|
||||
};
|
||||
|
||||
|
@ -102,7 +102,58 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
|||
user: &gpodder::User,
|
||||
device_ids: Vec<&str>,
|
||||
) -> Result<i64, gpodder::AuthErr> {
|
||||
todo!()
|
||||
let conn = &mut self.pool.get()?;
|
||||
|
||||
Ok(conn.transaction(|conn| {
|
||||
let devices: Vec<(i64, Option<i64>)> = devices::table
|
||||
.select((devices::id, devices::sync_group_id))
|
||||
.filter(
|
||||
devices::user_id
|
||||
.eq(user.id)
|
||||
.and(devices::device_id.eq_any(device_ids)),
|
||||
)
|
||||
.get_results(conn)?;
|
||||
|
||||
let mut sync_group_ids: Vec<i64> = devices
|
||||
.iter()
|
||||
.filter_map(|(_, group_id)| *group_id)
|
||||
.collect();
|
||||
|
||||
// Remove any duplicates, giving us each sync group ID once
|
||||
sync_group_ids.sort();
|
||||
sync_group_ids.dedup();
|
||||
|
||||
// If any of the devices are already in a sync group, we reuse the first one we find.
|
||||
// Otherwise, we generate a new one.
|
||||
let sync_group_id = if let Some(id) = sync_group_ids.pop() {
|
||||
id
|
||||
} else {
|
||||
db::SyncGroup::new(conn)?.id
|
||||
};
|
||||
|
||||
// Move all devices in the other sync groups into the new sync group
|
||||
diesel::update(
|
||||
devices::table.filter(devices::sync_group_id.eq_any(sync_group_ids.iter())),
|
||||
)
|
||||
.set(devices::sync_group_id.eq(sync_group_id))
|
||||
.execute(conn)?;
|
||||
|
||||
// Add the non-synchronized devices into the new sync group
|
||||
let unsynced_device_ids =
|
||||
devices
|
||||
.iter()
|
||||
.filter_map(|(id, group_id)| if group_id.is_none() { Some(id) } else { None });
|
||||
|
||||
diesel::update(devices::table.filter(devices::id.eq_any(unsynced_device_ids)))
|
||||
.set(devices::sync_group_id.eq(sync_group_id))
|
||||
.execute(conn)?;
|
||||
|
||||
// Remove the other now unused sync groups
|
||||
diesel::delete(sync_groups::table.filter(sync_groups::id.eq_any(sync_group_ids)))
|
||||
.execute(conn)?;
|
||||
|
||||
Ok::<_, diesel::result::Error>(sync_group_id)
|
||||
})?)
|
||||
}
|
||||
|
||||
fn remove_from_sync_group(
|
||||
|
@ -110,7 +161,23 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
|||
user: &gpodder::User,
|
||||
device_ids: Vec<&str>,
|
||||
) -> Result<(), gpodder::AuthErr> {
|
||||
todo!()
|
||||
let conn = &mut self.pool.get()?;
|
||||
|
||||
diesel::update(
|
||||
devices::table.filter(
|
||||
devices::user_id
|
||||
.eq(user.id)
|
||||
.and(devices::device_id.eq_any(device_ids)),
|
||||
),
|
||||
)
|
||||
.set(devices::sync_group_id.eq(None::<i64>))
|
||||
.execute(conn)?;
|
||||
|
||||
// This is in a different transaction on purpose, as the success of this removal shouldn't
|
||||
// fail the entire query
|
||||
SyncGroup::remove_unused(conn)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn synchronize_sync_group(
|
||||
|
@ -124,7 +191,36 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
|||
fn devices_by_sync_group(
|
||||
&self,
|
||||
user: &gpodder::User,
|
||||
) -> Result<(Vec<gpodder::Device>, Vec<Vec<gpodder::Device>>), gpodder::AuthErr> {
|
||||
todo!()
|
||||
) -> Result<(Vec<String>, Vec<Vec<String>>), gpodder::AuthErr> {
|
||||
let mut not_synchronized = Vec::new();
|
||||
let mut synchronized = Vec::new();
|
||||
|
||||
let conn = &mut self.pool.get()?;
|
||||
let mut devices = devices::table
|
||||
.select((devices::device_id, devices::sync_group_id))
|
||||
.filter(devices::user_id.eq(user.id))
|
||||
.order(devices::sync_group_id)
|
||||
.load_iter::<(String, Option<i64>), _>(conn)?;
|
||||
|
||||
let mut cur_group = &mut not_synchronized;
|
||||
let mut cur_group_id: Option<i64> = None;
|
||||
|
||||
while let Some((device_id, group_id)) = devices.next().transpose()? {
|
||||
if group_id != cur_group_id {
|
||||
if group_id.is_none() {
|
||||
cur_group = &mut not_synchronized;
|
||||
} else {
|
||||
synchronized.push(Vec::new());
|
||||
let index = synchronized.len() - 1;
|
||||
cur_group = &mut synchronized[index];
|
||||
}
|
||||
|
||||
cur_group_id = group_id;
|
||||
}
|
||||
|
||||
cur_group.push(device_id);
|
||||
}
|
||||
|
||||
Ok((not_synchronized, synchronized))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ pub trait DeviceRepository {
|
|||
/// Remove the devices from their respective sync groups
|
||||
fn remove_from_sync_group(&self, user: &User, device_ids: Vec<&str>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Return all devices for the user, grouped per sync group
|
||||
/// Return all device IDs for the user, grouped per sync group
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
@ -100,7 +100,7 @@ pub trait DeviceRepository {
|
|||
fn devices_by_sync_group(
|
||||
&self,
|
||||
user: &User,
|
||||
) -> Result<(Vec<Device>, Vec<Vec<Device>>), AuthErr>;
|
||||
) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait SubscriptionRepository {
|
||||
|
|
|
@ -106,7 +106,7 @@ impl GpodderRepository {
|
|||
pub fn devices_by_sync_group(
|
||||
&self,
|
||||
user: &models::User,
|
||||
) -> Result<(Vec<models::Device>, Vec<Vec<models::Device>>), AuthErr> {
|
||||
) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr> {
|
||||
self.store.devices_by_sync_group(user)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue