How can i implement `std::iter::FromIterator<_>' for Struct? - rust

When I try to make the one to many relational query for graph with diesel vie mysql, querying enum fails with fromIterator.
helps show i need to implement `std::iter::FromIterator<_> but I don't know how exactly implement the struct.
Any helps ?
thanks in advance!
error log
error[E0277]: a value of type `&std::vec::Vec<graphql::ContactContent>` cannot be built from an iterator over elements of type `_`
--> src/graphql.rs:129:89
|
129 | .and_then(|contact_contents| Ok(contact_contents.into_iter().map_into().collect()))
| ^^^^^^^ value of type `&std::vec::Vec<graphql::ContactContent>` cannot be built from `std::iter::Iterator<Item=_>`
|
= help: the trait `std::iter::FromIterator<_>` is not implemented for `&std::vec::Vec<graphql::ContactContent>`
cargo.toml
[package]
name = "lead_generation_api"
version = "0.1.0"
authors = ["ARBOR.JP"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
diesel = { version = "1.4.5", features = ["mysql", "r2d2", "chrono"] }
dotenv = "~0.15"
serde = "~1.0"
serde_derive = "~1.0"
serde_json = "~1.0"
chrono = "~0.4"
rand = "0.7.3"
actix-web = "1.0.9"
actix-cors = "0.1.0"
juniper = "0.14.1"
juniper-from-schema = "0.5.1"
juniper-eager-loading = "0.5.0"
r2d2_mysql = "*"
r2d2-diesel = "0.16.0"
mysql = "*"
r2d2 = "*"
futures01 = "0.1.29"
itertools = "0.8.2"
[[bin]]
name = "main"
path = "src/main.rs"
src/graphql.rs
use std::convert::From;
use std::sync::Arc;
use chrono::NaiveDateTime;
use actix_web::{web, Error, HttpResponse};
use futures01::future::Future;
use juniper::http::playground::playground_source;
use juniper::{http::GraphQLRequest,GraphQLObject, Executor, FieldResult, FieldError,ID};
use juniper_from_schema::graphql_schema_from_file;
use diesel::prelude::*;
use itertools::Itertools;
use crate::schema::{customers, contact_contents};
use crate::{DbCon, DbPool};
graphql_schema_from_file!("src/schema.graphql");
pub struct Context {
db_con: DbCon,
}
impl juniper::Context for Context {}
pub struct Query;
pub struct Mutation;
impl QueryFields for Query {
fn field_customers(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
) -> FieldResult<Vec<Customer>> {
//type FieldResult<T> = Result<T, String>;
customers::table
.load::<crate::models::Customer>(&executor.context().db_con)
.and_then(|customers| Ok(customers.into_iter().map_into().collect()))
.map_err(Into::into)
}
}
impl MutationFields for Mutation {
fn field_create_customer(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, Customer, Walked>,
name: String,
email: String,
contact_contents: Vec<String>,
) -> FieldResult<Customer> {
//type FieldResult<T> = Result<T, String>;
let new_customer = crate::models::NewCustomer { name: name, email: email};
diesel::insert_into(customers::table)
.values(&new_customer)
.execute(&executor.context().db_con);
customers::table
.first::<crate::graphql::Customer>(&executor.context().db_con)
.map_err(Into::into)
}
}
//#[derive(GraphQLObject)]
//#[graphql_object(name="customer name", email ="mail address")]
#[derive(Queryable)]
pub struct Customer {
id: u64,
name: String,
email: String,
created_at: NaiveDateTime,
updated_at: NaiveDateTime,
}
#[derive(Queryable)]
pub struct ContactContent {
id: u64,
customer_id: u64,
email: String,
}
impl ContactContentFields for ContactContent {
fn field_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.id.to_string()))
}
fn field_customer_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.customer_id.to_string()))
}
fn field_email(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.email)
}
}
impl From<crate::models::ContactContent> for ContactContent {
fn from(contact_contents: crate::models::ContactContent) -> Self {
Self {
id: contact_contents.id,
customer_id: contact_contents.customer_id,
email: contact_contents.email,
}
}
}
//#[juniper::object(Context = Context)]
//#[graphql(description = "A Photo returns struct")]
impl CustomerFields for Customer {
fn field_id(&self, _: &Executor<'_, Context>) -> FieldResult<juniper::ID> {
Ok(juniper::ID::new(self.id.to_string()))
}
fn field_name(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.name)
}
fn field_email(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
Ok(&self.email)
}
fn field_contact_contents(
&self,
executor: &Executor<'_, Context>,
_trail: &QueryTrail<'_, ContactContent, Walked>,
) -> FieldResult<&Vec<ContactContent>> {
contact_contents::table
.filter(contact_contents::customer_id.eq(&self.id))
.load::<crate::models::ContactContent>(&executor.context().db_con)
.and_then(|contact_contents| Ok(contact_contents.into_iter().map_into().collect()))
.map_err(Into::into)
}
}
impl From<crate::models::Customer> for Customer {
fn from(customer: crate::models::Customer) -> Self {
Self {
id: customer.id,
name: customer.name,
email: customer.email,
created_at: customer.created_at,
updated_at: customer.updated_at,
}
}
}
fn playground() -> HttpResponse {
let html = playground_source("");
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html)
}
fn graphql(
schema: web::Data<Arc<Schema>>,
data: web::Json<GraphQLRequest>,
db_pool: web::Data<DbPool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
let ctx = Context {
db_con: db_pool.get().unwrap(),
};
web::block(move || {
let res = data.execute(&schema, &ctx);
Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?)
})
.map_err(Error::from)
.and_then(|customer| {
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(customer))
})
}
pub fn register(config: &mut web::ServiceConfig) {
let schema = std::sync::Arc::new(Schema::new(Query, Mutation));
config
.data(schema)
.route("/", web::post().to_async(graphql))
.route("/", web::get().to(playground));
}
src/schema.rs
table! {
contact_contents (id) {
id -> Unsigned<Bigint>,
customer_id -> Unsigned<Bigint>,
email -> Varchar,
}
}
table! {
customers (id) {
id -> Unsigned<Bigint>,
name -> Varchar,
email -> Varchar,
created_at -> Timestamp,
updated_at -> Timestamp,
}
}
src/schema.graphql
schema {
query: Query
mutation: Mutation
}
type Query {
customers: [Customer!]! #juniper(ownership: "owned")
}
type Mutation {
createCustomer(
name: String!
email: String!
contactContents: [String!]!
): Customer! #juniper(ownership: "owned")
}
type Customer {
id: ID! #juniper(ownership: "owned")
name: String!
email: String!
contactContents: [ContactContent!]!
}
type ContactContent {
id: ID! #juniper(ownership: "owned")
customerId: ID! #juniper(ownership: "owned")
email: String!
}
src/models.rs
use chrono::NaiveDateTime;
pub struct Query;
pub struct Mutation;
#[derive(Queryable, Identifiable, AsChangeset, Clone, PartialEq, Debug)]
pub struct Customer {
pub id: u64,
pub name: String,
pub email: String,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
}
use super::schema::customers;
#[derive(Queryable,Insertable, AsChangeset)]
#[table_name="customers"]
pub struct NewCustomer {
pub name: String,
pub email: String,
}
use super::schema::contact_contents;
#[derive(Queryable,Identifiable)]
#[table_name="contact_contents"]
pub struct ContactContent {
pub id: u64,
pub customer_id: u64,
pub email: String,
}
src/main.rs
#[macro_use]
extern crate diesel;
extern crate r2d2;
use actix_cors::Cors;
use actix_web::{web, App, HttpServer};
use diesel::{
prelude::*,
};
use diesel::r2d2::ConnectionManager;
pub mod graphql;
pub mod models;
pub mod schema;
pub type DbPool = r2d2::Pool<ConnectionManager<MysqlConnection>>;
pub type DbCon = r2d2::PooledConnection<ConnectionManager<MysqlConnection>>;
fn main() {
let db_pool = create_db_pool();
let port: u16 = std::env::var("PORT")
.ok()
.and_then(|p| p.parse().ok())
.unwrap_or(8080);
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));
HttpServer::new(move || {
App::new()
.data(db_pool.clone())
.wrap(Cors::new())
.configure(graphql::register)
.default_service(web::to(|| "404"))
})
.bind(addr)
.unwrap()
.run()
.unwrap();
}
pub fn create_db_pool() -> DbPool {
let manager = ConnectionManager::<MysqlConnection>::new("mysql://root:example#mysql/test");
r2d2::Pool::new(manager).expect("Failed to create DB Pool")
}

