Compare commits
	
		
			No commits in common. "158910a61fdb2712879eef2eaa43f15b8b4bb901" and "320a46c0f313e6ba6f048f94d6635ac42362bc6e" have entirely different histories. 
		
	
	
		
			158910a61f
			...
			320a46c0f3
		
	
		| 
						 | 
				
			
			@ -24,9 +24,6 @@ create table devices (
 | 
			
		|||
    user_id bigint not null
 | 
			
		||||
        references users (id)
 | 
			
		||||
        on delete cascade,
 | 
			
		||||
    sync_group_id bigint
 | 
			
		||||
        references sync_group (id)
 | 
			
		||||
        on delete set null,
 | 
			
		||||
 | 
			
		||||
    caption text not null,
 | 
			
		||||
    type text not null,
 | 
			
		||||
| 
						 | 
				
			
			@ -34,10 +31,6 @@ create table devices (
 | 
			
		|||
    unique (user_id, device_id)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
create table sync_groups (
 | 
			
		||||
    id integer primary key not null
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
create table device_subscriptions (
 | 
			
		||||
    id integer primary key not null,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,12 +5,10 @@ mod schema;
 | 
			
		|||
use diesel::connection::InstrumentationEvent;
 | 
			
		||||
use diesel::r2d2::CustomizeConnection;
 | 
			
		||||
use diesel::Connection;
 | 
			
		||||
 | 
			
		||||
pub use models::device::{Device, DeviceType, NewDevice};
 | 
			
		||||
pub use models::device_subscription::{DeviceSubscription, NewDeviceSubscription};
 | 
			
		||||
pub use models::episode_action::{ActionType, EpisodeAction, NewEpisodeAction};
 | 
			
		||||
pub use models::session::Session;
 | 
			
		||||
pub use models::sync_group::SyncGroup;
 | 
			
		||||
pub use models::user::{NewUser, User};
 | 
			
		||||
 | 
			
		||||
pub use repository::SqliteRepository;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ pub struct Device {
 | 
			
		|||
    pub user_id: i64,
 | 
			
		||||
    pub caption: String,
 | 
			
		||||
    pub type_: DeviceType,
 | 
			
		||||
    pub sync_group_id: Option<i64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize, Insertable)]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,5 +2,4 @@ pub mod device;
 | 
			
		|||
pub mod device_subscription;
 | 
			
		||||
pub mod episode_action;
 | 
			
		||||
pub mod session;
 | 
			
		||||
pub mod sync_group;
 | 
			
		||||
pub mod user;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,33 +0,0 @@
 | 
			
		|||
use diesel::{
 | 
			
		||||
    dsl::{exists, not},
 | 
			
		||||
    prelude::*,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::db::schema::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Queryable, Selectable)]
 | 
			
		||||
#[diesel(table_name = sync_groups)]
 | 
			
		||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
 | 
			
		||||
pub struct SyncGroup {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SyncGroup {
 | 
			
		||||
    pub fn new(conn: &mut SqliteConnection) -> QueryResult<Self> {
 | 
			
		||||
        diesel::insert_into(sync_groups::table)
 | 
			
		||||
            .default_values()
 | 
			
		||||
            .returning(SyncGroup::as_returning())
 | 
			
		||||
            .get_result(conn)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn remove_unused(conn: &mut SqliteConnection) -> QueryResult<usize> {
 | 
			
		||||
        diesel::delete(
 | 
			
		||||
            sync_groups::table.filter(not(exists(
 | 
			
		||||
                devices::table
 | 
			
		||||
                    .select(1.into_sql::<diesel::sql_types::Integer>())
 | 
			
		||||
                    .filter(devices::sync_group_id.eq(sync_groups::id.nullable())),
 | 
			
		||||
            ))),
 | 
			
		||||
        )
 | 
			
		||||
        .execute(conn)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ use diesel::prelude::*;
 | 
			
		|||
 | 
			
		||||
use super::SqliteRepository;
 | 
			
		||||
use crate::{
 | 
			
		||||
    db::{self, schema::*, SyncGroup},
 | 
			
		||||
    db::{self, schema::*},
 | 
			
		||||
    gpodder,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,58 +102,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
 | 
			
		|||
        user: &gpodder::User,
 | 
			
		||||
        device_ids: Vec<&str>,
 | 
			
		||||
    ) -> Result<i64, gpodder::AuthErr> {
 | 
			
		||||
        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)
 | 
			
		||||
        })?)
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn remove_from_sync_group(
 | 
			
		||||
| 
						 | 
				
			
			@ -161,23 +110,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
 | 
			
		|||
        user: &gpodder::User,
 | 
			
		||||
        device_ids: Vec<&str>,
 | 
			
		||||
    ) -> Result<(), gpodder::AuthErr> {
 | 
			
		||||
        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(())
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn synchronize_sync_group(
 | 
			
		||||
| 
						 | 
				
			
			@ -191,36 +124,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
 | 
			
		|||
    fn devices_by_sync_group(
 | 
			
		||||
        &self,
 | 
			
		||||
        user: &gpodder::User,
 | 
			
		||||
    ) -> 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))
 | 
			
		||||
    ) -> Result<(Vec<gpodder::Device>, Vec<Vec<gpodder::Device>>), gpodder::AuthErr> {
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,6 @@ diesel::table! {
 | 
			
		|||
        id -> BigInt,
 | 
			
		||||
        device_id -> Text,
 | 
			
		||||
        user_id -> BigInt,
 | 
			
		||||
        sync_group_id -> Nullable<BigInt>,
 | 
			
		||||
        caption -> Text,
 | 
			
		||||
        #[sql_name = "type"]
 | 
			
		||||
        type_ -> Text,
 | 
			
		||||
| 
						 | 
				
			
			@ -46,12 +45,6 @@ diesel::table! {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
diesel::table! {
 | 
			
		||||
    sync_groups (id) {
 | 
			
		||||
        id -> BigInt,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
diesel::table! {
 | 
			
		||||
    users (id) {
 | 
			
		||||
        id -> BigInt,
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +64,5 @@ diesel::allow_tables_to_appear_in_same_query!(
 | 
			
		|||
    devices,
 | 
			
		||||
    episode_actions,
 | 
			
		||||
    sessions,
 | 
			
		||||
    sync_groups,
 | 
			
		||||
    users,
 | 
			
		||||
);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 device IDs for the user, grouped per sync group
 | 
			
		||||
    /// Return all devices 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<String>, Vec<Vec<String>>), AuthErr>;
 | 
			
		||||
    ) -> Result<(Vec<Device>, Vec<Vec<Device>>), AuthErr>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait SubscriptionRepository {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ impl GpodderRepository {
 | 
			
		|||
    pub fn devices_by_sync_group(
 | 
			
		||||
        &self,
 | 
			
		||||
        user: &models::User,
 | 
			
		||||
    ) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr> {
 | 
			
		||||
    ) -> Result<(Vec<models::Device>, Vec<Vec<models::Device>>), AuthErr> {
 | 
			
		||||
        self.store.devices_by_sync_group(user)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue