how to handle the moved exception in a loop in rust - rust

I want to map entity from one Vec(this entity list search from database) into another Vec(this response entity list return to frontend) in rust, this is my code:
fn main() {
let musics:Vec<Music> = Vec::new();
for x in 0..10 {
let filtered_music:Vec<Music> = musics.into_iter()
.filter(|item| item.source_id == "1")
.collect();
let resp = MusicRes{
music: take(filtered_music, 0).unwrap()
};
}
}
fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> {
if index < vec.len() {
Some(vec.swap_remove(index))
} else {
None
}
}
pub struct Music {
pub id: i64,
pub name: String,
pub artists: String,
pub album_id: i64,
pub publishtime: i64,
pub status: i32,
pub duration: i32,
pub source_id: String,
pub source: i32,
pub created_time: i64,
pub updated_time:i64,
pub album: String,
pub fetched_download_url: i32
}
pub struct MusicRes {
pub music:Music
}
this code give me tips that musics was moved. I could change the musics to &musics, but the returned response need to Music. How to handle this situation properly?

I'm not exactly sure what your requirements are, ie. what's the point of the 0..10 then taking the 0th element, but you could do something like this:
let musics: Vec<_> = musics
.into_iter()
.take(10)
.filter(|m| m.source_id == "1")
.map(|m| MusicRes { music: m })
.collect();

Related

how to define multi parameter with from function in rust

Now I want to map object from Favorites to FavMusicResponse, the Favorites object was selected from database and the FavMusicResponse entity was return to the client. I define the map function like this way in FavMusicResponse:
impl From<&Favorites> for FavMusicResponse {
fn from(f: &Favorites, music: Music) -> Self {
Self{
id: f.id,
song_id: None,
created_time: f.created_time,
updated_time: f.updated_time,
user_id: 0,
source_id: "".to_string(),
like_status: 0,
source: 0,
playlist_id: 0,
play_count: 0,
fetched_download_url: None,
downloaded: None,
music: Default::default()
}
}
}
most of the fields from Favorites fields are the same with FavMusicResponse, the only difference is that music was passed from another entity. This is my FavMusicResponse define:
#[derive( Serialize, Queryable, Deserialize,Default, Clone)]
pub struct FavMusicResponse{
pub id: i64,
pub song_id: Option<i64>,
pub created_time: i64,
pub updated_time: i64,
pub user_id: i64,
pub source_id: String,
pub like_status: i32,
pub source: i32,
pub playlist_id: i64,
pub play_count: i32,
pub fetched_download_url: Option<i32>,
pub downloaded: Option<i32>,
pub music: Music
}
the compiler tell me that from expected 1 parameter, found 2, what should I do do pass 2 or more parameter into the composite function in rust? I invoke the function like this way:
let filtered_music:Vec<_> = musics.iter()
.filter(|item| item.source_id == fav.source_id)
.map(|item|FavMusicResponse::from(fav,item.clone()))
.collect();
I want to passed two entity and composite to the finally FavMusicResponse entity. what should I do to make it work like that? This is my minimal reproduce that could run in rust playground to figure out where is going wrong:
fn main() {
let music = Music{
id: 1
};
let favMusic = Favorites{
id: 1
};
let musicRes = FavMusicResponse::from(favMusic,music);
}
pub struct Music {
pub id: i64
}
pub struct Favorites {
pub id: i64
}
pub struct FavMusicResponse {
pub id: i64,
pub music:Music
}
impl From<Favorites> for FavMusicResponse {
fn from(f: Favorites, music: Music) -> Self {
Self{
id: f.id,
music: music
}
}
}
From trait can't take two parameters only one, it's define that way, the only solution if you really want to use From trait is to transform your two parameter into one, a quick solution is to use a tuple:
impl From<(Favorites, Music)> for FavMusicResponse {
fn from((f, music): (Favorites, Music)) -> Self {
Self {
id: f.id,
music,
}
}
}
// let musicRes = FavMusicResponse::from((favMusic, music));
That said you could also just have a new() method on your type:
impl FavMusicResponse {
fn new(f: Favorites, music: Music) -> Self {
Self {
id: f.id,
music,
}
}
}
// let musicRes = FavMusicResponse::new(favMusic, music);

is it possible to get pagination info from rust pagination query result