There's nothing to implement, the issue here is that the typing of field_contact_contents is not correct: &Vec<ContactContent> would mean that it returns a member of one of its parameters somehow.
Since you're not borrowing the vec from somewhere but creating it from whole cloth inside the method, that makes no sense, the method should return a proper Vec.
Here's a trivial reproduction case: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8f0b6341f7ffd72fe8de334a098295a1

Related

Recursive structures - cant move reference

Having an issue understanding how to handle recursive objects.
I am trying to model a price book / order book structure in rust.
Here is what I am trying to do.
struct Price {
price: u64,
side: Side,
asset_type: String,
}
struct PriceLv {
current_level: Price,
next_price_level: Option<Box<Price>>,
running_orders: LinkedList<(Qty, OrderId)>,
}
#[derive(Clone)]
pub struct OrderEntry {
pub asset: Asset,
pub price: u64,
pub side: Side,
pub user: UserId,
pub order_id: OrderId,
pub qty: u64,
}
#[derive(Clone)]
pub struct Asset {
pub name: String,
pub qty: u64,
}
impl Asset {
pub fn to_string(&self) -> String {
name.to_owned()
}
}
For sure there is more issues besides that. But when I try to add a new level I am having trouble accomplishing that.
impl PriceLv {
pub fn new(price: u64, side: Side, asset_type: Asset) -> PriceLv {
PriceLv {
current_level: Price {
price,
side,
asset_type: asset_type.to_string(),
},
next_price_level: None,
running_orders: LinkedList::new(),
}
}
pub fn add_new_order(&mut self, order_entry: &OrderEntry) {
if self.price == order_entry.price {
self.running_orders.insert((order_entry.order_id, order_entry.order_id));
}
Self::update_price_level(self, &order_entry);
}
fn update_price_level(price_level: &mut PriceLv, order_entry: &OrderEntry) -> String {
loop {
if price_level.price == order_entry.price {
price_level.current_level =
price_level.running_orders.insert((order_entry.order_id, order_entry));
return "OK".to_owned();
}
match &price_level.next_price_level {
None => {
&price_level.next_price_level = &Some(
Box::new( Price {
price: order_entry.price,
side: order_entry.side,
asset_type: order_entry.asset_type.to_string(),
})
)
}
Some(level) => {
let &tmp = Box::new( Price {
price: order_entry.price,
side: order_entry.side,
asset_type: order_entry.asset_type.to_string(),
});
*price_level.current_level = *level.as_ref();
}
}
}
}
}
How can I set current level to be the next level to continue iterate over the structure to find where to add the next level.
I suspect something to do with mem::replace / mem::swap

