Trait DatabaseInstruction

Source
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§

Source

type Output

The type returned by executing this instruction.

Required Methods§

Source

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.

Implementors§