I am using rust diesel to do a pagination query right now. I get the pagination information from request right now, I was wonder is it possible to get pagination information from Query result? This is my code:
pub fn fav_music_query<T>(request: Json<FavMusicRequest>) -> Paginated<Vec<Favorites>> {
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*;
let connection = config::establish_music_connection();
let query = favorites.filter(like_status.eq(1)).paginate(request.pageNum).per_page(request.pageSize);
let query_result = query.load_and_count_pages::<Favorites>(&connection).unwrap();
let page_result = Paginated{
query: query_result.0,
page: request.pageNum,
per_page: request.pageSize,
is_sub_query: false
};
return page_result;
}
from the request I could only get pageSize and pageNum, but I did not know the total size. what is the best way the get the pagination information? this is my pagination code:
use diesel::prelude::*;
use diesel::query_dsl::methods::LoadQuery;
use diesel::query_builder::{QueryFragment, Query, AstPass};
use diesel::pg::Pg;
use diesel::sql_types::BigInt;
use diesel::QueryId;
use serde::{Serialize, Deserialize};
pub trait PaginateForQueryFragment: Sized {
fn paginate(self, page: i64) -> Paginated<Self>;
}
impl<T> PaginateForQueryFragment for T
where T: QueryFragment<Pg>{
fn paginate(self, page: i64) -> Paginated<Self> {
Paginated {
query: self,
per_page: 10,
page,
is_sub_query: true,
}
}
}
#[derive(Debug, Clone, Copy, QueryId, Serialize, Deserialize, Default)]
pub struct Paginated<T> {
pub query: T,
pub page: i64,
pub per_page: i64,
pub is_sub_query: bool
}
impl<T> Paginated<T> {
pub fn per_page(self, per_page: i64) -> Self {
Paginated { per_page, ..self }
}
pub fn load_and_count_pages<U>(self, conn: &PgConnection) -> QueryResult<(Vec<U>, i64)>
where
Self: LoadQuery<PgConnection, (U, i64)>,
{
let per_page = self.per_page;
let results = self.load::<(U, i64)>(conn)?;
let total = results.get(0).map(|x| x.1).unwrap_or(0);
let records = results.into_iter().map(|x| x.0).collect();
let total_pages = (total as f64 / per_page as f64).ceil() as i64;
Ok((records, total_pages))
}
}
impl<T: Query> Query for Paginated<T> {
type SqlType = (T::SqlType, BigInt);
}
impl<T> RunQueryDsl<PgConnection> for Paginated<T> {}
impl<T> QueryFragment<Pg> for Paginated<T>
where
T: QueryFragment<Pg>,
{
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
out.push_sql("SELECT *, COUNT(*) OVER () FROM ");
if self.is_sub_query {
out.push_sql("(");
}
self.query.walk_ast(out.reborrow())?;
if self.is_sub_query {
out.push_sql(")");
}
out.push_sql(" t LIMIT ");
out.push_bind_param::<BigInt, _>(&self.per_page)?;
out.push_sql(" OFFSET ");
let offset = (self.page - 1) * self.per_page;
out.push_bind_param::<BigInt, _>(&offset)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, QueryId)]
pub struct QuerySourceToQueryFragment<T> {
query_source: T,
}
impl<FC, T> QueryFragment<Pg> for QuerySourceToQueryFragment<T>
where
FC: QueryFragment<Pg>,
T: QuerySource<FromClause=FC>,
{
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
self.query_source.from_clause().walk_ast(out.reborrow())?;
Ok(())
}
}
pub trait PaginateForQuerySource: Sized {
fn paginate(self, page: i64) -> Paginated<QuerySourceToQueryFragment<Self>>;
}
impl<T> PaginateForQuerySource for T
where T: QuerySource {
fn paginate(self, page: i64) -> Paginated<QuerySourceToQueryFragment<Self>> {
Paginated {
query: QuerySourceToQueryFragment {query_source: self},
per_page: 10,
page,
is_sub_query: false,
}
}
}
and this is my FavMusicRequest that define the pagination query information:
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[allow(non_snake_case)]
pub struct FavMusicRequest {
pub userId: i64,
pub pageNum: i64,
pub pageSize: i64
}
and this is the query entity from database:
#[derive( Serialize, Queryable, Deserialize,Default)]
pub struct Favorites {
pub id: i64,
pub song_id: Option<i64>,
pub created_time: i64,
pub updated_time: i64,
pub user_id: i64,
pub source_id: String,
pub like_status: i32,
pub source: i32,
pub playlist_id: i64,
pub play_count: i32,
pub fetched_download_url: Option<i32>,
pub downloaded: Option<i32>
}
and this is the request defined with rocket:
#[post("/v1/page",data = "<request>")]
pub fn page(request: Json<FavMusicRequest>) -> content::Json<String> {
let fav_musics = fav_music_query::<Vec<Favorites>>(request);
let res = ApiResponse {
result: fav_musics,
..Default::default()
};
let response_json = serde_json::to_string(&res).unwrap();
return content::Json(response_json);
}
You can return the results in QueryResult<(....)> in the load_and_count_pages.
Here is a working example:
use diesel::pg::Pg;
use diesel::prelude::*;
use diesel::query_builder::*;
use diesel::query_dsl::methods::LoadQuery;
use diesel::sql_types::BigInt;
pub trait Paginate: Sized {
fn paginate(self, page: i64) -> Paginated<Self>;
}
impl<T> Paginate for T {
fn paginate(self, page: i64) -> Paginated<Self> {
Paginated {
query: self,
per_page: DEFAULT_PER_PAGE,
page,
}
}
}
const DEFAULT_PER_PAGE: i64 = 100;
#[derive(Debug, Clone, Copy, QueryId)]
pub struct Paginated<T> {
query: T,
page: i64,
per_page: i64,
}
impl<T> Paginated<T> {
pub fn per_page(self, per_page: i64) -> Self {
Paginated { per_page, ..self }
}
pub fn load_and_count_pages<U>(self, conn: &PgConnection) -> QueryResult<(Vec<U>, i64)>
where
Self: LoadQuery<PgConnection, (U, i64)>,
{
let _per_page = self.per_page;
let results = self.load::<(U, i64)>(conn)?;
let total = results.get(0).map(|x| x.1).unwrap_or(0);
let records = results.into_iter().map(|x| x.0).collect();
Ok((records, total))
}
}
impl<T: Query> Query for Paginated<T> {
type SqlType = (T::SqlType, BigInt);
}
impl<T> RunQueryDsl<PgConnection> for Paginated<T> {}
impl<T> QueryFragment<Pg> for Paginated<T>
where
T: QueryFragment<Pg>,
{
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
out.push_sql("SELECT *, COUNT(*) OVER () FROM (");
self.query.walk_ast(out.reborrow())?;
out.push_sql(") t LIMIT ");
out.push_bind_param::<BigInt, _>(&self.per_page)?;
out.push_sql(" OFFSET ");
let offset = (self.page - 1) * self.per_page;
out.push_bind_param::<BigInt, _>(&offset)?;
Ok(())
}
}
Then you can define a pagination handler.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Cursor {
pub total_pages: i32,
pub filters: Vec<String>,
}
#[derive(Serialize)]
pub struct PaginationResult<T>
where
T: Serialize,
{
pub records: Vec<T>,
pub cursor: Cursor,
}
Then you can now do:
pub fn fav_music_query<T>(request: Json<FavMusicRequest>) -> PaginationResult<Vec<Favorites>> {
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*;
let connection = config::establish_music_connection();
let query = favorites
.filter(like_status.eq(1))
.paginate(request.pageNum)
.per_page(request.pageSize);
let (favorites, pages) = query
.load_and_count_pages::<Favorites>(&connection)
.unwrap();
return PaginationResult {
records: favorites,
cursor: Cursor {
total_pages: pages as i32,
filters: vec![],
},
};
}
My example just gets the total number of pages. You can add more all you need.

