How to use i64 with Insertable using Diesel - sqlite

How do I use i64/u64 with Diesel?
Do I really need to implement the diesel::Expression trait for the primitive type?
Here is my code.
Cargo.toml:
[dependencies]
...
diesel = { version = "1.4.5", features = ["sqlite", "numeric"] }
migration/up.sql:
CREATE TABLE books (
id INTEGER NOT NULL PRIMARY KEY,
size INTEGER NOT NULL
);
schema.rs:
table! {
books (id) {
id -> Integer,
size -> Integer,
}
}
sources:
use crate::schema::books;
#[derive(Insertable, Queryable)]
#[table_name="books"]
pub struct BookRecord {
pub id: Id,
pub size: i64,
}
This gives the following error:
error[E0277]: the trait bound `i64: diesel::Expression` is not satisfied
--> src/lib/models/book.rs:4:10
|
4 | #[derive(Insertable, Queryable)]
| ^^^^^^^^^^ the trait `diesel::Expression` is not implemented for `i64`
|
= note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::Integer>` for `i64`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
How do I resolve this error?

i64 corresponds to BigInt and i32 corresponds to Integer. Either change your schema to use BigInt, or change your numbers to i32.

Related

What is the best way to store an enum in a database in rusqlite?

If I have a simple struct, one attribute of which contains a simple enum, how can I best store examples of this struct with their enumerations in the rusqlite database? Something like:
use rusqlite::{params, Connection, Result};
enum Sex{
Unknown,
Male,
Female,
}
struct Person{
name: String,
sex: Sex
}
fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
conn.execute(
"CREATE TABLE people(
name TEXT NOT NULL,
sex TEXT NOT NULL
)",
(), // empty list of parameters.
)?;
let person_01 = Person{
name: String::from("Adam"),
sex: Sex::Male
};
conn.execute(
"INSERT INTO people (name, sex) VALUES (?1, ?2)",
(&person_01.name, &person_01.sex),
)?;
Ok(())
}
The problem is that sqlite only allows data of restricted types (NULL, INTEGER, REAL, TEXT), trying to use TEXT here for the enum gives the following error:
error[E0277]: the trait bound `Sex: ToSql` is not satisfied
--> src/main.rs:33:9
|
31 | conn.execute(
| ------- required by a bound introduced by this call
32 | "INSERT INTO tasklist (name, sex) VALUES (?1, ?2)",
33 | (&person_01.name, &person_01.sex),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSql` is not implemented for `Sex`
This error makes sense, but what is the best way to implement this? Cast the enum to int? I read here that this is "removes the guarantee that values always represent the variants of the enum", which I agree with. It would be nicer to match the string.
I have tried to do this using strum, which allows me to add to_str & from_str to the enum, allowing it to be added to the database like so:
#[derive(strum_macros::Display, strum_macros::EnumString, Debug)]
enum Sex{
Unknown,
Male,
Female,
}
...
conn.execute(
"INSERT INTO people (name, sex) VALUES (?1, ?2)",
(&person_01.name, &person_01.sex.to_string())
)?;
and retrieved like so:
let mut stmt = conn.prepare("SELECT name, sex FROM people")?;
let person_itr = stmt.query_map([], |row|{
Ok(
Person{
name: row.get(0)?,
sex: Sex::from_str(String::as_str(&row.get(1)?)).unwrap(),
}
)
});
but this feels messy. Is there a better way?
I have seen here people manually implementing FromSqlRow for the enum, but is there a better (quicker) way?
The right way to handle this is to implement ToSql and FromSql directly on your enum. This will make using it substantially more ergonomic, and possibly more efficient since you don't first have to convert to a type with an allocation, like String.
It also means the conversion to/from a string doesn't "infect" every interaction you have with the database; the conversion becomes automatic. So, while there is a bit more boilerplate, it will pay off every time you use this type in conjunction with the database.
impl ToSql for Sex {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
Ok(self.to_string().into())
}
}
impl FromSql for Sex {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str()?.parse()
.map_err(|e| FromSqlError::Other(Box::new(e)))
}
}
Now you can just do this when converting to Person:
sex: row.get(1)?,
Note that FromSqlRow is a trait specific to a postgres client; rusqlite has no such trait. If you wanted to, you could create a factory method on Person that constructs from a Row. That's up to you.

