Files
Oxicloud/src/domain/entities/trashed_item.rs
T
Claude b01633791b perf: round 11 finale — benchmark verdicts, geo min(uuid) rollback, ROUND11.md
- benches/ROUND11.md: final BEFORE/AFTER numbers for all 21 micro
  sections, the 5 query sections, the 4 log-writer arms, the SPA gates,
  and the two cross-round regression guards (bench_row_path 2.52x,
  bench_dto_map — both byte-identical)
- ROLLBACK (gate-caught): min(fm.file_id)::text geo-cluster cast —
  PostgreSQL has no min(uuid) aggregate; the bench section now reproduces
  the rejection and the per-row-cast original stays
- REJECTED (bench-measured): tracing-appender non-blocking writer —
  slower than sync on fast sinks (1.41M vs 0.99M ev/s, worse tail) and
  the slow-sink drain gate showed shutdown tail-loss risk for the audit
  channel; dep moved to dev-dependencies (harness only)
- RateLimiter final form: lock-free get + insert (8.0 → 6.0 allocs, wall
  neutral; and_upsert_with variant rejected at 2 365 ns)
- fix: TrashedItemParts insertion had stolen TrashedItem's derive line
  (caught by clippy --all-targets)
- grant_role enum values corrected in the queries bench

Validation: cargo fmt + clippy --all-features --all-targets -D warnings
clean; cargo test --workspace 524 passed / 0 failed; frontend npm run
check 0 errors + vitest 306 passed (1 pre-existing round-7 wall-clock
gate flaked only under concurrent Rust-build CPU contention; passes in
isolation)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ABhTEHuGujvwoodh67Kga7
2026-07-18 22:46:20 +00:00

131 lines
2.9 KiB
Rust

use chrono::{DateTime, Utc};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq)]
pub enum TrashedItemType {
File,
Folder,
}
/// Owned decomposition of a [`TrashedItem`] (see
/// [`TrashedItem::into_parts`]).
pub struct TrashedItemParts {
pub id: Uuid,
pub original_id: Uuid,
pub item_type: TrashedItemType,
pub name: String,
pub original_path: String,
pub trashed_at: DateTime<Utc>,
}
#[derive(Debug, Clone)]
pub struct TrashedItem {
id: Uuid,
original_id: Uuid,
user_id: Uuid,
item_type: TrashedItemType,
name: String,
original_path: String,
trashed_at: DateTime<Utc>,
deletion_date: DateTime<Utc>,
}
impl TrashedItem {
pub fn new(
original_id: Uuid,
user_id: Uuid,
item_type: TrashedItemType,
name: String,
original_path: String,
retention_days: u32,
) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4(),
original_id,
user_id,
item_type,
name,
original_path,
trashed_at: now,
deletion_date: now + chrono::Duration::days(retention_days as i64),
}
}
#[allow(clippy::too_many_arguments)]
pub fn from_raw(
id: Uuid,
original_id: Uuid,
user_id: Uuid,
item_type: TrashedItemType,
name: String,
original_path: String,
trashed_at: DateTime<Utc>,
deletion_date: DateTime<Utc>,
) -> Self {
Self {
id,
original_id,
user_id,
item_type,
name,
original_path,
trashed_at,
deletion_date,
}
}
// ── Getters ──
pub fn id(&self) -> Uuid {
self.id
}
pub fn original_id(&self) -> Uuid {
self.original_id
}
pub fn user_id(&self) -> Uuid {
self.user_id
}
pub fn item_type(&self) -> &TrashedItemType {
&self.item_type
}
pub fn name(&self) -> &str {
&self.name
}
pub fn original_path(&self) -> &str {
&self.original_path
}
pub fn trashed_at(&self) -> DateTime<Utc> {
self.trashed_at
}
pub fn deletion_date(&self) -> DateTime<Utc> {
self.deletion_date
}
/// Decompose into owned parts for DTO conversion — moves `name` /
/// `original_path` instead of the getter clones `to_dto` used to make
/// per trash row (benches/ROUND11.md; the File/Folder/Contact pattern).
pub fn into_parts(self) -> TrashedItemParts {
TrashedItemParts {
id: self.id,
original_id: self.original_id,
item_type: self.item_type,
name: self.name,
original_path: self.original_path,
trashed_at: self.trashed_at,
}
}
pub fn days_until_deletion(&self) -> i64 {
let now = Utc::now();
(self.deletion_date - now).num_days().max(0)
}
}