Simplest way to match multiple fields of a struct against `None`

I have a Rust struct like this:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>
}
What is the simplest way to check if all optional ids are not set? I know the syntax like
if let Some(x) = option_value {...}
to extract a value from an Option, but I don't get how to use this in a concise way to check multiple values for None.
You can destructure a structure in pattern matching like so:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>,
}
fn main() {
let x = SomeMapping {
id: "R".to_string(),
other_id: Some("u".to_string()),
yet_another_id: Some("s".to_string()),
very_different_id: Some("t".to_string()),
};
if let SomeMapping {
id: a,
other_id: Some(b),
yet_another_id: Some(c),
very_different_id: Some(d),
} = x {
println!("{} {} {} {}", a, b, c, d);
}
}
It is documented in the Rust book chapter 18.

Use trait as interface for database entity

I am trying to make an Entity interface for dynamically mapping a database result into a Rust struct:
pub trait Entity {
fn map(&self, Result<QueryResult>) -> Self;
}
pub struct DbQuery<T> {
pub sql: String,
pub params: Vec<Value>,
pub limit: i32,
pub paged: Option<Pagination>,
pub entity: T,
}
pub struct Settings {
pub name: String,
pub value: Option<String>,
}
impl Entity for Settings {
fn map(&self, result: Result<QueryResult>) -> Settings {
// ...
Settings {
name: "hello".to_string(),
value: None,
}
}
}
impl DbMapper {
// ...
pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>> {
println!("query find SQL: {}", query.sql);
let mut stmt = &self.pool.prepare(query.sql).unwrap();
let ret = Vec::new();
for row in stmt.execute(query.params).unwrap() {
ret.push(query.entity.map(row.unwrap()));
}
Some(ret)
}
}
But I get an error:
error: no method named map found for type T in the current scope
ret.push(query.entity.map(row.unwrap())); |
note: the method map exists but the following trait
bounds were not satisfied: T : std::iter::Iterator = help: items
from traits can only be used if the trait is implemented and in scope;
the following traits define an item map, perhaps you need to
implement one of them: = help: candidate #1:
models::holders::database::Entity = help: candidate #2:
std::iter::Iterator
Here is a version of your code that runs on the playground and replicates your issue:
pub struct QueryResult;
pub struct Value;
pub struct Pagination;
pub struct DbMapper;
pub trait Entity {
fn map(&self, Result<QueryResult, ()>) -> Self;
}
pub struct DbQuery<T> {
pub sql: String,
pub params: Vec<Value>,
pub limit: i32,
pub paged: Option<Pagination>,
pub entity: T,
}
pub struct Settings {
pub name: String,
pub value: Option<String>,
}
impl Entity for Settings {
fn map(&self, result: Result<QueryResult, ()>) -> Settings {
// ...
Settings {
name: "hello".to_string(),
value: None,
}
}
}
impl DbMapper {
// ...
pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>> {
println!("query find SQL: {}", query.sql);
// ########## attempt to call map()
let _ = query.entity.map(Ok(QueryResult {}));
let ret = Vec::new();
Some(ret)
}
}
fn main() {}
The problem is that T in the DbQuery<T> argument in the find method has no idea that T is an Entity type. So we need to tell it:
pub fn find<T>(&self, query: DbQuery<T>) -> Option<Vec<T>>
where T: Entity
{
// ... code here ...
}
This now compiles and runs.
The compiler now knows that T is an Entity of some description, and it can call the map method on it.

