1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Database instruction implementations for structured database operations.
//!
//! This module provides a trait-based abstraction for database operations using the
//! Command pattern. This design allows for:
//!
//! - Type-safe database operations
//! - Composable and reusable commands
//! - Clear separation of operation logic
//! - Consistent error handling
//!
//! # Architecture
//!
//! The module is organized around three main operation types:
//!
//! - [`query`] - Read operations for searching and retrieving papers
//! - [`add`] - Write operations for adding papers and documents
//! - [`remove`] - Delete operations for removing papers from the database
//!
//! Each operation type implements the [`DatabaseInstruction`] trait, providing
//! a consistent interface while allowing for operation-specific behavior.
//!
//! # Usage
//!
//! Operations are constructed as instructions and then executed against a database:
//!
//! ```no_run
//! use learner::{
//! database::{Add, Database, Query, Remove},
//! prelude::*,
//! resource::Paper,
//! Learner,
//! };
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let mut db = Database::open("papers.db").await?;
//!
//! // Query papers
//! let papers = Query::text("quantum computing").execute(&mut db).await?;
//!
//! // Add a new paper
//! # let learner = Learner::builder().build().await?;
//! # let retriever = learner.retriever;
//! let paper = retriever.get_paper("2301.07041").await?;
//! Add::paper(&paper).execute(&mut db).await?;
//!
//! // Remove papers by author
//! Remove::by_author("Alice Researcher").execute(&mut db).await?;
//! # Ok(())
//! # }
//! ```
use *;
use ;
use Query;
/// Trait for implementing type-safe database operations.
///
/// This trait defines the core interface for the Command pattern used in database
/// operations. Each implementation represents a specific operation (like querying,
/// adding, or removing papers) and encapsulates its own:
///
/// - SQL generation and execution
/// - Parameter handling
/// - Result type specification
/// - Error handling
///
/// The trait is async to support non-blocking database operations while maintaining
/// proper connection management.
///
/// # Type Parameters
///
/// * `Output` - The type returned by executing this instruction. Common types include:
/// - `Vec<Paper>` for query operations
/// - `()` for operations that don't return data
/// - Custom types for specialized operations
///
/// # Implementation Notes
///
/// When implementing this trait:
/// - Keep SQL generation and execution within the implementation
/// - Use proper parameter binding for SQL injection prevention
/// - Handle errors appropriately and convert to [`LearnerError`]
/// - Consider optimizing repeated operations with prepared statements
///
/// # Examples
///
/// Querying papers with different criteria:
///
/// ```no_run
/// # use learner::database::{Database, DatabaseInstruction, Query};
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let mut db = Database::open("papers.db").await?;
///
/// // Full-text search
/// let papers = Query::text("neural networks").execute(&mut db).await?;
///
/// // Search by author
/// let papers = Query::by_author("Alice Researcher").execute(&mut db).await?;
///
/// // Search by publication date
/// use chrono::{DateTime, Utc};
/// let papers =
/// Query::before_date(DateTime::parse_from_rfc3339("2024-01-01T00:00:00Z")?.with_timezone(&Utc))
/// .execute(&mut db)
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// Implementing a custom instruction:
///
/// ```no_run
/// # use learner::{database::{Database, DatabaseInstruction}, error::LearnerError};
/// # use async_trait::async_trait;
/// struct CountPapers;
///
/// #[async_trait]
/// impl DatabaseInstruction for CountPapers {
/// type Output = i64;
///
/// async fn execute(&self, db: &mut Database) -> std::result::Result<Self::Output, LearnerError> {
/// Ok(
/// db.conn
/// .call(|conn| {
/// conn.query_row("SELECT COUNT(*) FROM papers", [], |row| row.get(0)).map_err(Into::into)
/// })
/// .await?,
/// )
/// }
/// }
/// # type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
/// ```