Return Result<Struct,Error> with query

hi, i'm parsing a sql table and i need to give back a structure. How should i do it?

use libc::printf;
use libsqlite3_sys::Error;
use log::error;
use rusqlite::{Connection, Result};
use serde_xml_rs::expect;
use std::error;

#[derive(Debug)]
struct Command_TO {
    id_type: i32,
    id_variable: i32,
    type_command: String,
    label_command: String,
}


impl Commands_TO {
    pub fn new(sql_db: &str) -> Result<Command_TO,Error> {
        let conn = Connection::open(sql_db)?;
        let mut query = conn.prepare("SELECT * FROM Comandi_TO LIMIT 10")?;
        let id_iter = query.query_map([], |row| {
            Ok(Command_TO {
                id_type: row.get(0).expect("error field Id_type"),
                id_variable: row.get(1).expect("error field id_variable"),
                type_command: row.get(2).expect("error field type_command"),
                label_command: row.get(3).expect("error field label_command"),
            })
        })?;
        }
        Ok(Command_TO);

In this case i obtain an error, differently i try to use cycle for to use data present in Command_TO, but i don't know how to return Result<Command_TO,Error>.
i'm definitely missing some passages.

Shouldn't your new function return Result<Vec<Command_TO>, Error>? You query up to ten rows from your database, so I guess you want to return all of them?

I set a limit of 10 just for an example. i want to return all of them of course.

  • the path I would like to follow is as follows.
  • read db,
  • fill the struct Command_TO with the db columns
  • return in the new() function the struct or error
    I assume that the first three points are already carried out

Well, you already map each row to an instance of Command_TO inside the query_map call. Now all you got to do is extract the created Command_TO instances from the mapping and return them (or a single one of them if that is what you really want).

If you want to return a vector of Command_TO instances build from your query, I'm quite sure this should do the trick:

pub fn new(sql_db: &str) -> Result<Vec<Command_TO>, Error> {
    let conn = Connection::open(sql_db)?;
    let mut query = conn.prepare("SELECT * FROM Comandi_TO LIMIT 10")?;
    
    query.query_map([], |row| {
        Ok(Command_TO {
            id_type: row.get(0).expect("error field Id_type"),
            id_variable: row.get(1).expect("error field id_variable"),
            type_command: row.get(2).expect("error field type_command"),
            label_command: row.get(3).expect("error field label_command"),
        })
    })?
    .collect()
}

If you want to only return the first row of your query, something akin to this should work:

pub fn new(sql_db: &str) -> Result<Command_TO, Error> {
    let conn = Connection::open(sql_db)?;
    let mut query = conn.prepare("SELECT * FROM Comandi_TO LIMIT 10")?;
    
    let rows = query.query_map([], |row| {
        Ok(Command_TO {
            id_type: row.get(0).expect("error field Id_type"),
            id_variable: row.get(1).expect("error field id_variable"),
            type_command: row.get(2).expect("error field type_command"),
            label_command: row.get(3).expect("error field label_command"),
        })
    })?;

    rows.next().unwrap() // panics if your table is empty
}

in this way with collect it works but i can't return Commands_TO


struct Command_TO {
...
}

pub struct Commands_TO {
    Command_TO_vec:Vec<Vec<Command_TO>>
}

impl Commands_TO {
pub fn new(&mut self ,sql_db: &str) -> Result<Commands_TO, rusqlite::Error> {
    let conn = Connection::open(sql_db)?;
    let mut query = conn.prepare("SELECT * FROM Comandi_TO LIMIT 10")?;
    
    let rows = query.query_map([], |row| {
        Ok(Command_TO {
            id_type: row.get(0).expect("error field Id_type"),
            id_variable: row.get(1).expect("error field id_variable"),
            type_command: row.get(2).expect("error field type_command"),
            label_command: row.get(3).expect("error field label_command"),
        })
    })?;

       let id_iter_collection= id_iter.collect::<Result<Vec<Comando_TO>>>().unwrap();
       self.Command_TO_vec.push(id_iter_collection);
       println!("{:?}",self.Command_TO_vec);
        Ok()
    }
}

In this case Ok() returns me an error as : expected tuple (Comandi_TO, rusqlite::Error)
found unit type () differently with Ok(Commands_TO) i obtain : expected value, found struct Commands_TO

Your last expression without a trailing ; is what is returned from your method (relevant chapter from the book). You must return a value of type Result<Commands_TO, Error>. Ok(()) is not of type Result<Commands_TO, Error> but of type Result<(), Error>[1], nor is Ok(Commands_TO). Commands_TO is just the name of a struct in your program, it is not even a value. The right value to return from your method would be Ok(self), since self is a value of type Commands_TO and Ok is an enumeration variant of Result which indicates that a computation has succeeded (contrary to the other variant of Result, Err, which indicates that a computation failed). You should probably read this chapter from the book on Result which describes much better what I'm trying to say.

Having said all this, a couple of changes to your method should make it work:

pub fn new(mut self ,sql_db: &str) -> Result<Commands_TO, rusqlite::Error> {
    let conn = Connection::open(sql_db)?;
    let mut query = conn.prepare("SELECT * FROM Comandi_TO LIMIT 10")?;
    
    let rows = query.query_map([], |row| {
        Ok(Command_TO {
            id_type: row.get(0).expect("error field Id_type"),
            id_variable: row.get(1).expect("error field id_variable"),
            type_command: row.get(2).expect("error field type_command"),
            label_command: row.get(3).expect("error field label_command"),
        })
    })?;

    let id_iter_collection= id_iter.collect::<Result<Vec<Comando_TO>>>().unwrap();
    self.Command_TO_vec.push(id_iter_collection);
    println!("{:?}",self.Command_TO_vec);
    Ok(self)
}

I changed the last expression to match your return type and removed the & from &mut self in the argument. Otherwise we'd get another error, because we'd try to move out of borrowed content (see this chapter from the book).


  1. () is the empty tuple, also called unit type and can crudely be described as meaning "nothing to return" ↩︎

In this case you don't manage the error.

mismatched types
expected tuple `(Commands_TO, rusqlite::Error)`
  found struct `Commands_TO`

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.