What is the error "field `id` of struct `Todo` is private"? [duplicate]

This question already has answers here:
field of struct is private when importing module
(2 answers)
Closed 3 months ago.
I want to put a value in the structure, but I get an error because it is private. How do I resolve it?
I have it set to pub, but I get this error.
use actix_web::{get, post, web, HttpResponse,Responder};
use crate::app::model::todo::Todo;
#[get("/todos/{id}")]
async fn get_todo(id: web::Path<u32>) -> impl Responder {
let id_option: Option<u32> = Some(id.into_inner());
HttpResponse::Ok().json(Todo {
id: id_option,
content: String::from("やること"),
completed: false,
})
}
#[post("/todos")]
async fn post_todo(todo: web::Json<Todo>) -> impl Responder {
println!("post_todo");
println!("{:?}", todo);
HttpResponse::Ok().body("ok")
}
pub struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
Your struct and were is being used are not part of the same module, so declaring the struct pub won't be enough, you have to grant visibility to the fields.
This program would compile fine:
struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
fn main() {
let t = Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
but this wouldn't:
mod todo {
struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
}
fn main() {
let t = todo::Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
if you add pub to the struct but not to the fields, the struct is now visible from your main, but not its contents. If you add pub to the fields, you can create the struct from main, as well as access its fields:
mod todo {
pub struct Todo {
pub id: Option<u32>,
pub content: String,
pub completed: bool,
}
}
fn main() {
let t = todo::Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
};
println!("{}", t.content);
}
If you make only the struct pub, but not the fields, this would allow you to see and use the structure from main, while protecting its fields from direct access:
mod todo {
pub struct Todo {
id: Option<u32>,
content: String,
completed: bool,
}
impl Todo {
pub fn new() -> Self {
Todo {
id: Some(1),
content: String::from("やること"),
completed: false,
}
}
pub fn content(&self) -> String {
self.content.to_owned()
}
}
}
fn main() {
let t = todo::Todo::new();
println!("{}", t.content());
}
If you tried to create a struct directly from main as in Todo {.....} instead of using new(), you would get an error. if you tried to print t.content instead of using the content() function, you would get an error.

Why does variable need to continue living after output is consumed?

use std::cell::RefCell;
use std::collections::VecDeque;
// minimum reproducible example for stack overflow question
// which is essentially the whole thing b/c all of these types
// depend on each other
// this is an implementation of Monopoly Deal (see http://monopolydealrules.com/)
// but the only relevant part to the question is in main(), around line 400
// card.rs
pub trait Card {
fn value(&self) -> i32;
fn kind(&self) -> CardKind;
}
pub enum CardKind {
Money,
Action,
Property,
Building,
}
// property.rs
pub struct PropertySet {
color: Color,
properties: Vec<Property>,
house: bool,
hotel: bool,
}
impl PropertySet {
pub fn rent(&self) -> i32 {
unimplemented!() // stub
}
pub fn color(&self) -> Color {
self.color
}
pub fn properties(&self) -> &Vec<Property> {
&self.properties
}
pub fn is_full(&self) -> bool {
self.properties().len() == self.color.set_size() as usize
}
pub fn is_empty(&self) -> bool {
self.properties().len() == 0
}
pub fn add(&mut self, property: Property) -> Result<(), PropertySetAddError> {
if !property.matches(self.color) {
return Err(PropertySetAddError {
property,
kind: PropertySetAddErrorKind::WrongColor,
});
}
if self.properties.len() + 1 < self.color.set_size() as usize {
self.properties.push(property);
Ok(())
} else {
Err(PropertySetAddError {
property,
kind: PropertySetAddErrorKind::SetFull,
})
}
}
fn remove(&mut self, index: usize) -> Property {
self.properties.remove(index)
}
}
pub struct PropertySetAddError {
property: Property,
kind: PropertySetAddErrorKind,
}
pub enum PropertySetAddErrorKind {
WrongColor,
SetFull,
}
pub enum Property {
Basic { name: String, color: Color },
Wild { colors: [Color; 2], value: i32 },
Any,
}
impl Card for Property {
fn value(&self) -> i32 {
unimplemented!() // stub
}
fn kind(&self) -> CardKind {
CardKind::Property
}
}
impl Property {
pub fn matches(&self, color: Color) -> bool {
unimplemented!() // stub
}
}
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
pub enum Color {
Red,
Orange,
Yellow,
Green,
LightBlue,
DarkBlue,
Magenta,
Brown,
Utility,
Railroad,
}
impl Color {
pub fn set_size(&self) -> i32 {
unimplemented!() // stub
}
}
// money.rs
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Money(pub i32);
impl Card for Money {
fn value(&self) -> i32 {
self.0
}
fn kind(&self) -> CardKind {
CardKind::Money
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Id(pub usize);
pub struct Possessions {
bank: Vec<Money>,
hand: Vec<Box<dyn Card>>,
properties: Vec<PropertySet>,
}
// brain.rs
pub trait Brain {
fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect>;
fn react(
&self,
state: &GameState,
possessions: &mut Possessions,
effect: &Effect,
) -> Vec<Effect>;
}
pub struct Human {}
impl Human {
pub fn new() -> Human {
Human {}
}
}
impl Brain for Human {
fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect> {
unimplemented!()
}
fn react(
&self,
state: &GameState,
possessions: &mut Possessions,
effect: &Effect,
) -> Vec<Effect> {
unimplemented!()
}
}
// action.rs
pub enum Action {
Rent { colors: [Color; 2] },
AnyRent,
DoubleRent,
DealBreaker,
DebtCollector,
Birthday,
SayNo,
PassGo,
SlyDeal,
ForcedDeal,
}
impl Card for Action {
fn value(&self) -> i32 {
unimplemented!() // stub
}
fn kind(&self) -> CardKind {
CardKind::Action
}
}
impl Action {
pub fn effect<'a>(
&self,
source: Id,
target: ActionTarget<'a>,
) -> Result<Effect<'a>, EffectError> {
unimplemented!() // stub
}
}
pub enum ActionTarget<'a> {
None,
Player {
player: Id,
},
Set {
/// The player that this action is targeted against
player: Id,
/// Can be a set that player owns, such as in the case of Deal Breaker, or it
/// can be a set that the source owns, such as in the case of rent cards
set: &'a PropertySet,
},
Property {
player: Id,
property: (&'a PropertySet, usize),
},
Swap {
player: Id,
take: (&'a PropertySet, usize),
give: (&'a PropertySet, usize),
},
}
// effect.rs
#[derive(Clone)]
pub enum Effect<'a> {
// swaps properties with another player
Swap {
source: Id,
target: Id,
give: (&'a PropertySet, usize),
take: (&'a PropertySet, usize),
},
// steals properties from another player
Steal {
source: Id,
target: Id,
set: &'a PropertySet,
indices: Vec<usize>,
},
// charges another player
Charge {
source: Id,
target: Option<Id>,
amount: i32,
reason: ChargeReason,
},
// cancels prior effect
Cancel {
source: Id,
target: Id,
},
// pass Go, credit $2M
Go {
source: Id,
},
}
#[derive(Clone)]
pub enum ChargeReason {
Rent,
Birthday,
DebtCollector,
}
pub enum EffectError {
/// The target supplied was not valid for this action.
InvalidTarget,
/// You tried to charge rent for a color, but the specified set isn't that color
NoProperty,
}
// player.rs
pub struct Player {
pub id: Id,
pub name: String,
pub possessions: Possessions,
pub brain: Box<dyn Brain>,
}
impl Player {
pub fn new(id: Id, name: String, brain: Box<dyn Brain>) -> Player {
Player {
id,
possessions: Possessions {
bank: vec![],
hand: vec![],
properties: vec![],
},
name,
brain,
}
}
pub fn id(&self) -> Id {
self.id
}
pub fn bank(&self) -> &Vec<Money> {
&self.possessions.bank
}
pub fn properties(&self) -> &Vec<PropertySet> {
&self.possessions.properties
}
pub fn name(&self) -> &str {
&self.name
}
pub fn brain(&self) -> &Box<dyn Brain> {
&self.brain
}
pub fn act(&mut self, state: &GameState) -> Vec<Effect> {
self.brain.act(state, &mut self.possessions)
}
pub fn react(&mut self, state: &GameState, effect: &Effect) -> Vec<Effect> {
self.brain.react(state, &mut self.possessions, effect)
}
}
// state.rs
pub struct GameState {
pub players: Vec<RefCell<Player>>,
pub current: Id,
pub stack: Vec<Box<dyn Card>>,
}
impl GameState {
pub fn next(&mut self) {
self.current = Id((self.current.0 + 1) % self.players.len())
}
pub fn current_player(&self) -> &RefCell<Player> {
self.players.get(self.current.0).unwrap()
}
pub fn get_player(&self, id: Id) -> Option<&RefCell<Player>> {
self.players.get(id.0)
}
}
// deck.rs
pub fn create_deck() -> Vec<Box<dyn Card>> {
vec![
// ...
]
}
// main.rs
pub fn main() {
let brain = Human::new(); // Human implements Brain
let me = Player::new(Id(0), "Ibi".to_owned(), Box::new(brain));
let current = me.id();
let players = vec![RefCell::new(me)];
let stack = create_deck(); // returns Vec<Box<dyn Card>>
let mut state = GameState {
players,
stack,
current,
};
while !state.players.iter().any(|player| {
player
.borrow()
.properties()
.iter()
.filter(|&set| set.is_full())
.count()
>= 3
}) {
// ...
let mut effects = VecDeque::new();
{
let mut current_player = state.current_player().borrow_mut();
let action = current_player.act(&state);
effects.extend(action);
}
// let all other players react to effects until no more reactions are generated
while !effects.is_empty() {
let effect = effects.pop_front().unwrap();
// ...
}
}
}
I can't get this code to compile; it says that current_player does not live long enough and complains that it is dropped at the end of the block. Why does current_player need to survive beyond the end of the block? My understanding is that it returns a Vec<Effect> which my method now owns, and then that vector is consumed by extend() and the values it contained are now owned by effects, so why is current_player still necessary?

Most "rusty" way to wrap Rustson responses and avoid duplicated traits?

I'm learning Rust, but I'm not sure about the most elegant or "rusty" way of doing some things:
I'm retrieving data from an API that, on some endpoints returns a JSON object ({ value: "resource A" }), but in other occasions, it returns a JSON object wrapped by another object ({ error: false, data: { value: "resource A" } }).
I'm using Restson to retrieve that data.
My question is: what is the most elegant way to deal with different responses? I don't know how to use some kind of abstract Response that could accept both kind of JSON responses.
I mean, in this case I'm implementing 2 traits, but both of them have the same content, so, to me, it smells like there is something wrong there.
This is a simplified example, so typos could exist:
use restson::{RestPath, RestClient, Error};
#[derive(Debug, Serialize, Deserialize)]
struct Response<T> {
error: bool,
data: T
}
#[derive(Debug, Serialize, Deserialize)]
struct ResourceA {
value: String,
}
// HERE: How do I remove this duplication?
impl<'a> RestPath<(&'a str, String)> for ResourceA {
fn get_path(params: (i8, String, &str)) -> Result<String, Error> {
let (resource, id) = params;
Ok(format!("{}/{}", resource, id))
}
}
impl<'a, T> RestPath<(&'a str, String)> for Response<T> {
fn get_path(params: (&str, String)) -> Result<String, Error> {
let (resource, id) = params;
Ok(format!("{}/{}", resource, id))
}
}
pub struct Client {
client: RestClient,
}
impl Client {
pub fn new() -> Client {
Client {
client: RestClient::new("http://my.client").unwrap(),
}
}
pub fn get_resource_a(&mut self, id: String) -> ResourceA {
let params = ("a", id);
self.client.get(params).unwrap()
}
pub fn get_resource_a2(&mut self, id: String) -> ResourceA {
let params = ("a2", id);
let response: Response<ResourceA> = self.api_client.get(params).unwrap();
response.data
}
}
You have a response with two variants, so an enum based solution may be considered:
#[derive(Debug, Serialize, Deserialize)]
struct ResourceA {
value: String,
}
#[derive(Debug, Serialize, Deserialize]
#[serde(untagged)]
pub enum Response {
ErrAndValue{error: bool, data: ResourceA},
Simple(ResourceA),
}
I've used the untagged annotation to conform the json format:
{ value: "resource A" }
{ error: false, data: { value: "resource A" } }
Then your RestPath impl reduce to:
impl<'a> RestPath<(&'a str, String)> for Response {
fn get_path(params: (&str, String)) -> Result<String, Error> {
let (resource, id) = params;
Ok(format!("{}/{}", resource, id))
}
}

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.

Resources