pub trait DatabaseInstruction {
type Output;
// Required method
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
db: &'life1 mut Database,
) -> Pin<Box<dyn Future<Output = Result<Self::Output>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
}
Expand description
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:
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?;
Implementing a custom instruction:
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?,
)
}
}
Required Associated Types§
Required Methods§
Sourcefn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
db: &'life1 mut Database,
) -> Pin<Box<dyn Future<Output = Result<Self::Output>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
db: &'life1 mut Database,
) -> Pin<Box<dyn Future<Output = Result<Self::Output>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Executes the instruction against a database connection.
This method performs the actual database operation, managing:
- SQL execution
- Parameter binding
- Result processing
- Error handling
§Arguments
db
- Mutable reference to the database connection
§Returns
Returns a Result
containing either:
- The operation’s output of type
Self::Output
- A
LearnerError
if the operation fails
§Notes
The mutable database reference is required for operations that modify the database. A future enhancement might split this into separate traits for read-only and read-write operations.