1

I am trying to do a get a object from a database with Diesel when the Enter key is pressed in a gtk Entry. My idea is to create a Diesel SQLite connection in main function and then borrow it every time that I need it.

To do that, I am trying to use a very simple MVC. The idea is to pass the connection to all the controllers and reuse it. I know that lifetime is necessary here.

pub struct Controller<'a> {
    pub connection: &'a SQLiteConnection,
    pub search_entry: SearchEntry,
    ....
}

impl<'a> Controller<'a> {

    pub fn new(conn: &'a SQLiteConnection) -> Self {
        Self {
            search_entry: SearchEntry::new(),
            connection: conn,
            ....
        }
    }

    pub fn init(&self) {
        self.search_entry.connect_activate(|x| {
            let need_it = diesel_table
            .filter(column_id.eq(&x.get_text().unwrap()))
            .first(self.connection)
            .unwrap();
        });
    }
}

When compile I get this:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:44:44
   |
44 |           self.search_entry.connect_activate(|x| {
   |  ____________________________________________^
45 | |             let need_it = diesel_table
46 | |                 .filter(column_id.eq(&x.get_text().unwrap()))
47 | |                 .first(self.connection)
48 | |                 .unwrap();
49 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 43:5...
  --> src/lib.rs:43:5
   |
43 | /     pub fn init(&self) {
44 | |         let need_it = diesel_table
46 | |                 .filter(column_id.eq(&x.get_text().unwrap()))
47 | |                 .first(self.connection)
48 | |                 .unwrap();
49 | |         });
50 | |     }
   | |_____^
note: ...so that the types are compatible
  --> src/lib.rs:44:44
   |
44 |           self.search_entry.connect_activate(|x| {
   |  ____________________________________________^
45 | |             let need_it = diesel_table
46 | |                 .filter(column_id.eq(&x.get_text().unwrap()))
47 | |                 .first(self.connection)
48 | |                 .unwrap();
49 | |         });
   | |_________^
   = note: expected  `&&Controller<'_>`
              found  `&&Controller<'a>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/lib.rs:44:44: 49:10 self:&&Controller<'_>]` will meet its required lifetime bounds
  --> src/lib.rs:44:27
   |
44 |         self.search_entry.connect_activate(|x| {
   |                           ^^^^^^^^^^^^^^^^

This error is because the function connect_activate has a static parameter: fn connect_activate<F: Fn(&Self) + 'static>.

I would not like to initialize the connection every time that the user press the Intro key by using a function that returns a connection. Instead I would like to borrow that connection.

What would be the most efficient way to do that?

Thanks you very much. I hope you understand everything.

2 Answers2

1

I think you need a Rc<SQLiteConnection>

elsuizo
  • 144
  • 1
  • 3
0

The question contains various other code issues beside the one mentioned by the OP, so I will include a full working example based on the information provided above. For future questions: Please make sure that your example is self contained and do not contain other compilation errors as that one mentioned in the question. That will make it easier for other people to reproduce your problem and answer the question.

#[macro_use] extern crate diesel;

use diesel::prelude::*;

table! {
    diesel_table(id) {
        id -> Integer,
        column_id -> Text,
    }
}

pub struct Controller<'a> {
    pub connection: &'a SqliteConnection,
    pub search_entry: SearchEntry,
}

pub struct SearchEntry;

impl SearchEntry {
    fn new() -> Self {
        SearchEntry
    }

    fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {
        f(self)
    }

    fn get_text(&self) -> Option<&'static str> {
        Some("foo")
    }
}

impl<'a> Controller<'a> {

    pub fn new(conn: &'a SqliteConnection) -> Self {
        Self {
            search_entry: SearchEntry::new(),
            connection: conn,
        }
    }

    pub fn init(&self) {
        self.search_entry.connect_activate(|x| {
            use self::diesel_table::dsl::*;

            let need_it: (i32, String) = diesel_table
            .filter(column_id.eq(&x.get_text().unwrap()))
            .first(self.connection)
            .unwrap();
        });
    }
}

The only relevant change for solving the error described in the OP is the following change to connect_activate:

- fn connect_activate<F: Fn(&Self) + 'static>(&self, f: F) {
+ fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {
weiznich
  • 2,910
  • 9
  • 16