executing method on variable pointer moves the variable itself?

I'm using the rusqlite crate and am doing some queries, basically i'm just trying to check the length of the query results before trying to proceed, however I'm running into error[E0382]: use of moved value: key_rows whilst trying to compile, I don't understand since i'm borrowing a reference to the variable so it wouldn't move it's local in memory?
Maybe it's due to the method i'm calling on the variable's pointer?
Full compiler error:
error[E0382]: use of moved value: `key_rows`
--> src/handle.rs:126:16
|
108 | let key_rows = key_stmt.query_map(&[(":key", key.as_str())], |row| {
| -------- move occurs because `key_rows` has type `MappedRows<'_, [closure#src/handle.rs:108:66: 113:6]>`, which does not implement the `Copy` trait
...
117 | if(&key_rows.count() == &0){
| ------- `key_rows` moved due to this method call
...
126 | for row in key_rows {
| ^^^^^^^^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `key_rows`
Erroneous code:
let mut key_stmt = conn.prepare("SELECT id , key FROM key_table WHERE key = :key;").unwrap();
let key_rows = key_stmt.query_map(&[(":key", key.as_str())], |row| {
Ok(Table {
id: row.get(0)?,
payload: row.get(1)?,
})
}).unwrap();
//Checking that the key exists:
if(&key_rows.count() == &0){
panic!("Can't find the key...")
}
//Putting in a default value since the compiler is worried.
let mut reference_id : i32 = 0;
//For loop is nessessary since MappedRow type cannot be indexed regularly (weird)
for row in key_rows {
reference_id = row.unwrap().id;
println!("{:?}", reference_id.to_string());
}
You aren't borrowing key_rows then checking the count, but rather calling key_rows.count(), then borrowing the result.
Iterator#count consumes the entire iterator, returning how many elements were traversed.
let mut reference_id = key_rows.next().unwrap_or_else(|| panic!("Can't find the key..."));
// Remove the code past this point if you are only expecting one, or the first value.
for row in key_rows {
reference_id = row.unwrap().id;
println!("{:?}", reference_id.to_string());
}

Following "getting started" diesel tutorial, but with sqlite, causes

I'm trying to follow: https://diesel.rs/guides/getting-started but I'm using:
echo DATABASE_URL=/tmp/diesel_demo.sqlite > .env
instead of a Postgres database.
I've changed all occurrences of Pg to Sqlite, and SERIAL to INT, but get the following error:
error[E0277]: the trait bound `i32: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Integer>, Sqlite>` is not satisfied
--> src/bin/show_posts.rs:14:10
|
14 | .load::<Post>(&connection)
| ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Integer>, Sqlite>` is not implemented for `i32`
How to get a result set where field value == row number?
show_posts.rs:
extern crate diesel_demo;
extern crate diesel;
use self::diesel_demo::*;
use self::models::*;
use self::diesel::prelude::*;
fn main() {
use diesel_demo::schema::posts::dsl::*;
let connection = establish_connection();
let results = posts.filter(published.eq(true))
.limit(5)
.load::<Post>(&connection)
.expect("Error loading posts");
println!("Displaying {} posts", results.len());
for post in results {
println!("{}", post.title);
println!("----------\n");
println!("{}", post.body);
}
}
up.sql:
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
title VARCHAR NOT NULL,
body TEXT NOT NULL,
published BOOLEAN NOT NULL DEFAULT 'f'
)
models.rs (autogenerated):
#[derive(Queryable)]
pub struct Post {
pub id: i32,
pub title: String,
pub body: String,
pub published: bool,
}
I don't understand why Diesel expects id to be Nullable.
Adding NOT NULL to the id field in up.sql fixed it.

Cannot infer type for type parameter T, when the type is explicitly specified in a struct definition

I have a struct definition which includes, among other things, this field:
pub struct Separated<'a, I, T>
{
..., // other fields,
separated: NonNull<dyn 'a + Iterator<Item = T>>,
}
Shortly after, in its constructor, I attempt to initialize that field as a dangling pointer:
let sep = Separated {
..., // other fields
separated: NonNull::dangling(),
};
This, weirdly, produces this error:
error[E0282]: type annotations needed
|
16 | separated: NonNull::dangling(),
| ^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
There's nothing mysterious about that field; its type is explicitly set in the struct definition. I do not understand why the type inferencer cannot infer an appropriate type to inject there.
A minimal 20-line example producing this error can be found below and on the playground:
use std::pin::Pin;
use std::ptr::NonNull;
pub struct Separated<'a, T> {
t: &'a T,
separated: NonNull<dyn 'a + Iterator<Item = T>>,
}
impl<'a, T> Separated<'a, T>
where
T: 'a + Copy + PartialEq,
{
fn new(t: &'a T) -> Pin<Box<Self>> {
let sep = Separated {
t,
separated: NonNull::dangling(),
};
unimplemented!()
}
}
I do need separated to be a pointer to a trait object instead of a monomorphized type: the real trait object which it will contain is composed of a bunch of iterator combinators, including ones like Map and TakeWhile, whose types include function pointers and are therefore unnameable.
NonNull::dangling is not a parametric function: the NonNull<T> struct is parametric, but this function is not. Therefore, I can't just turbofish my way out of this. I'm not sure how I'd go about providing type annotations at all.
Context, if useful: the whole reason I'm going down this path is I am attempting to create an iterator combinator, auto-implemented for all appropriate iterators, which injects a single element between each N elements of the origin iterator. It's not all that hard to accomplish for a single iterator, but much harder to do as a generic combinator, because the IntoChunks struct produced by Itertools' chunks() combinator is not itself an iterator, just a struct implementing IntoIterator. Therefore, we need to keep track of the IntoChunks struct as well as the iterator it produces.
The approach I'm taking is to create a self-referential struct, Separated, which contains both of those. This should be safe assuming the struct is always pinned. I then impl Iterator for Separated and just defer the next calls to self.separated.
According to the standard docs, the definition of NonNull::dangling() is this:
impl<T> NonNull<T> {
pub const fn dangling() -> NonNull<T> {
/* ... */
}
}
And in your code, you're using it in a place where an expression with the type NonNull<dyn 'a + Iterator<Item = T>>, so the return value must have this type.
The subtle thing here is that generic type parameters have an implicit Sized bound (unless it has a ?Sized bound). So because the implementation of NonNull::dangling does not have a ?Sized bound, Rust will attempt to infer the type parameter of NonNull based on these requirements:
Because the NonNull::<T>::dangling() method does not have a bound T: ?Sized, it is only implemented for sized types T, and the type parameter must be sized.
The type parameter must be dyn 'a + Iterator<Item = T>.
However, because trait objects ("dyn Trait types") are unsized, it is impossible for Rust to satisfy both requirements at once, hence why it "cannot infer type for type parameter T".
In fact, by explicitly adding the type to your playground example, you'll get a different error message that's more explicit about the problem:
let sep = Separated::<'a, T> {
t,
separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
};
error[E0599]: no function or associated item named `dangling` found for type `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>` in the current scope
--> src/lib.rs:16:64
|
16 | separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
| ^^^^^^^^ function or associated item not found in `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>`
|
= note: the method `dangling` exists but the following trait bounds were not satisfied:
`dyn std::iter::Iterator<Item = T> : std::marker::Sized`

Store data that implements a trait in a vector

I'm very new to Rust and system languages in general. And I'm currently playing around with Rust to explore the language. I've a problem that I cannot fix by myself. And I think I've understanding problem whats going on.
I wan't to store objects that implements the trait BaseStuff in a vector. In Rust not a simple task for me :-).
Here is my example code that won't compile.
trait BaseStuff {}
struct MyStuff {
value: i32,
}
struct AwesomeStuff {
value: f32,
text: String,
}
impl BaseStuff for MyStuff {}
impl BaseStuff for AwesomeStuff {}
struct Holder {
stuff: Vec<BaseStuff>,
}
impl Holder {
fn register(&mut self, data: impl BaseStuff) {
self.stuff.push(data);
}
}
fn main() {
let my_stuff = MyStuff { value: 100 };
let awesome_stuff = AwesomeStuff {
value: 100.0,
text: String::from("I'm so awesome!"),
};
let mut holder = Holder { stuff: vec![] };
holder.register(my_stuff);
}
error[E0277]: the size for values of type (dyn BaseStuff + 'static)
cannot be known at compilation time --> src\main.rs:17:5 | 17 |
stuff: Vec, // unknown size | ^^^^^^^^^^^^^^^^^^^^^
doesn't have a size known at compile-time | = help: the trait
std::marker::Sized is not implemented for (dyn BaseStuff +
'static) = note: to learn more, visit
https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
= note: required by std::vec::Vec
error: aborting due to previous error
For more information about this error, try rustc --explain E0277.
error: Could not compile playground.
The compiler message is clear and I understand the message. I can
implement the trait BaseStuff in any struct I want't so its unclear
which size it is. Btw the link isn't helpful because its pointing to
outdated site...
The size of String is also unknown, but the String implements the trait std::marker::Sized and that's why a Vec<String> will work without problems. Is that correct?
In the rust book I read for data types with unknown size I've to store these data on the heap instead of the stack. I changed my code as follows.
struct Holder {
stuff: Vec<Box<BaseStuff>>,
}
impl Holder {
fn register(&mut self, data: impl BaseStuff) {
self.stuff.push(Box::new(data));
}
}
Now I'm hitting a new compiler issue:
error[E0310]: the parameter type impl BaseStuff may not live long
enough --> src\main.rs:22:25 | 21 | fn register(&mut self,
data: impl BaseStuff) { |
--------------- help: consider adding an explicit lifetime bound impl BaseStuff: 'static... 22 | self.stuff.push(Box::new(data));
| ^^^^^^^^^^^^^^ | note: ...so that the
type impl BaseStuff will meet its required lifetime bounds -->
src\main.rs:22:25 | 22 | self.stuff.push(Box::new(data));
| ^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try rustc --explain E0310.
error: Could not compile playground.
And know I'm out... I read in the book about lifetimes and changed my code a lot with 'a here and 'a in any combination but without luck... I don't want to write down any lifetime definition combination I tried.
I don't understand why I need the lifetime definition. The ownership is moved in any step so for my understanding its clear that Holder struct is the owner for all data. Is it?
How can I correct my code to compile?
Thanks for help.
You almost got it - the issue here is that the type for which BaseStuff is implemented may be a reference (e.g. impl BaseStuff for &SomeType). This means that even though you're passing data by value, the value may be a reference that will be outlived by your Box.
The way to fix this is to add a constraint such that the object has a 'static lifetime, meaning it will either be a value type or a static reference. You can apply this constraint to the trait or the method accepting the trait, depending on your use case.
Applying the constraint to the trait:
trait BaseStuff: 'static {}
Applying the constraint to the method:
impl Holder {
fn register(&mut self, data: impl BaseStuff + 'static) {
self.stuff.push(Box::new(data));
}
}
If you add the 'static constraint to the method, I would recommend also adding it to the Vec to avoid losing type information, like so:
struct Holder {
stuff: Vec<Box<dyn BaseStuff + 'static>>,
}

Resources