Skip to main content

VTabModuleDerive

Derive Macro VTabModuleDerive 

Source
#[derive(VTabModuleDerive)]
Expand description

Macro to derive a VTabModule for your extension. This macro will generate the necessary functions to register your module with core. You must implement the VTabModule, VTable, and VTabCursor traits.

#[derive(Debug, VTabModuleDerive)]
struct CsvVTabModule;

impl VTabModule for CsvVTabModule {
 type Table = CsvTable;
 const NAME: &'static str = "csv_data";
 const VTAB_KIND: VTabKind = VTabKind::VirtualTable;

  /// Declare your virtual table and its schema
 fn create(args: &[Value]) -> Result<(String, Self::Table), ResultCode> {
    let schema = "CREATE TABLE csv_data(
            name TEXT,
            age TEXT,
            city TEXT
        )".into();
    Ok((schema, CsvTable {}))
 }
}

struct CsvTable {}

// Implement the VTable trait for your virtual table
impl VTable for CsvTable {
 type Cursor = CsvCursor;
 type Error = &'static str;

 /// Open the virtual table and return a cursor
 fn open(&self) -> Result<Self::Cursor, Self::Error> {
    let csv_content = fs::read_to_string("data.csv").unwrap_or_default();
    let rows: Vec<Vec<String>> = csv_content
        .lines()
        .skip(1)
        .map(|line| {
            line.split(',')
                .map(|s| s.trim().to_string())
                .collect()
        })
        .collect();
    Ok(CsvCursor { rows, index: 0 })
 }

/// **Optional** methods for non-readonly tables:

 /// Update the row with the provided values, return the new rowid
 fn update(&mut self, rowid: i64, args: &[Value]) -> Result<Option<i64>, Self::Error> {
     Ok(None)// return Ok(None) for read-only
 }

 /// Insert a new row with the provided values, return the new rowid
 fn insert(&mut self, args: &[Value]) -> Result<(), Self::Error> {
     Ok(()) //
 }

 /// Delete the row with the provided rowid
 fn delete(&mut self, rowid: i64) -> Result<(), Self::Error> {
   Ok(())
 }

 /// Destroy the virtual table. Any cleanup logic for when the table is deleted comes heres
 fn destroy(&mut self) -> Result<(), Self::Error> {
    Ok(())
 }
}

 #[derive(Debug)]
struct CsvCursor {
  rows: Vec<Vec<String>>,
  index: usize,
}

impl CsvCursor {
  /// Returns the value for a given column index.
  fn column(&self, idx: u32) -> Result<Value, Self::Error> {
      let row = &self.rows[self.index];
      if (idx as usize) < row.len() {
          Value::from_text(&row[idx as usize])
      } else {
          Value::null()
      }
  }
}

// Implement the VTabCursor trait for your virtual cursor
impl VTabCursor for CsvCursor {
 type Error = &'static str;

 /// Filter the virtual table based on arguments (omitted here for simplicity)
 fn filter(&mut self, _args: &[Value], _idx_info: Option<(&str, i32)>) -> ResultCode {
     ResultCode::OK
 }

 /// Move the cursor to the next row
 fn next(&mut self) -> ResultCode {
    if self.index < self.rows.len() - 1 {
        self.index += 1;
        ResultCode::OK
    } else {
        ResultCode::EOF
    }
 }

 fn eof(&self) -> bool {
     self.index >= self.rows.len()
 }

 /// Return the value for a given column index
 fn column(&self, idx: u32) -> Result<Value, Self::Error> {
     self.column(idx)
 }

 fn rowid(&self) -> i64 {
     self.index as i64
 }
}