Syntax of Rust lifetime specifier

I need help understanding lifetime specifiers. I think I get the concept of lifetimes. I watched Memory, Ownership and Lifetimes. I just think if I could work through this small example it might help me with the syntax of lifetimes. A topic I, to date, find confusing.
use std::collections::HashMap;
fn main() {
pub struct User<'a> {
pub name: & 'a str
}
impl <'a>User<'a> {
pub fn new(uname: & 'a str, pwd: & 'a str) -> User {
User{name: uname}
}
}
pub struct ChatRoom<'a> {
pub name: & 'a str,
pub users: HashMap<& 'a str, User>
}
impl <'a>ChatRoom<'a> {
pub fn new(name: &str) -> ChatRoom {
let users = HashMap::new();
ChatRoom {name: name, users: users}
}
pub fn join(&mut self, user: User) {
self.users.insert(user.name, user);
}
}
let mut room = ChatRoom::new("Test");
let user = User::new("bender","123");
room.join(user);
}
I'm not sure what your exact question is, so I imagine you wanted that code to compile. Check this playground.
Notice that lifetime parameters are part of the type, so you want User<'a> not just User.
use std::collections::HashMap;
fn main() {
struct User<'a> {
name: &'a str,
}
impl<'a> User<'a> {
fn new(uname: &'a str, pwd: &'a str) -> User<'a> {
User { name: uname }
}
}
struct ChatRoom<'a> {
name: &'a str,
users: HashMap<&'a str, User<'a>>,
}
impl<'a> ChatRoom<'a> {
fn new(name: &str) -> ChatRoom {
let users = HashMap::new();
ChatRoom {
name: name,
users: users,
}
}
fn join(&mut self, user: User<'a>) {
self.users.insert(user.name, user);
}
}
let mut room = ChatRoom::new("Test");
let user = User::new("bender", "123");
room.join(user);
}

Resources