mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-02 11:13:29 +00:00
media data sync (#2102)
* basic sync operation backfill * media data sync * sync entry helpers * fix sync generator * nicer * re-add key_id
This commit is contained in:
parent
393a907b57
commit
c533d12df0
|
@ -1,10 +1,11 @@
|
|||
use sd_prisma::{
|
||||
prisma::{
|
||||
file_path, label, label_on_object, location, object, tag, tag_on_object, PrismaClient,
|
||||
file_path, label, label_on_object, location, media_data, object, tag, tag_on_object,
|
||||
PrismaClient,
|
||||
},
|
||||
prisma_sync,
|
||||
};
|
||||
use sd_sync::OperationFactory;
|
||||
use sd_sync::{option_sync_entry, OperationFactory};
|
||||
use sd_utils::chain_optional_iter;
|
||||
use serde_json::json;
|
||||
|
||||
|
@ -23,28 +24,26 @@ pub async fn backfill_operations(db: &PrismaClient, sync: &crate::Manager, insta
|
|||
locations
|
||||
.into_iter()
|
||||
.flat_map(|l| {
|
||||
use location::*;
|
||||
|
||||
sync.shared_create(
|
||||
prisma_sync::location::SyncId { pub_id: l.pub_id },
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[
|
||||
l.name.map(|v| (location::name::NAME, json!(v))),
|
||||
l.path.map(|v| (location::path::NAME, json!(v))),
|
||||
l.total_capacity
|
||||
.map(|v| (location::total_capacity::NAME, json!(v))),
|
||||
l.available_capacity
|
||||
.map(|v| (location::available_capacity::NAME, json!(v))),
|
||||
l.size_in_bytes
|
||||
.map(|v| (location::size_in_bytes::NAME, json!(v))),
|
||||
l.is_archived
|
||||
.map(|v| (location::is_archived::NAME, json!(v))),
|
||||
l.generate_preview_media
|
||||
.map(|v| (location::generate_preview_media::NAME, json!(v))),
|
||||
l.sync_preview_media
|
||||
.map(|v| (location::sync_preview_media::NAME, json!(v))),
|
||||
l.hidden.map(|v| (location::hidden::NAME, json!(v))),
|
||||
l.date_created
|
||||
.map(|v| (location::date_created::NAME, json!(v))),
|
||||
option_sync_entry!(l.name, name),
|
||||
option_sync_entry!(l.path, path),
|
||||
option_sync_entry!(l.total_capacity, total_capacity),
|
||||
option_sync_entry!(l.available_capacity, available_capacity),
|
||||
option_sync_entry!(l.size_in_bytes, size_in_bytes),
|
||||
option_sync_entry!(l.is_archived, is_archived),
|
||||
option_sync_entry!(
|
||||
l.generate_preview_media,
|
||||
generate_preview_media
|
||||
),
|
||||
option_sync_entry!(l.sync_preview_media, sync_preview_media),
|
||||
option_sync_entry!(l.hidden, hidden),
|
||||
option_sync_entry!(l.date_created, date_created),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -62,20 +61,65 @@ pub async fn backfill_operations(db: &PrismaClient, sync: &crate::Manager, insta
|
|||
objects
|
||||
.into_iter()
|
||||
.flat_map(|o| {
|
||||
use object::*;
|
||||
|
||||
sync.shared_create(
|
||||
prisma_sync::object::SyncId { pub_id: o.pub_id },
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[
|
||||
o.kind.map(|v| (object::kind::NAME, json!(v))),
|
||||
o.hidden.map(|v| (object::hidden::NAME, json!(v))),
|
||||
o.favorite.map(|v| (object::favorite::NAME, json!(v))),
|
||||
o.important.map(|v| (object::important::NAME, json!(v))),
|
||||
o.note.map(|v| (object::note::NAME, json!(v))),
|
||||
o.date_created
|
||||
.map(|v| (object::date_created::NAME, json!(v))),
|
||||
o.date_accessed
|
||||
.map(|v| (object::date_accessed::NAME, json!(v))),
|
||||
option_sync_entry!(o.kind, kind),
|
||||
option_sync_entry!(o.hidden, hidden),
|
||||
option_sync_entry!(o.favorite, favorite),
|
||||
option_sync_entry!(o.important, important),
|
||||
option_sync_entry!(o.note, note),
|
||||
option_sync_entry!(o.date_created, date_created),
|
||||
option_sync_entry!(o.date_accessed, date_accessed),
|
||||
],
|
||||
),
|
||||
)
|
||||
})
|
||||
.map(|o| crdt_op_unchecked_db(&o, instance_id))
|
||||
.collect(),
|
||||
)
|
||||
.exec()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let media_datas = db
|
||||
.media_data()
|
||||
.find_many(vec![])
|
||||
.include(media_data::include!({
|
||||
object: select { pub_id }
|
||||
}))
|
||||
.exec()
|
||||
.await
|
||||
.unwrap();
|
||||
db.crdt_operation()
|
||||
.create_many(
|
||||
media_datas
|
||||
.into_iter()
|
||||
.flat_map(|md| {
|
||||
use media_data::*;
|
||||
|
||||
sync.shared_create(
|
||||
prisma_sync::media_data::SyncId {
|
||||
object: prisma_sync::object::SyncId {
|
||||
pub_id: md.object.pub_id,
|
||||
},
|
||||
},
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[
|
||||
option_sync_entry!(md.resolution, resolution),
|
||||
option_sync_entry!(md.media_date, media_date),
|
||||
option_sync_entry!(md.media_location, media_location),
|
||||
option_sync_entry!(md.camera_data, camera_data),
|
||||
option_sync_entry!(md.artist, artist),
|
||||
option_sync_entry!(md.description, description),
|
||||
option_sync_entry!(md.copyright, copyright),
|
||||
option_sync_entry!(md.exif_version, exif_version),
|
||||
option_sync_entry!(md.epoch_time, epoch_time),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -103,35 +147,31 @@ pub async fn backfill_operations(db: &PrismaClient, sync: &crate::Manager, insta
|
|||
file_paths
|
||||
.into_iter()
|
||||
.flat_map(|fp| {
|
||||
use file_path::*;
|
||||
|
||||
sync.shared_create(
|
||||
prisma_sync::file_path::SyncId { pub_id: fp.pub_id },
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[
|
||||
fp.is_dir.map(|v| (file_path::is_dir::NAME, json!(v))),
|
||||
fp.cas_id.map(|v| (file_path::cas_id::NAME, json!(v))),
|
||||
fp.integrity_checksum
|
||||
.map(|v| (file_path::integrity_checksum::NAME, json!(v))),
|
||||
fp.location.map(|l| {
|
||||
(
|
||||
file_path::location::NAME,
|
||||
json!(prisma_sync::location::SyncId { pub_id: l.pub_id }),
|
||||
)
|
||||
}),
|
||||
fp.materialized_path
|
||||
.map(|v| (file_path::materialized_path::NAME, json!(v))),
|
||||
fp.name.map(|v| (file_path::name::NAME, json!(v))),
|
||||
fp.extension.map(|v| (file_path::extension::NAME, json!(v))),
|
||||
fp.hidden.map(|v| (file_path::hidden::NAME, json!(v))),
|
||||
fp.size_in_bytes_bytes
|
||||
.map(|v| (file_path::size_in_bytes_bytes::NAME, json!(v))),
|
||||
fp.inode.map(|v| (file_path::inode::NAME, json!(v))),
|
||||
fp.date_created
|
||||
.map(|v| (file_path::date_created::NAME, json!(v))),
|
||||
fp.date_modified
|
||||
.map(|v| (file_path::date_modified::NAME, json!(v))),
|
||||
fp.date_indexed
|
||||
.map(|v| (file_path::date_indexed::NAME, json!(v))),
|
||||
option_sync_entry!(fp.is_dir, is_dir),
|
||||
option_sync_entry!(fp.cas_id, cas_id),
|
||||
option_sync_entry!(fp.integrity_checksum, integrity_checksum),
|
||||
option_sync_entry!(
|
||||
fp.location.map(|l| prisma_sync::location::SyncId {
|
||||
pub_id: l.pub_id
|
||||
}),
|
||||
location
|
||||
),
|
||||
option_sync_entry!(fp.materialized_path, materialized_path),
|
||||
option_sync_entry!(fp.name, name),
|
||||
option_sync_entry!(fp.extension, extension),
|
||||
option_sync_entry!(fp.hidden, hidden),
|
||||
option_sync_entry!(fp.size_in_bytes_bytes, size_in_bytes_bytes),
|
||||
option_sync_entry!(fp.inode, inode),
|
||||
option_sync_entry!(fp.date_created, date_created),
|
||||
option_sync_entry!(fp.date_modified, date_modified),
|
||||
option_sync_entry!(fp.date_indexed, date_indexed),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -194,8 +234,10 @@ pub async fn backfill_operations(db: &PrismaClient, sync: &crate::Manager, insta
|
|||
},
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[t_o.date_created
|
||||
.map(|v| (tag_on_object::date_created::NAME, json!(v)))],
|
||||
[option_sync_entry!(
|
||||
t_o.date_created,
|
||||
tag_on_object::date_created
|
||||
)],
|
||||
),
|
||||
)
|
||||
})
|
||||
|
|
|
@ -169,18 +169,9 @@ async fn bruh() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
use prisma::location;
|
||||
|
||||
macro_rules! item {
|
||||
($name:ident, $value:expr) => {
|
||||
(
|
||||
(location::$name::NAME, json!($value)),
|
||||
location::$name::set(Some($value.to_string())),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let (sync_ops, db_ops): (Vec<_>, Vec<_>) = [
|
||||
item!(name, "Location 0"),
|
||||
item!(path, "/User/Brendan/Documents"),
|
||||
sync_db_entry!(location::name, "Location 0"),
|
||||
sync_db_entry!(location::path, "/User/Brendan/Documents"),
|
||||
]
|
||||
.into_iter()
|
||||
.unzip();
|
||||
|
|
|
@ -278,6 +278,7 @@ model Object {
|
|||
// @@map("key")
|
||||
// }
|
||||
|
||||
/// @shared(id: object)
|
||||
model MediaData {
|
||||
id Int @id @default(autoincrement())
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::{api::utils::library, invalidate_query, library::Library};
|
||||
|
||||
use sd_prisma::{prisma::saved_search, prisma_sync};
|
||||
use sd_sync::OperationFactory;
|
||||
use sd_sync::{option_sync_db_entry, sync_db_entry, OperationFactory};
|
||||
use sd_utils::chain_optional_iter;
|
||||
|
||||
use chrono::{DateTime, FixedOffset, Utc};
|
||||
use rspc::alpha::AlphaRouter;
|
||||
use serde::{de::IgnoredAny, Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use specta::Type;
|
||||
use tracing::error;
|
||||
use uuid::Uuid;
|
||||
|
@ -39,18 +38,12 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
|
|||
|
||||
let (sync_params, db_params): (Vec<_>, Vec<_>) = chain_optional_iter(
|
||||
[
|
||||
(
|
||||
(saved_search::date_created::NAME, json!(date_created)),
|
||||
saved_search::date_created::set(Some(date_created)),
|
||||
),
|
||||
(
|
||||
(saved_search::name::NAME, json!(&args.name)),
|
||||
saved_search::name::set(Some(args.name)),
|
||||
),
|
||||
sync_db_entry!(date_created, saved_search::date_created),
|
||||
sync_db_entry!(args.name, saved_search::name),
|
||||
],
|
||||
[
|
||||
args.filters
|
||||
.and_then(|s| {
|
||||
option_sync_db_entry!(
|
||||
args.filters.and_then(|s| {
|
||||
// https://github.com/serde-rs/json/issues/579
|
||||
// https://docs.rs/serde/latest/serde/de/struct.IgnoredAny.html
|
||||
|
||||
|
@ -60,31 +53,12 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
|
|||
} else {
|
||||
Some(s)
|
||||
}
|
||||
})
|
||||
.map(|v| {
|
||||
(
|
||||
(saved_search::filters::NAME, json!(&v)),
|
||||
saved_search::filters::set(Some(v)),
|
||||
)
|
||||
}),
|
||||
args.search.map(|v| {
|
||||
(
|
||||
(saved_search::search::NAME, json!(&v)),
|
||||
saved_search::search::set(Some(v)),
|
||||
)
|
||||
}),
|
||||
args.description.map(|v| {
|
||||
(
|
||||
(saved_search::description::NAME, json!(&v)),
|
||||
saved_search::description::set(Some(v)),
|
||||
)
|
||||
}),
|
||||
args.icon.map(|v| {
|
||||
(
|
||||
(saved_search::icon::NAME, json!(&v)),
|
||||
saved_search::icon::set(Some(v)),
|
||||
)
|
||||
}),
|
||||
saved_search::filters
|
||||
),
|
||||
option_sync_db_entry!(args.search, saved_search::search),
|
||||
option_sync_db_entry!(args.description, saved_search::description),
|
||||
option_sync_db_entry!(args.icon, saved_search::icon),
|
||||
],
|
||||
)
|
||||
.into_iter()
|
||||
|
@ -157,41 +131,13 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
|
|||
})?;
|
||||
|
||||
let (sync_params, db_params): (Vec<_>, Vec<_>) = chain_optional_iter(
|
||||
[(
|
||||
(saved_search::date_modified::NAME, json!(updated_at)),
|
||||
saved_search::date_modified::set(Some(updated_at)),
|
||||
)],
|
||||
[sync_db_entry!(updated_at, saved_search::date_modified)],
|
||||
[
|
||||
args.name.map(|v| {
|
||||
(
|
||||
(saved_search::name::NAME, json!(&v)),
|
||||
saved_search::name::set(v),
|
||||
)
|
||||
}),
|
||||
args.description.map(|v| {
|
||||
(
|
||||
(saved_search::name::NAME, json!(&v)),
|
||||
saved_search::name::set(v),
|
||||
)
|
||||
}),
|
||||
args.icon.map(|v| {
|
||||
(
|
||||
(saved_search::icon::NAME, json!(&v)),
|
||||
saved_search::icon::set(v),
|
||||
)
|
||||
}),
|
||||
args.search.map(|v| {
|
||||
(
|
||||
(saved_search::search::NAME, json!(&v)),
|
||||
saved_search::search::set(v),
|
||||
)
|
||||
}),
|
||||
args.filters.map(|v| {
|
||||
(
|
||||
(saved_search::filters::NAME, json!(&v)),
|
||||
saved_search::filters::set(v),
|
||||
)
|
||||
}),
|
||||
option_sync_db_entry!(args.name.flatten(), saved_search::name),
|
||||
option_sync_db_entry!(args.description.flatten(), saved_search::name),
|
||||
option_sync_db_entry!(args.icon.flatten(), saved_search::icon),
|
||||
option_sync_db_entry!(args.search.flatten(), saved_search::search),
|
||||
option_sync_db_entry!(args.filters.flatten(), saved_search::filters),
|
||||
],
|
||||
)
|
||||
.into_iter()
|
||||
|
|
|
@ -116,45 +116,28 @@ async fn execute_indexer_save_step(
|
|||
),
|
||||
location_id::set(Some(location.id)),
|
||||
),
|
||||
(
|
||||
(materialized_path::NAME, json!(materialized_path)),
|
||||
materialized_path::set(Some(materialized_path.to_string())),
|
||||
),
|
||||
((name::NAME, json!(name)), name::set(Some(name.to_string()))),
|
||||
((is_dir::NAME, json!(*is_dir)), is_dir::set(Some(*is_dir))),
|
||||
(
|
||||
(extension::NAME, json!(extension)),
|
||||
extension::set(Some(extension.to_string())),
|
||||
),
|
||||
(
|
||||
(
|
||||
size_in_bytes_bytes::NAME,
|
||||
json!(entry.metadata.size_in_bytes.to_be_bytes().to_vec()),
|
||||
),
|
||||
size_in_bytes_bytes::set(Some(
|
||||
entry.metadata.size_in_bytes.to_be_bytes().to_vec(),
|
||||
)),
|
||||
),
|
||||
(
|
||||
(inode::NAME, json!(entry.metadata.inode.to_le_bytes())),
|
||||
inode::set(Some(inode_to_db(entry.metadata.inode))),
|
||||
),
|
||||
(
|
||||
(date_created::NAME, json!(entry.metadata.created_at)),
|
||||
date_created::set(Some(entry.metadata.created_at.into())),
|
||||
),
|
||||
(
|
||||
(date_modified::NAME, json!(entry.metadata.modified_at)),
|
||||
date_modified::set(Some(entry.metadata.modified_at.into())),
|
||||
),
|
||||
(
|
||||
(date_indexed::NAME, json!(Utc::now())),
|
||||
date_indexed::set(Some(Utc::now().into())),
|
||||
),
|
||||
(
|
||||
(hidden::NAME, json!(entry.metadata.hidden)),
|
||||
hidden::set(Some(entry.metadata.hidden)),
|
||||
sync_db_entry!(materialized_path.to_string(), materialized_path),
|
||||
sync_db_entry!(name.to_string(), name),
|
||||
sync_db_entry!(*is_dir, is_dir),
|
||||
sync_db_entry!(extension.to_string(), extension),
|
||||
sync_db_entry!(
|
||||
entry.metadata.size_in_bytes.to_be_bytes().to_vec(),
|
||||
size_in_bytes_bytes
|
||||
),
|
||||
sync_db_entry!(inode_to_db(entry.metadata.inode), inode),
|
||||
{
|
||||
let v = entry.metadata.created_at.into();
|
||||
sync_db_entry!(v, date_created)
|
||||
},
|
||||
{
|
||||
let v = entry.metadata.modified_at.into();
|
||||
sync_db_entry!(v, date_modified)
|
||||
},
|
||||
{
|
||||
let v = Utc::now().into();
|
||||
sync_db_entry!(v, date_indexed)
|
||||
},
|
||||
sync_db_entry!(entry.metadata.hidden, hidden),
|
||||
]
|
||||
.into_iter()
|
||||
.unzip();
|
||||
|
@ -212,48 +195,29 @@ async fn execute_indexer_update_step(
|
|||
let (sync_params, db_params): (Vec<_>, Vec<_>) = [
|
||||
// As this file was updated while Spacedrive was offline, we mark the object_id and cas_id as null
|
||||
// So this file_path will be updated at file identifier job
|
||||
(
|
||||
should_unlink_object.then_some((
|
||||
(object_id::NAME, serde_json::Value::Null),
|
||||
should_unlink_object.then_some(object::disconnect()),
|
||||
),
|
||||
(
|
||||
(cas_id::NAME, serde_json::Value::Null),
|
||||
Some(cas_id::set(None)),
|
||||
),
|
||||
(
|
||||
(is_dir::NAME, json!(*is_dir)),
|
||||
Some(is_dir::set(Some(*is_dir))),
|
||||
),
|
||||
(
|
||||
(
|
||||
size_in_bytes_bytes::NAME,
|
||||
json!(entry.metadata.size_in_bytes.to_be_bytes().to_vec()),
|
||||
),
|
||||
Some(size_in_bytes_bytes::set(Some(
|
||||
entry.metadata.size_in_bytes.to_be_bytes().to_vec(),
|
||||
))),
|
||||
),
|
||||
(
|
||||
(inode::NAME, json!(entry.metadata.inode.to_le_bytes())),
|
||||
Some(inode::set(Some(inode_to_db(entry.metadata.inode)))),
|
||||
),
|
||||
(
|
||||
(date_created::NAME, json!(entry.metadata.created_at)),
|
||||
Some(date_created::set(Some(entry.metadata.created_at.into()))),
|
||||
),
|
||||
(
|
||||
(date_modified::NAME, json!(entry.metadata.modified_at)),
|
||||
Some(date_modified::set(Some(entry.metadata.modified_at.into()))),
|
||||
),
|
||||
(
|
||||
(hidden::NAME, json!(entry.metadata.hidden)),
|
||||
Some(hidden::set(Some(entry.metadata.hidden))),
|
||||
),
|
||||
object::disconnect(),
|
||||
)),
|
||||
Some(((cas_id::NAME, serde_json::Value::Null), cas_id::set(None))),
|
||||
Some(sync_db_entry!(*is_dir, is_dir)),
|
||||
Some(sync_db_entry!(
|
||||
entry.metadata.size_in_bytes.to_be_bytes().to_vec(),
|
||||
size_in_bytes_bytes
|
||||
)),
|
||||
Some(sync_db_entry!(inode_to_db(entry.metadata.inode), inode)),
|
||||
Some({
|
||||
let v = entry.metadata.created_at.into();
|
||||
sync_db_entry!(v, date_created)
|
||||
}),
|
||||
Some({
|
||||
let v = entry.metadata.modified_at.into();
|
||||
sync_db_entry!(v, date_modified)
|
||||
}),
|
||||
Some(sync_db_entry!(entry.metadata.hidden, hidden)),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(sync_param, maybe_db_param)| {
|
||||
maybe_db_param.map(|db_param| (sync_param, db_param))
|
||||
})
|
||||
.flatten()
|
||||
.unzip();
|
||||
|
||||
Ok::<_, IndexerError>((
|
||||
|
|
|
@ -306,7 +306,7 @@ async fn inner_create_file(
|
|||
db.file_path().update(
|
||||
file_path::pub_id::equals(created_file.pub_id.clone()),
|
||||
vec![file_path::object::connect(object::pub_id::equals(
|
||||
object_pub_id,
|
||||
object_pub_id.clone(),
|
||||
))],
|
||||
),
|
||||
)
|
||||
|
@ -342,22 +342,30 @@ async fn inner_create_file(
|
|||
.await
|
||||
.map_err(|e| error!("Failed to extract media data: {e:#?}"))
|
||||
{
|
||||
if let Ok(media_data_params) = media_data_image_to_query_params(media_data)
|
||||
.map_err(|e| {
|
||||
error!("Failed to prepare media data create params: {e:#?}")
|
||||
}) {
|
||||
db.media_data()
|
||||
.upsert(
|
||||
let (sync_params, db_params) = media_data_image_to_query_params(media_data);
|
||||
|
||||
sync.write_ops(
|
||||
db,
|
||||
(
|
||||
sync.shared_create(
|
||||
prisma_sync::media_data::SyncId {
|
||||
object: prisma_sync::object::SyncId {
|
||||
pub_id: object_pub_id.clone(),
|
||||
},
|
||||
},
|
||||
sync_params,
|
||||
),
|
||||
db.media_data().upsert(
|
||||
media_data::object_id::equals(object_id),
|
||||
media_data::create(
|
||||
object::id::equals(object_id),
|
||||
media_data_params.clone(),
|
||||
db_params.clone(),
|
||||
),
|
||||
media_data_params,
|
||||
)
|
||||
.exec()
|
||||
.await?;
|
||||
}
|
||||
db_params,
|
||||
),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -682,22 +690,31 @@ async fn inner_update_file(
|
|||
.await
|
||||
.map_err(|e| error!("Failed to extract media data: {e:#?}"))
|
||||
{
|
||||
if let Ok(media_data_params) =
|
||||
media_data_image_to_query_params(media_data).map_err(|e| {
|
||||
error!("Failed to prepare media data create params: {e:#?}")
|
||||
}) {
|
||||
db.media_data()
|
||||
.upsert(
|
||||
let (sync_params, db_params) =
|
||||
media_data_image_to_query_params(media_data);
|
||||
|
||||
sync.write_ops(
|
||||
db,
|
||||
(
|
||||
sync.shared_create(
|
||||
prisma_sync::media_data::SyncId {
|
||||
object: prisma_sync::object::SyncId {
|
||||
pub_id: object.pub_id.clone(),
|
||||
},
|
||||
},
|
||||
sync_params,
|
||||
),
|
||||
db.media_data().upsert(
|
||||
media_data::object_id::equals(object.id),
|
||||
media_data::create(
|
||||
object::id::equals(object.id),
|
||||
media_data_params.clone(),
|
||||
db_params.clone(),
|
||||
),
|
||||
media_data_params,
|
||||
)
|
||||
.exec()
|
||||
.await?;
|
||||
}
|
||||
db_params,
|
||||
),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,18 +31,24 @@ pub fn media_data_image_to_query(
|
|||
#[cfg(feature = "location-watcher")]
|
||||
pub fn media_data_image_to_query_params(
|
||||
mdi: ImageMetadata,
|
||||
) -> Result<Vec<SetParam>, MediaDataError> {
|
||||
Ok(vec![
|
||||
camera_data::set(serde_json::to_vec(&mdi.camera_data).ok()),
|
||||
media_date::set(serde_json::to_vec(&mdi.date_taken).ok()),
|
||||
resolution::set(serde_json::to_vec(&mdi.resolution).ok()),
|
||||
media_location::set(serde_json::to_vec(&mdi.location).ok()),
|
||||
artist::set(mdi.artist),
|
||||
description::set(mdi.description),
|
||||
copyright::set(mdi.copyright),
|
||||
exif_version::set(mdi.exif_version),
|
||||
epoch_time::set(mdi.date_taken.map(|x| x.unix_timestamp())),
|
||||
])
|
||||
) -> (Vec<(&'static str, serde_json::Value)>, Vec<SetParam>) {
|
||||
use sd_sync::option_sync_db_entry;
|
||||
use sd_utils::chain_optional_iter;
|
||||
|
||||
chain_optional_iter(
|
||||
[],
|
||||
[
|
||||
option_sync_db_entry!(serde_json::to_vec(&mdi.camera_data).ok(), camera_data),
|
||||
option_sync_db_entry!(serde_json::to_vec(&mdi.date_taken).ok(), media_date),
|
||||
option_sync_db_entry!(serde_json::to_vec(&mdi.location).ok(), media_location),
|
||||
option_sync_db_entry!(mdi.artist, artist),
|
||||
option_sync_db_entry!(mdi.description, description),
|
||||
option_sync_db_entry!(mdi.copyright, copyright),
|
||||
option_sync_db_entry!(mdi.exif_version, exif_version),
|
||||
],
|
||||
)
|
||||
.into_iter()
|
||||
.unzip()
|
||||
}
|
||||
|
||||
pub fn media_data_image_from_prisma_data(
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use prisma_client_rust_sdk::{prelude::*, prisma::prisma_models::walkers::RelationFieldWalker};
|
||||
use prisma_client_rust_sdk::{
|
||||
prelude::*,
|
||||
prisma::prisma_models::walkers::{RefinedFieldWalker, RelationFieldWalker},
|
||||
};
|
||||
|
||||
use crate::{ModelSyncType, ModelWithSyncType};
|
||||
|
||||
|
@ -35,15 +38,50 @@ pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
|
|||
|
||||
let match_arms = match sync_type.as_ref()? {
|
||||
ModelSyncType::Shared { id } => {
|
||||
let id_name_snake = snake_ident(id.name());
|
||||
let (get_id, equals_value, id_name_snake, create_id) = match id.refine() {
|
||||
RefinedFieldWalker::Relation(rel) => {
|
||||
let scalar_field = rel.referenced_fields().unwrap().next().unwrap();
|
||||
let id_name_snake = snake_ident(scalar_field.name());
|
||||
let field_name_snake = snake_ident(rel.name());
|
||||
let opposite_model_name_snake =
|
||||
snake_ident(rel.opposite_relation_field().unwrap().model().name());
|
||||
|
||||
let relation_equals_condition = quote!(prisma::#opposite_model_name_snake::pub_id::equals(
|
||||
id.#field_name_snake.pub_id.clone()
|
||||
));
|
||||
|
||||
let rel_fetch = quote! {
|
||||
let rel = db.#opposite_model_name_snake()
|
||||
.find_unique(#relation_equals_condition)
|
||||
.exec()
|
||||
.await?
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
(
|
||||
Some(rel_fetch),
|
||||
quote!(rel.id),
|
||||
id_name_snake,
|
||||
relation_equals_condition,
|
||||
)
|
||||
}
|
||||
RefinedFieldWalker::Scalar(s) => {
|
||||
let field_name_snake = snake_ident(s.name());
|
||||
let thing = quote!(id.#field_name_snake.clone());
|
||||
|
||||
(None, thing.clone(), field_name_snake, thing)
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#get_id
|
||||
|
||||
match data {
|
||||
sd_sync::CRDTOperationData::Create => {
|
||||
db.#model_name_snake()
|
||||
.upsert(
|
||||
prisma::#model_name_snake::#id_name_snake::equals(id.#id_name_snake.clone()),
|
||||
prisma::#model_name_snake::create(id.#id_name_snake, vec![]),
|
||||
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
|
||||
prisma::#model_name_snake::create(#create_id, vec![]),
|
||||
vec![]
|
||||
)
|
||||
.exec()
|
||||
|
@ -56,8 +94,8 @@ pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
|
|||
|
||||
db.#model_name_snake()
|
||||
.upsert(
|
||||
prisma::#model_name_snake::#id_name_snake::equals(id.#id_name_snake.clone()),
|
||||
prisma::#model_name_snake::create(id.#id_name_snake, data.clone()),
|
||||
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
|
||||
prisma::#model_name_snake::create(#create_id, data.clone()),
|
||||
data,
|
||||
)
|
||||
.exec()
|
||||
|
@ -65,7 +103,7 @@ pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
|
|||
},
|
||||
sd_sync::CRDTOperationData::Delete => {
|
||||
db.#model_name_snake()
|
||||
.delete(prisma::#model_name_snake::#id_name_snake::equals(id.#id_name_snake))
|
||||
.delete(prisma::#model_name_snake::#id_name_snake::equals(#equals_value))
|
||||
.exec()
|
||||
.await?;
|
||||
},
|
||||
|
|
|
@ -106,3 +106,33 @@ pub trait OperationFactory {
|
|||
self.new_op(&id, CRDTOperationData::Delete)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! sync_entry {
|
||||
($v:expr, $($m:tt)*) => {{
|
||||
let v = $v;
|
||||
($($m)*::NAME, serde_json::json!(&v))
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! option_sync_entry {
|
||||
($v:expr, $($m:tt)*) => {
|
||||
$v.map(|v| $crate::sync_entry!(v, $($m)*))
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! sync_db_entry {
|
||||
($v:expr, $($m:tt)*) => {{
|
||||
let v = $v;
|
||||
($crate::sync_entry!(&v, $($m)*), $($m)*::set(Some(v)))
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! option_sync_db_entry {
|
||||
($v:expr, $($m:tt)*) => {
|
||||
$v.map(|v| $crate::sync_db_entry!(v, $($m)*))
|
||||
};
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ export type FileDeleterJobInit = { location_id: number; file_path_ids: number[]
|
|||
|
||||
export type FileEraserJobInit = { location_id: number; file_path_ids: number[]; passes: string }
|
||||
|
||||
export type FilePath = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; key_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null }
|
||||
export type FilePath = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null }
|
||||
|
||||
export type FilePathCursor = { isDir: boolean; variant: FilePathCursorVariant }
|
||||
|
||||
|
@ -262,7 +262,7 @@ export type FilePathOrder = { field: "name"; value: SortOrder } | { field: "size
|
|||
|
||||
export type FilePathSearchArgs = { take?: number | null; orderAndPagination?: OrderAndPagination<number, FilePathOrder, FilePathCursor> | null; filters?: SearchFilterArgs[]; groupDirectories?: boolean }
|
||||
|
||||
export type FilePathWithObject = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; key_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null; object: { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null } | null }
|
||||
export type FilePathWithObject = { id: number; pub_id: number[]; is_dir: boolean | null; cas_id: string | null; integrity_checksum: string | null; location_id: number | null; materialized_path: string | null; name: string | null; extension: string | null; hidden: boolean | null; size_in_bytes: string | null; size_in_bytes_bytes: number[] | null; inode: number[] | null; object_id: number | null; date_created: string | null; date_modified: string | null; date_indexed: string | null; object: { id: number; pub_id: number[]; kind: number | null; key_id: number | null; hidden: boolean | null; favorite: boolean | null; important: boolean | null; note: string | null; date_created: string | null; date_accessed: string | null } | null }
|
||||
|
||||
export type Flash = {
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue