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
|
user_id bigint not null
|
||||||
references users (id)
|
references users (id)
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
sync_group_id bigint
|
|
||||||
references sync_group (id)
|
|
||||||
on delete set null,
|
|
||||||
|
|
||||||
caption text not null,
|
caption text not null,
|
||||||
type text not null,
|
type text not null,
|
||||||
|
@ -34,10 +31,6 @@ create table devices (
|
||||||
unique (user_id, device_id)
|
unique (user_id, device_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table sync_groups (
|
|
||||||
id integer primary key not null
|
|
||||||
);
|
|
||||||
|
|
||||||
create table device_subscriptions (
|
create table device_subscriptions (
|
||||||
id integer primary key not null,
|
id integer primary key not null,
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,10 @@ mod schema;
|
||||||
use diesel::connection::InstrumentationEvent;
|
use diesel::connection::InstrumentationEvent;
|
||||||
use diesel::r2d2::CustomizeConnection;
|
use diesel::r2d2::CustomizeConnection;
|
||||||
use diesel::Connection;
|
use diesel::Connection;
|
||||||
|
|
||||||
pub use models::device::{Device, DeviceType, NewDevice};
|
pub use models::device::{Device, DeviceType, NewDevice};
|
||||||
pub use models::device_subscription::{DeviceSubscription, NewDeviceSubscription};
|
pub use models::device_subscription::{DeviceSubscription, NewDeviceSubscription};
|
||||||
pub use models::episode_action::{ActionType, EpisodeAction, NewEpisodeAction};
|
pub use models::episode_action::{ActionType, EpisodeAction, NewEpisodeAction};
|
||||||
pub use models::session::Session;
|
pub use models::session::Session;
|
||||||
pub use models::sync_group::SyncGroup;
|
|
||||||
pub use models::user::{NewUser, User};
|
pub use models::user::{NewUser, User};
|
||||||
|
|
||||||
pub use repository::SqliteRepository;
|
pub use repository::SqliteRepository;
|
||||||
|
|
|
@ -21,7 +21,6 @@ pub struct Device {
|
||||||
pub user_id: i64,
|
pub user_id: i64,
|
||||||
pub caption: String,
|
pub caption: String,
|
||||||
pub type_: DeviceType,
|
pub type_: DeviceType,
|
||||||
pub sync_group_id: Option<i64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Insertable)]
|
#[derive(Deserialize, Insertable)]
|
||||||
|
|
|
@ -2,5 +2,4 @@ pub mod device;
|
||||||
pub mod device_subscription;
|
pub mod device_subscription;
|
||||||
pub mod episode_action;
|
pub mod episode_action;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod sync_group;
|
|
||||||
pub mod user;
|
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 super::SqliteRepository;
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{self, schema::*, SyncGroup},
|
db::{self, schema::*},
|
||||||
gpodder,
|
gpodder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,58 +102,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
||||||
user: &gpodder::User,
|
user: &gpodder::User,
|
||||||
device_ids: Vec<&str>,
|
device_ids: Vec<&str>,
|
||||||
) -> Result<i64, gpodder::AuthErr> {
|
) -> Result<i64, gpodder::AuthErr> {
|
||||||
let conn = &mut self.pool.get()?;
|
todo!()
|
||||||
|
|
||||||
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(
|
fn remove_from_sync_group(
|
||||||
|
@ -161,23 +110,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
||||||
user: &gpodder::User,
|
user: &gpodder::User,
|
||||||
device_ids: Vec<&str>,
|
device_ids: Vec<&str>,
|
||||||
) -> Result<(), gpodder::AuthErr> {
|
) -> Result<(), gpodder::AuthErr> {
|
||||||
let conn = &mut self.pool.get()?;
|
todo!()
|
||||||
|
|
||||||
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(
|
fn synchronize_sync_group(
|
||||||
|
@ -191,36 +124,7 @@ impl gpodder::DeviceRepository for SqliteRepository {
|
||||||
fn devices_by_sync_group(
|
fn devices_by_sync_group(
|
||||||
&self,
|
&self,
|
||||||
user: &gpodder::User,
|
user: &gpodder::User,
|
||||||
) -> Result<(Vec<String>, Vec<Vec<String>>), gpodder::AuthErr> {
|
) -> Result<(Vec<gpodder::Device>, Vec<Vec<gpodder::Device>>), gpodder::AuthErr> {
|
||||||
let mut not_synchronized = Vec::new();
|
todo!()
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ diesel::table! {
|
||||||
id -> BigInt,
|
id -> BigInt,
|
||||||
device_id -> Text,
|
device_id -> Text,
|
||||||
user_id -> BigInt,
|
user_id -> BigInt,
|
||||||
sync_group_id -> Nullable<BigInt>,
|
|
||||||
caption -> Text,
|
caption -> Text,
|
||||||
#[sql_name = "type"]
|
#[sql_name = "type"]
|
||||||
type_ -> Text,
|
type_ -> Text,
|
||||||
|
@ -46,12 +45,6 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
|
||||||
sync_groups (id) {
|
|
||||||
id -> BigInt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
users (id) {
|
users (id) {
|
||||||
id -> BigInt,
|
id -> BigInt,
|
||||||
|
@ -71,6 +64,5 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
devices,
|
devices,
|
||||||
episode_actions,
|
episode_actions,
|
||||||
sessions,
|
sessions,
|
||||||
sync_groups,
|
|
||||||
users,
|
users,
|
||||||
);
|
);
|
||||||
|
|
|
@ -92,7 +92,7 @@ pub trait DeviceRepository {
|
||||||
/// Remove the devices from their respective sync groups
|
/// Remove the devices from their respective sync groups
|
||||||
fn remove_from_sync_group(&self, user: &User, device_ids: Vec<&str>) -> Result<(), AuthErr>;
|
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
|
/// # Returns
|
||||||
///
|
///
|
||||||
|
@ -100,7 +100,7 @@ pub trait DeviceRepository {
|
||||||
fn devices_by_sync_group(
|
fn devices_by_sync_group(
|
||||||
&self,
|
&self,
|
||||||
user: &User,
|
user: &User,
|
||||||
) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr>;
|
) -> Result<(Vec<Device>, Vec<Vec<Device>>), AuthErr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SubscriptionRepository {
|
pub trait SubscriptionRepository {
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl GpodderRepository {
|
||||||
pub fn devices_by_sync_group(
|
pub fn devices_by_sync_group(
|
||||||
&self,
|
&self,
|
||||||
user: &models::User,
|
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)
|
self.store.devices_by_sync_group(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue