I am trying to order diesel queries dynamically, something like this question. QueryOrdering::order_query works fine, but when I tried to create the DynOrderDsl trait, so that I can build the queries by chaining functions like in the example fn I cannot get the code to compile.
I think the trait bounds should be fine, since those are all copy pasted from QueryOrdering::order_query which works.
#[macro_use]
extern crate diesel;
use diesel::backend::Backend;
use diesel::dsl::{Asc, Desc};
use diesel::helper_types::IntoBoxed;
use diesel::query_dsl::methods::{BoxedDsl, OrderDsl};
use diesel::{table, ExpressionMethods, QueryDsl};
table! {
posts (id) {
id -> Nullable<Integer>,
}
}
enum QueryOrdering {
Ascending,
Descending,
}
impl QueryOrdering {
fn order_query<'a, Expr, Q, DB>(&self, query: Q, expr: Expr) -> IntoBoxed<'a, Q, DB>
where
Expr: ExpressionMethods,
Q: QueryDsl + BoxedDsl<'a, DB>,
DB: Backend,
IntoBoxed<'a, Q, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Q, DB>>
+ OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Q, DB>>,
{
match self {
Self::Ascending => query.into_boxed().order(expr.asc()),
Self::Descending => query.into_boxed().order(expr.desc()),
}
}
}
pub trait DynOrderDsl<'a, DB, Expr>
where
Expr: ExpressionMethods,
Self: QueryDsl + BoxedDsl<'a, DB>,
DB: Backend,
IntoBoxed<'a, Self, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Self, DB>>
+ OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Self, DB>>,
{
fn dyn_order(self, order: QueryOrdering, expr: Expr) -> IntoBoxed<'a, Self, DB>;
}
impl<'a, Expr, DB, Q> DynOrderDsl<'a, Expr, DB> for Q
where
Expr: ExpressionMethods,
Q: QueryDsl + BoxedDsl<'a, DB>,
DB: Backend,
IntoBoxed<'a, Q, DB>: OrderDsl<Asc<Expr>, Output = IntoBoxed<'a, Q, DB>>
+ OrderDsl<Desc<Expr>, Output = IntoBoxed<'a, Q, DB>>,
{
fn dyn_order(self, order: QueryOrdering, expr: Expr) -> IntoBoxed<'a, Q, DB> {
order.order_query(self, expr)
}
}
fn example<DB: Backend>(order: QueryOrdering) {
order
.order_query::<_, _, DB>(posts::table, posts::id)
.limit(5);
// want to do this instead
posts::table.dyn_order(order, posts::id).limit(5);
}
The compiler shows this error
error[E0275]: overflow evaluating the requirement `Q: BoxedDsl<'_, Expr>`
--> src/main.rs:48:23
|
48 | impl<'a, Expr, DB, Q> DynOrderDsl<'a, Expr, DB> for Q
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`databases`)
= note: required for `Q` to implement `BoxedDsl<'_, Expr>`
= note: 126 redundant requirements hidden
= note: required for `Q` to implement `BoxedDsl<'_, Expr>`
As I see I somehow should tell the compiler that
I got it in the end. The order of generic arguments in the impl of DynOrderDsl and the trait decralation was wrong. The final, working code:
I will post the final working code to the question I linked at the start.
Related
I am trying to send the Polars dataframe over juniper GraphQL, but #[juniper::graphql_object] is complaining about trail bound
the trait bound `Result<HashMap<std::string::String, polars::prelude::DataFrame>, FieldError>: IntoResolvable<'_, __S, _, ()>` is not satisfied
the following other types implement trait `IntoResolvable<'a, S, T, C>`:
<Result<(&'a <T as GraphQLValue<S2>>::Context, T), FieldError<S1>> as IntoResolvable<'a, S2, T, C>>
<Result<T, E> as IntoResolvable<'a, S, T, C>>
<Result<std::option::Option<(&'a <T as GraphQLValue<S2>>::Context, T)>, FieldError<S1>> as IntoResolvable<'a, S2, std::option::Option<T>, C>>
Here is my Rust code.
use juniper::{EmptySubscription,
FieldResult,
RootNode,
EmptyMutation};
use polars::prelude::DataFrame;
use std::collections::HashMap;
pub struct QueryRoot;
#[juniper::graphql_object]
impl QueryRoot {
fn fetch_data() -> FieldResult<HashMap<String, DataFrame>> {
// ...
let data: HashMap<String, DataFrame> = fetch_my_data();
Ok(data)
}
}
pub type Schema = RootNode<'static, QueryRoot, EmptyMutation, EmptySubscription>;
pub fn create_schema() -> Schema {
Schema::new(QueryRoot {}, EmptyMutation::new(), EmptySubscription::new())
}
I am guessing that juniper cannot recognize polar's Dataframe struct as graphqlobject. I am wondering if anyone knows how to fix this compile error. I also tried with serde_json, but no luck so far.
Would like to make this function generic but having trouble specifying the bounds for parameter T
Errors : 1)'cannot find type DB in this scope
not found in this scope'
Not sure if I was supposed to include ::bind either. I got that from rust-analyzer
pub async fn set_db_value<
'q,
T: std::marker::Sync
+ std::marker::Send
+ sqlx::query::Query<'q, DB, <DB as HasArguments<'q>>::Arguments>::bind,
>(
key: &str,
b: T,
) {
let statement = format!("update preferences set {} = $1 where key = 'p'", &key);
sqlx::query(&statement)
.bind(&b)
.execute(&pg)
.await
.unwrap();
}
I'm learning Rust, (coming from Java) and decided to write a Chess Engine in Rust (as I previously have in Java) to get used to the language.
I've made structs for different types of chess moves (Slide, Passant, Castle, etc), each of which implements the Move trait. Here is an example:
pub struct PawnPush{
indices: [i8; 2],
befores: [i8; 2],
afters: [i8; 2],
passant_before: i8,
}
impl PawnPush{
pub fn new(from_index: i8, passant_square: i8) -> Self{
if from_index < 32{
Self{
indices: [from_index, from_index + 16],
befores: [piece::WP, piece::__],
afters: [piece::__, piece::WP],
passant_before : passant_square,
}
}
else{
Self{
indices: [from_index, from_index - 16],
befores: [piece::BP, piece::__],
afters: [piece::__, piece::BP],
passant_before : passant_square,
}
}
}
}
impl Move for PawnPush{
fn indices(&self) -> &[i8]{
return &(self.indices);
}
fn befores(&self) -> &[i8]{
return &(self.befores);
}
fn afters(&self) -> &[i8]{
return &(self.afters);
}
fn is_capture(&self) -> bool{
return false;
}
fn is_reversible(&self) -> bool{
return false;
}
fn passant_before(&self) -> i8{
return self.passant_before;
}
fn passant_after(&self) -> i8{
return if self.indices[0] < 32 {self.indices[0] + 8} else {self.indices[0] - 8};
}
fn get_name(&self) -> String{
return "".to_string();
}
fn moves_king(&self) -> bool{
return false;
}
}
The idea is that the Board can iterate through indices, befores, and afters of any move to implement them.
I've read through https://doc.rust-lang.org/book/ch17-02-trait-objects.html, and following that, I have some functions defined as such.
pub fn get_moves(&self) -> Vec<Box<dyn Move>>
pub fn take_move(&mut self, m : &impl Move)
The question is: How can I get an element from the vector returned from the first function to be given to the second function?
Like, if I do:
fn main() {
let mut b = Board::new(true);
let m = chess_move::PawnPush::new(12, -1);
b.take_move(&m);
b.print_board();
}
This works just fine.
Yet if I try something like:
fn main() {
let mut b = Board::new(true);
let m = b.get_moves()[0];
b.take_move(&m);
b.print_board();
}
I am met with a compilation error:
error[E0277]: the trait bound `Box<dyn Move>: Move` is not satisfied
--> board.rs:143:14
|
143 | b.take_move(&m);
| --------- ^^ the trait `Move` is not implemented for `Box<dyn Move>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Move`:
Castle
KingMove
Passant
PawnPush
Slide
note: required by a bound in `Board::take_move`
--> board.rs:101:40
|
101 | pub fn take_move(&mut self, m : &impl Move){
| ^^^^ required by this bound in `Board::take_move`
Yet, I can still otherwise treat elements of b.get_moves() as if it did impl Move - I can call the methods from Move on m., such as:
fn main() {
let mut b = Board::new(true);
for m in b.get_moves(){
println!("{}",m.is_capture());
}
}
The Rust docs even have this example:
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
It seems strange to me that I can otherwise treat elements of b.get_moves() as if it did impl Move but I can't give it's reference to a function that wants a &impl Move. I'd greatly appreciate an explanation of what Box is/does, as I couldn't really find much about it online.
Additionally, I'm also open to any suggestions if my entire approach is wrong and I shouldn't be handling things in this way. Again, most of my programming experience is in Java, so maybe I'm trying to force OOP where it's not needed.
b.get_moves() returns Vec<Box<dyn Move>>. Therefore, b.get_moves()[0] returns Box<dyn Move>. This type does not implement Move itself, because you haven't written such implementation.
However, Box implements Deref, and as such can behave in many ways "as if" it was the inner type. The meaning of Deref is that you can use the * operator on it: for example, &*b.get_moves(0)[0] will give you &dyn Move, which is what you want. However, as Rust "auto-derefs" method calls, in other words, calls * as many times as needed automatically, you can call methods of Move directly on Box<dyn Move>, without the need to do (*v).method().
I want to write a function that will insert a type into a database where the database connection parameter is generic, so that it can work on multiple backends.
I came up with the following function to insert an object using a generic connection:
pub fn create_label<C>(connection: &C, label: &model::Label)
where
C: Connection,
C::Backend: diesel::backend::Backend,
C::Backend: diesel::backend::SupportsDefaultKeyword,
{
diesel::insert(&label)
.into(schema::label::table)
.execute(connection);
}
If I don't include the SupportsDefaultKeyword constraint, the function will not compile. When calling it with a SqliteConnection as the connection parameter, I get the following error:
database::create_label(&db_conn, &label);
^^^^^^^^^^^^^^^^^^^^^^ the trait
'diesel::backend::SupportsDefaultKeyword' is not implemented for
'diesel::sqlite::Sqlite'
This would imply that inserting data with a SqliteConnection does not work. That's obviously not the case, and furthermore changing create_label such that it takes a SqliteConnection directly works just fine.
pub fn create_label(connection: &SqliteConnection, label: &model::Label) {
diesel::insert(&label)
.into(schema::label::table)
.execute(connection);
}
Why is it that the generic function requires the SupportsDefaultKeyword constraint and the function taking SqliteConnection does not?
Here is a minimal example illustrating the problem. As per the comments, line 60 of main.rs will not compile with the error from above, whereas line 61 does compile:
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
mod schema {
table! {
labels {
id -> Integer,
name -> VarChar,
}
}
}
mod model {
use schema::labels;
#[derive(Debug, Identifiable, Insertable)]
#[table_name = "labels"]
pub struct Label {
pub id: i32,
pub name: String,
}
}
use diesel::ExecuteDsl;
use diesel::Connection;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
pub fn create_label<C>(connection: &C, label: &model::Label)
where
C: Connection,
C::Backend: diesel::backend::Backend,
C::Backend: diesel::backend::SupportsDefaultKeyword,
{
diesel::insert(label)
.into(schema::labels::table)
.execute(connection)
.expect("nope");
}
pub fn create_label_sqlite(connection: &SqliteConnection, label: &model::Label) {
diesel::insert(label)
.into(schema::labels::table)
.execute(connection)
.expect("nope");
}
pub fn establish_connection() -> SqliteConnection {
let url = "test.db";
SqliteConnection::establish(&url).expect(&format!("Error connecting to {}", url))
}
fn main() {
let label = model::Label {
id: 1,
name: String::from("test"),
};
let conn = establish_connection();
create_label(&conn, &label); /* Does not compile */
create_label_sqlite(&conn, &label); /*Compiles */
}
[dependencies]
diesel = { version = "0.16.0", features = ["sqlite"] }
diesel_codegen = "0.16.0"
The Diesel function execute has multiple concrete implementations. The two that are relevant here are:
impl<'a, T, U, Op, Ret, Conn, DB> ExecuteDsl<Conn, DB> for BatchInsertStatement<T, &'a [U], Op, Ret>
where
Conn: Connection<Backend = DB>,
DB: Backend + SupportsDefaultKeyword,
InsertStatement<T, &'a [U], Op, Ret>: ExecuteDsl<Conn>,
impl<'a, T, U, Op, Ret> ExecuteDsl<SqliteConnection> for BatchInsertStatement<T, &'a [U], Op, Ret>
where
InsertStatement<T, &'a U, Op, Ret>: ExecuteDsl<SqliteConnection>,
T: Copy,
Op: Copy,
Ret: Copy,
As you can see from these two, the implementation for SQLite is special-cased. I don't know enough about the details of Diesel to know why, but I'd guess that SQLite is missing the default keyword.
You can instead reformulate the requirements for any connection that works with that particular statement:
use diesel::query_builder::insert_statement::InsertStatement;
pub fn create_label<C>(connection: &C, label: &model::Label)
where
C: Connection,
for<'a> InsertStatement<schema::labels::table, &'a model::Label>: ExecuteDsl<C>,
{
diesel::insert(label)
.into(schema::labels::table)
.execute(connection)
.expect("nope");
}
Is there a type that preserves insertion order (think Vec) but only tracks unique values (think HashSet)? I want to avoid using Vec because I would first need to check if the value exists in it before insertion.
linked_hash_set crate is now available. It's based on the
linked-hash-map crate mirroring the std HashSet API as closely as possible.
extern crate linked_hash_set;
use linked_hash_set::LinkedHashSet;
let mut set = LinkedHashSet::new();
set.insert(234);
set.insert(123);
set.insert(345);
set.insert(123);
assert_eq!(set.into_iter().collect::<Vec<_>>(), vec![234, 345, 123]);
The linked-hash-map crate provides a hash map that holds key-value insertion order. We can create a set wrapper for this hash map using () as values (std::collections::HashSet is implemented this way):
extern crate linked_hash_map;
use linked_hash_map::*;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash};
use std::borrow::Borrow;
fn main() {
let mut s = LinkedHashSet::new();
s.insert(5);
s.insert(3);
s.insert(7);
s.insert(1);
assert_eq!(vec![5, 3, 7, 1], s.iter().cloned().collect::<Vec<_>>());
s.remove(&7);
assert_eq!(vec![5, 3, 1], s.iter().cloned().collect::<Vec<_>>());
s.remove(&5);
assert_eq!(vec![3, 1], s.iter().cloned().collect::<Vec<_>>());
}
pub struct LinkedHashSet<K, S = RandomState>(LinkedHashMap<K, (), S>);
impl<K: Hash + Eq> LinkedHashSet<K> {
pub fn new() -> Self {
LinkedHashSet(LinkedHashMap::new())
}
}
impl<K: Hash + Eq, S: BuildHasher> LinkedHashSet<K, S> {
pub fn insert(&mut self, k: K) -> Option<()> {
self.0.insert(k, ())
}
pub fn contains<Q: ?Sized>(&self, k: &Q) -> bool
where K: Borrow<Q>,
Q: Eq + Hash
{
self.0.contains_key(k)
}
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<()>
where K: Borrow<Q>,
Q: Eq + Hash
{
self.0.remove(k)
}
pub fn iter(&self) -> Keys<K, ()> {
self.0.keys()
}
}
You can implement other methods. See LinkedHashMap docs.
Updating answers since linked-hash-map is in maintenance mode (see github commit)
The most popular github crates in September 2021:
indexmap which provide direct implementation of IndexSet.
array_tool which provide helper to build a vector set data structure with few lines of code.
RiteLinked provides more up to date versions of LinkedHashMap & LinkedHashSet in Rust. You can easily use it on std or no_std environment. You can use it instead of linked-hash-map and linked_hash_set.
https://github.com/ritedb/ritelinked
https://crates.io/crates/ritelinked