bl4_idb/
repository.rs

1//! Repository trait for items database operations.
2//!
3//! This trait defines the interface for all database backends.
4
5use crate::types::*;
6use std::collections::HashMap;
7
8/// Error type for repository operations
9#[derive(Debug, thiserror::Error)]
10pub enum RepoError {
11    #[error("Item not found: {0}")]
12    NotFound(String),
13
14    #[error("Database error: {0}")]
15    Database(String),
16
17    #[error("IO error: {0}")]
18    Io(#[from] std::io::Error),
19
20    #[error("Parse error: {0}")]
21    Parse(#[from] ParseError),
22}
23
24/// Result type for repository operations
25pub type RepoResult<T> = Result<T, RepoError>;
26
27/// Trait for items database operations (synchronous version for CLI)
28pub trait ItemsRepository {
29    /// Initialize the database schema
30    fn init(&self) -> RepoResult<()>;
31
32    // === Items CRUD ===
33
34    /// Add a new item with just its serial
35    fn add_item(&self, serial: &str) -> RepoResult<()>;
36
37    /// Get an item by serial
38    fn get_item(&self, serial: &str) -> RepoResult<Option<Item>>;
39
40    /// Update item metadata
41    fn update_item(&self, serial: &str, update: &ItemUpdate) -> RepoResult<()>;
42
43    /// List items with optional filters
44    fn list_items(&self, filter: &ItemFilter) -> RepoResult<Vec<Item>>;
45
46    /// Delete an item
47    fn delete_item(&self, serial: &str) -> RepoResult<bool>;
48
49    // === Verification ===
50
51    /// Set verification status for an item
52    fn set_verification_status(
53        &self,
54        serial: &str,
55        status: VerificationStatus,
56        notes: Option<&str>,
57    ) -> RepoResult<()>;
58
59    /// Set legal status for an item
60    fn set_legal(&self, serial: &str, legal: bool) -> RepoResult<()>;
61
62    /// Set legal status for all items
63    fn set_all_legal(&self, legal: bool) -> RepoResult<usize>;
64
65    // === Metadata ===
66
67    /// Set item type
68    fn set_item_type(&self, serial: &str, item_type: &str) -> RepoResult<()>;
69
70    /// Set source for an item
71    fn set_source(&self, serial: &str, source: &str) -> RepoResult<()>;
72
73    /// Set source for items without one
74    fn set_source_for_null(&self, source: &str) -> RepoResult<usize>;
75
76    /// Set source for items matching a condition (SQL WHERE clause)
77    /// WARNING: condition is inserted directly into SQL - do not use with untrusted input
78    fn set_source_where(&self, source: &str, condition: &str) -> RepoResult<usize>;
79
80    // === Parts ===
81
82    /// Get parts for an item
83    fn get_parts(&self, serial: &str) -> RepoResult<Vec<ItemPart>>;
84
85    // === Multi-source values ===
86
87    /// Set a field value with source attribution
88    #[allow(clippy::too_many_arguments)] // Trait method with distinct semantic params
89    fn set_value(
90        &self,
91        serial: &str,
92        field: &str,
93        value: &str,
94        source: ValueSource,
95        source_detail: Option<&str>,
96        confidence: Confidence,
97    ) -> RepoResult<()>;
98
99    /// Get all values for a field across sources
100    fn get_values(&self, serial: &str, field: &str) -> RepoResult<Vec<ItemValue>>;
101
102    /// Get the best value for a field
103    fn get_best_value(&self, serial: &str, field: &str) -> RepoResult<Option<ItemValue>>;
104
105    /// Get all values for an item
106    fn get_all_values(&self, serial: &str) -> RepoResult<Vec<ItemValue>>;
107
108    /// Get best value for each field as a map
109    fn get_best_values(&self, serial: &str) -> RepoResult<HashMap<String, String>>;
110
111    /// Get best values for all items (bulk query)
112    fn get_all_items_best_values(&self) -> RepoResult<HashMap<String, HashMap<String, String>>>;
113
114    // === Statistics ===
115
116    /// Get database statistics
117    fn stats(&self) -> RepoResult<DbStats>;
118
119    // === Migration ===
120
121    /// Migrate column values to item_values table
122    fn migrate_column_values(&self, dry_run: bool) -> RepoResult<MigrationStats>;
123}
124
125/// Extension trait for attachment operations (feature-gated)
126#[cfg(feature = "attachments")]
127pub trait AttachmentsRepository {
128    /// Add an image attachment
129    #[allow(clippy::too_many_arguments)] // Trait method with distinct semantic params
130    fn add_attachment(
131        &self,
132        serial: &str,
133        name: &str,
134        mime_type: &str,
135        data: &[u8],
136        view: &str,
137    ) -> RepoResult<i64>;
138
139    /// Get attachments for an item (without data)
140    fn get_attachments(&self, serial: &str) -> RepoResult<Vec<Attachment>>;
141
142    /// Get attachment data by ID
143    fn get_attachment_data(&self, id: i64) -> RepoResult<Option<Vec<u8>>>;
144
145    /// Delete an attachment
146    fn delete_attachment(&self, id: i64) -> RepoResult<bool>;
147}
148
149/// Extension trait for import/export operations
150pub trait ImportExportRepository {
151    /// Import an item from a directory
152    fn import_from_dir(&self, dir: &std::path::Path) -> RepoResult<String>;
153
154    /// Export an item to a directory
155    fn export_to_dir(&self, serial: &str, dir: &std::path::Path) -> RepoResult<()>;
156}
157
158/// Extension trait for bulk operations
159pub trait BulkRepository {
160    /// Add multiple items at once
161    fn add_items_bulk(&self, serials: &[&str]) -> RepoResult<BulkResult>;
162
163    /// Set values for multiple items
164    fn set_values_bulk(&self, values: &[BulkValueSet]) -> RepoResult<BulkResult>;
165}
166
167/// Request for bulk value setting
168#[derive(Debug, Clone)]
169pub struct BulkValueSet {
170    pub serial: String,
171    pub field: String,
172    pub value: String,
173    pub source: ValueSource,
174    pub source_detail: Option<String>,
175    pub confidence: Confidence,
176}
177
178/// Result of a bulk operation
179#[derive(Debug, Clone, Default)]
180pub struct BulkResult {
181    pub succeeded: usize,
182    pub failed: usize,
183    pub errors: Vec<(String, String)>, // (serial, error message)
184}