How to handle errors when extracting data from untyped JSON in serde_json? - json

I have a serde_json::Value which I expect to contain an array of objects. From those objects I want to extract 2 values and return an error if anything fails. This is my code so far:
use std::collections::HashMap;
use anyhow::Result;
fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>>{
response["products"]
.as_array()?.iter()
.map(|product| {
let product = product.as_object()?;
(
product["name"].as_str()?.to_owned(),
//as_u64 fails for some reason
product["stock"].as_str()?.parse::<u32>()?,
)
})
.collect()?
}
When I used .unwrap() this worked fine, but after changing the return type to Result and replacing unwraps with ? I'm getting the following compilation errors:
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> src/bin/products.rs:7:20
|
5 | / fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>>{
6 | | response["products"]
7 | | .as_array()?.iter()
| | ^ use `.ok_or(...)?` to provide an error compatible with `Result<HashMap<std::string::String, u32>, anyhow::Error>`
8 | | .map(|product| {
... |
16 | | .collect()?
17 | | }
| |_- this function returns a `Result`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<HashMap<std::string::String, u32>, anyhow::Error>`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:9:46
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
10 | | (
11 | | product["name"].as_str()?.to_owned(),
... |
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:11:41
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
... |
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:13:42
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
12 | | //as_u64 fails for some reason
13 | | product["stock"].as_str()?.parse::<u32>()?,
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:13:58
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
12 | | //as_u64 fails for some reason
13 | | product["stock"].as_str()?.parse::<u32>()?,
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
miav#battlestation catbot % cargo run --bin products
Compiling catbot v0.1.0 (/Users/miav/Documents/Personal/Projects/programming/catbot)
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> src/bin/products.rs:7:20
|
5 | / fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>>{
6 | | response["products"]
7 | | .as_array()?.iter()
| | ^ use `.ok_or(...)?` to provide an error compatible with `Result<HashMap<std::string::String, u32>, anyhow::Error>`
8 | | .map(|product| {
... |
16 | | .collect()?
17 | | }
| |_- this function returns a `Result`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<HashMap<std::string::String, u32>, anyhow::Error>`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:9:46
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
10 | | (
11 | | product["name"].as_str()?.to_owned(),
... |
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:11:41
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
... |
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:13:42
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
12 | | //as_u64 fails for some reason
13 | | product["stock"].as_str()?.parse::<u32>()?,
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/bin/products.rs:13:58
|
8 | .map(|product| {
| ______________-
9 | | let product = product.as_object()?;
10 | | (
11 | | product["name"].as_str()?.to_owned(),
12 | | //as_u64 fails for some reason
13 | | product["stock"].as_str()?.parse::<u32>()?,
| | ^ cannot use the `?` operator in a closure that returns `(std::string::String, u32)`
14 | | )
15 | | })
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Result<Infallible, ParseIntError>>` is not implemented for `(std::string::String, u32)`
= note: required by `from_residual`
error: aborting due to 5 previous errors
I don't know the exact structure of the JSON in advance, so I cannot parse it into a struct. All I know is that it is most likely an array of objects which have a name string field and a stock integer field, which I want to extract into a map. If that doesn't happen to be the case, then I want to return an error. What is the simplest way to do this?
UPDATE:
After following Lagerbaer's suggestions and doing some digging I came up with the following solution.
use anyhow::{anyhow, Result};
use std::collections::HashMap;
fn get_stock(response: serde_json::Value) -> Result<HashMap<String, u32>> {
response
.get("products")
.ok_or(anyhow!("'products' not found"))?
.as_array()
.ok_or(anyhow!("'products' is not an array"))?
.iter()
.map(|product| -> Result<(String, u32)> {
let product = product.as_object().unwrap();
Ok((
product
.get("name")
.ok_or(anyhow!("'name' not found"))?
.as_str()
.ok_or(anyhow!("'name' is not a string"))?
.trim()
.to_owned(),
//as_u64 fails for some reason
product
.get("stock")
.ok_or(anyhow!("'stock' not found"))?
.as_str()
.ok_or(anyhow!("'stock' is not a string"))?
.parse::<u32>()?,
))
})
.collect()
}
Used ok_or() to map Option to Result, had to use the anyhow! macro to make it compatible with the anyhow result type.
It also turns out that collect() actually accepts an iterator of
Result<(String, u32)> to produce a Result<HashMap<String, u32>> with the exact behavior I wanted, that is, returning the first error or the complete hash map if there were no errors.

So there's a couple issues here and the compiler tries its best to tell you.
I'll get you started on the first, and then I encourage you to try going it alone for a bit.
So the very first error is that, apparently, as_array returns an Option and not Result and, hence, you can't use the ? operator there.
Luckily, the compiler tells you what to do: Option has a method ok_or that you should call. It will turn the Option into Result. If the Option is Some(value) you'll get a Ok(value), and if the Option is None, you'll get whatever error you specified in the ok_or argument.
Another easy to spot mistake is this: Your function returns a Result, so the return value should, obviously, be a Result. Hence the very final last ? should be removed, because that ? would take a Result and turn it into the "pure" value (if the result was Ok).
And then what's left is to figure out exactly what the closure should return. Maybe you can try that after fixing the other mistakes that I explained above.

Related

MySQL many-many JSON aggregation merging duplicate keys

I'm having trouble returning a JSON representation of a many-many join. My plan was to encode the columns returned using the following JSON format
{
"dog": [
"duke"
],
"location": [
"home",
"scotland"
]
}
This format would handle duplicate keys by aggregating the results in a JSON array, howver all of my attempts at aggregating this structure so far have just removed duplicates, so the arrays only ever have a single element.
Tables
Here is a simplified table structure I've made for the purposes of explaining this query.
media
| media_id | sha256 | filepath |
| 1 | 33327AD02AD09523C66668C7674748701104CE7A9976BC3ED8BA836C74443DBC | /photos/cat.jpeg |
| 2 | 323b5e69e72ba980cd4accbdbb59c5061f28acc7c0963fee893c9a40db929070 | /photos/dog.jpeg |
| 3 | B986620404660DCA7B3DEC4EFB2DE80C0548AB0DE243B6D59DA445DE2841E474 | /photos/dog2.jpeg |
| 4 | 1be439dd87cd87087a425c760d6d8edc484f126b5447beb2203d21e09e2a8f11 | /photos/balloon.jpeg |
media_metdata_labels_has_media (for many-many joins)
| media_metadata_labels_label_id | media_media_id |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 1 | 2 |
| 4 | 2 |
| 5 | 2 |
| 1 | 3 |
| 6 | 3 |
| 7 | 3 |
| 8 | 4 |
| 9 | 4 |
media_metadata_labels
| label_id | label_key | label_value |
| 2 | cat | lily |
| 4 | dog | duke |
| 6 | dog | rex |
| 1 | pet size | small |
| 3 | location | home |
| 7 | location | park |
| 8 | location | scotland |
| 9 | location | sky |
| 5 | location | studio |
My current attempt
My latest attempt at querying this data uses JSON_MERGE_PRESERVE with two arguments, the first is just an empty JSON object and the second is an invalid JSON document. It's invalid because there are duplicate keys, but I was hoping that JSON_MERGE_PRESERVE would merge them. It turns out JSON_MERGE_PRESERVE will only merge duplicates if they're not in the same JSON argument.
For example, this won't merge two keys
SET #key_one = '{}';
SET #key_two = '{"location": ["home"], "location": ["scotland"]}';
SELECT JSON_MERGE_PRESERVE(#key_one, #key_two);
-- returns {"location": ["scotland"]}
but this will
SET #key_one = '{"location": ["home"] }';
SET #key_two = '{"location": ["scotland"]}';
SELECT JSON_MERGE_PRESERVE(#key_one, #key_two);
-- returns {"location": ["home", "scotland"]}
So anyway, here's my current attempt
SELECT
m.media_id,
m.filepath,
JSON_MERGE_PRESERVE(
'{}',
CAST(
CONCAT(
'{',
GROUP_CONCAT(CONCAT('"', l.label_key, '":["', l.label_value, '"]')),
'}'
)
AS JSON)
)
as labels
FROM media AS m
LEFT JOIN media_metadata_labels_has_media AS lm ON lm.media_media_id = m.media_id
LEFT JOIN media_metadata_labels AS l ON l.label_id = lm.media_metadata_labels_label_id
GROUP BY m.media_id, m.filepath
-- HAVING JSON_CONTAINS(labels, '"location"', CONCAT('$.', '"home"')); -- this would let me filter on labels one they're in the correct JSON format
After trying different combinations of JSON_MERGE, JSON_OBJECTAGG, JSON_ARRAYAGG, CONCAT and GROUP_CONCAT this still leaves me scratching my head.
Disclaimer: Since posting this question I've started using mariadb instead of oracle MySQL. The function below should work for MySQL too, but in case it doesn't then any changes required will likely be small syntax fixes.
I solved this by creating a custom aggregation function
DELIMITER //
CREATE AGGREGATE FUNCTION JSON_LABELAGG (
json_key TEXT,
json_value TEXT
) RETURNS JSON
BEGIN
DECLARE complete_json JSON DEFAULT '{}';
DECLARE current_jsonpath TEXT;
DECLARE current_jsonpath_value_type TEXT;
DECLARE current_jsonpath_value JSON;
DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN complete_json;
main_loop: LOOP
FETCH GROUP NEXT ROW;
SET current_jsonpath = CONCAT('$.', json_key); -- the jsonpath to our json_key
SET current_jsonpath_value_type = JSON_TYPE(JSON_EXTRACT(complete_json, current_jsonpath)); -- the json object type at the current path
SET current_jsonpath_value = JSON_QUERY(complete_json, current_jsonpath); -- the json value at the current path
-- if this is the first label value with this key then place it in a new array
IF (ISNULL(current_jsonpath_value_type)) THEN
SET complete_json = JSON_INSERT(complete_json, current_jsonpath, JSON_ARRAY(json_value));
ITERATE main_loop;
END IF;
-- confirm that an array is at this jsonpath, otherwise that's an exception
CASE current_jsonpath_value_type
WHEN 'ARRAY' THEN
-- check if our json_value is already within the array and don't push a duplicate if it is
IF (ISNULL(JSON_SEARCH(JSON_EXTRACT(complete_json, current_jsonpath), "one", json_value))) THEN
SET complete_json = JSON_ARRAY_APPEND(complete_json, current_jsonpath, json_value);
END IF;
ITERATE main_loop;
ELSE
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Expected JSON label object to be an array';
END CASE;
END LOOP;
RETURN complete_json;
END //
DELIMITER ;
and editing my query to use it
SELECT
m.media_id,
m.filepath,
JSON_LABELAGG(l.label_key, l.label_value) as labels
FROM media AS m
LEFT JOIN media_metadata_labels_has_media AS lm ON lm.media_media_id = m.media_id
LEFT JOIN media_metadata_labels AS l ON l.label_id = lm.media_metadata_labels_label_id
GROUP BY m.media_id, m.filepath

the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)

I am doing my assignment that's include make connection with the database in Rust. I am using the latest version of mysql crate: mysql ="18.2.0".My Database connection is successful as I print the pool variable. I write my own code for table student but I get the error. Then i paste the code of documentation, I recieve the following error with'?' operator:
I am connecting the database in rust for the first time. Any help is appreciated.
warning: unused import: `std::io`
--> src/main.rs:2:5
|
2 | use std::io;
| ^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:17:12
|
14 | / fn insert(){
15 | |
16 | |
17 | | let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
... |
58 | |
59 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:19:16
|
14 | / fn insert(){
15 | |
16 | |
17 | | let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
18 | |
19 | | let mut conn = pool.get_conn()?;
| | ^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
... |
58 | |
59 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:22:1
|
14 | / fn insert(){
15 | |
16 | |
17 | | let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
... |
22 | /| conn.query_drop(
23 | || r"CREATE TEMPORARY TABLE payment (
24 | || customer_id int not null,
25 | || amount int not null,
26 | || account_name text
27 | || )")?;
| ||________^ cannot use the `?` operator in a function that returns `()`
... |
58 | |
59 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:38:1
|
14 | / fn insert(){
15 | |
16 | |
17 | | let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
... |
38 | /| conn.exec_batch(
39 | || r"INSERT INTO payment (customer_id, amount, account_name)
40 | || VALUES (:customer_id, :amount, :account_name)",
41 | || payments.iter().map(|p| params! {
... ||
45 | || })
46 | || )?;
| ||__^ cannot use the `?` operator in a function that returns `()`
... |
58 | |
59 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:49:25
|
14 | / fn insert(){
15 | |
16 | |
17 | | let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
... |
49 | | let selected_payments = conn
| |_________________________^
50 | || .query_map(
51 | || "SELECT customer_id, amount, account_name from payment",
52 | || |(customer_id, amount, account_name)| {
53 | || Payment { customer_id, amount, account_name }
54 | || },
55 | || )?;
| ||______^ cannot use the `?` operator in a function that returns `()`
... |
58 | |
59 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.
error: could not compile `class-09`.
Here is the code, i copy from documentation to test:
use std::io;
use mysql::prelude::*;
use mysql::*;
#[derive(Debug, PartialEq, Eq)]
struct Payment {
customer_id: i32,
amount: i32,
account_name: Option<String>,
}
fn insert(){
let pool = Pool::new("mysql://root:root#localhost:3306/Rust_testing")?;
let mut conn = pool.get_conn()?;
// Let's create a table for payments.
conn.query_drop(
r"CREATE TEMPORARY TABLE payment (
customer_id int not null,
amount int not null,
account_name text
)")?;
let payments = vec![
Payment { customer_id: 1, amount: 2, account_name: None },
Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
Payment { customer_id: 5, amount: 6, account_name: None },
Payment { customer_id: 7, amount: 8, account_name: None },
Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
];
// Now let's insert payments to the database
conn.exec_batch(
r"INSERT INTO payment (customer_id, amount, account_name)
VALUES (:customer_id, :amount, :account_name)",
payments.iter().map(|p| params! {
"customer_id" => p.customer_id,
"amount" => p.amount,
"account_name" => &p.account_name,
})
)?;
// Let's select payments from database. Type inference should do the trick here.
let selected_payments = conn
.query_map(
"SELECT customer_id, amount, account_name from payment",
|(customer_id, amount, account_name)| {
Payment { customer_id, amount, account_name }
},
)?;
println!("Yay!");
}
fn main(){
insert();
}
and when i write my code without the ? operator, I got the following error:
warning: unused import: `std::io`
--> src/main.rs:2:5
|
2 | use std::io;
| ^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0599]: no method named `query_drop` found for enum `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>` in the current scope
--> src/main.rs:32:6
|
32 | conn.query_drop(
| ^^^^^^^^^^ method not found in `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>`
error[E0599]: no method named `exec_batch` found for enum `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>` in the current scope
--> src/main.rs:48:6
|
48 | conn.exec_batch(
| ^^^^^^^^^^ method not found in `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>`
error[E0599]: no method named `query_map` found for enum `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>` in the current scope
--> src/main.rs:60:6
|
60 | .query_map(
| ^^^^^^^^^ method not found in `std::result::Result<mysql::conn::pool::PooledConn, mysql::error::Error>`
warning: unused import: `mysql::prelude`
--> src/main.rs:4:5
|
4 | use mysql::prelude::*;
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors; 2 warnings emitted
For more information about this error, try `rustc --explain E0599`.
error: could not compile `class-09`.
As the compiler is telling you: you are missing a return type in your function.
The ? operator will return (propagate) the error if any, but for that to work you need to have a return type that can be constructed with the error type.
For prototyping, you can just call unwrap. But this approach should be carefully considered when writing production code, as it will just crash the program when the function returns an error.
find more here

How to call a function from another file and fetch in web

I'm new to Rust and still I am learning things. There is a rust application with main.rs and routes.rs. main.rs file has server configuration and routes.rs has methods with paths.
main.rs
#[macro_use]
extern crate log;
use actix_web::{App, HttpServer};
use dotenv::dotenv;
use listenfd::ListenFd;
use std::env;
mod search;
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::init();
let mut listenfd = ListenFd::from_env();
let mut server = HttpServer::new(||
App::new()
.configure(search::init_routes)
);
server = match listenfd.take_tcp_listener(0)? {
Some(listener) => server.listen(listener)?,
None => {
let host = env::var("HOST").expect("Host not set");
let port = env::var("PORT").expect("Port not set");
server.bind(format!("{}:{}", host, port))?
}
};
info!("Starting server");
server.run().await
}
routes.rs
use crate::search::User;
use actix_web::{get, post, put, delete, web, HttpResponse, Responder};
use serde_json::json;
extern crate reqwest;
extern crate serde;
use reqwest::Error;
use serde::{Deserialize};
use rocket_contrib::json::Json;
use serde_json::Value;
// mod bargainfindermax;
#[get("/users")]
async fn find_all() -> impl Responder {
HttpResponse::Ok().json(
vec![
User { id: 1, email: "tore#cloudmaker.dev".to_string() },
User { id: 2, email: "tore#cloudmaker.dev".to_string() },
]
)
}
pub fn init_routes(cfg: &mut web::ServiceConfig) {
cfg.service(find_all);
}
Now what I want is I want to fetch an API using a method in another separate rs file (fetch_test.rs) and route it in the routes.rs file. Then I want to get the response from a web browser by running that route path(link).
How can I do these things ?? I searched everywhere, but I found nothing helpful. And sometimes I didn't understand some documentations also.
**Update.
fetch_test.rs
extern crate reqwest;
use hyper::header::{Headers, Authorization, Basic, ContentType};
pub fn authenticate() -> String {
fn construct_headers() -> Headers {
let mut headers = Headers::new();
headers.set(
Authorization(
Basic {
username: "HI:ABGTYH".to_owned(),
password: Some("%8YHT".to_owned())
}
)
);
headers.set(ContentType::form_url_encoded());
headers
}
let client = reqwest::Client::new();
let resz = client.post("https://api.test.com/auth/token")
.headers(construct_headers())
.body("grant_type=client_credentials")
.json(&map)
.send()
.await?;
}
Errors.
Compiling sabre-actix-kist v0.1.0 (E:\wamp64\www\BukFlightsNewLevel\flights\APIs\sabre-actix-kist)
error[E0425]: cannot find value `map` in this scope
--> src\search\routes\common.rs:28:12
|
28 | .json(&map)
| ^^^ not found in this scope
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src\search\routes\common.rs:25:12
|
4 | pub fn authenticate() -> String {
| ------------ this is not `async`
...
25 | let resz = client.post("https://api-crt.cert.havail.sabre.com/v2/auth/token")
| ____________^
26 | | .headers(construct_headers())
27 | | .body("grant_type=client_credentials")
28 | | .json(&map)
29 | | .send()
30 | | .await?;
| |__________^ only allowed inside `async` functions and blocks
error[E0277]: the trait bound `std::result::Result<search::routes::reqwest::Response, search::routes::reqwest::Error>: std::future::Future` is not satisfied
--> src\search\routes\common.rs:25:12
|
25 | let resz = client.post("https://api-crt.cert.havail.sabre.com/v2/auth/token")
| ____________^
26 | | .headers(construct_headers())
27 | | .body("grant_type=client_credentials")
28 | | .json(&map)
29 | | .send()
30 | | .await?;
| |__________^ the trait `std::future::Future` is not implemented for `std::result::Result<search::routes::reqwest::Response, search::routes::reqwest::Error>`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src\search\routes\common.rs:25:12
|
4 | / pub fn authenticate() -> String {
5 | |
6 | | let res = reqwest::get("http://api.github.com/users")
7 | | .expect("Couldnt")
... |
25 | | let resz = client.post("https://api-crt.cert.havail.sabre.com/v2/auth/token")
| |____________^
26 | || .headers(construct_headers())
27 | || .body("grant_type=client_credentials")
28 | || .json(&map)
29 | || .send()
30 | || .await?;
| ||___________^ cannot use the `?` operator in a function that returns `std::string::String`
31 | |
32 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `std::ops::Try` is not implemented for `std::string::String`
= note: required by `std::ops::Try::from_error`
error[E0308]: mismatched types
--> src\search\routes\common.rs:4:26
|
4 | pub fn authenticate() -> String {
| ------------ ^^^^^^ expected struct `std::string::String`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
**Update Again.
extern crate reqwest;
use hyper::header::{Headers, Authorization, Basic, ContentType};
fn construct_headers() -> Headers {
let mut headers = Headers::new();
headers.set(
Authorization(
Basic {
username: "HI:ABGTYH".to_owned(),
password: Some("%8YHT".to_owned())
}
)
);
headers.set(ContentType::form_url_encoded());
headers
}
pub async fn authenticate() -> Result<String, reqwest::Error> {
let client = reqwest::Client::new();
let resz = client.post("https://api.test.com/auth/token")
.headers(construct_headers())
.body("grant_type=client_credentials")
.json(&map)
.send()
.await?;
}
**New Error.
error[E0425]: cannot find value `map` in this scope
--> src\search\routes\common.rs:24:12
|
24 | .json(&map)
| ^^^ not found in this scope
error[E0277]: the trait bound `impl std::future::Future: search::routes::serde::Serialize` is not satisfied
--> src\search\routes.rs:24:29
|
24 | HttpResponse::Ok().json(set_token)
| ^^^^^^^^^ the trait `search::routes::serde::Serialize` is not implemented for `impl std::future::Future`
error[E0308]: mismatched types
--> src\search\routes\common.rs:22:14
|
22 | .headers(construct_headers())
| ^^^^^^^^^^^^^^^^^^^ expected struct `search::routes::reqwest::header::HeaderMap`, found struct `hyper::header::Headers`
|
= note: expected struct `search::routes::reqwest::header::HeaderMap`
found struct `hyper::header::Headers`
error[E0599]: no method named `json` found for struct `search::routes::reqwest::RequestBuilder` in the current scope
--> src\search\routes\common.rs:24:6
|
24 | .json(&map)
| ^^^^ method not found in `search::routes::reqwest::RequestBuilder`
error[E0308]: mismatched types
--> src\search\routes\common.rs:18:63
|
18 | pub async fn authenticate() -> Result<String, reqwest::Error> {
| _______________________________________________________________^
19 | |
20 | | let client = reqwest::Client::new();
21 | | let resz = client.post("https://api.test.com/auth/token")
... |
27 | |
28 | | }
| |_^ expected enum `std::result::Result`, found `()`
|
= note: expected enum `std::result::Result<std::string::String, search::routes::reqwest::Error>`
found unit type `()`
Can I clarify your question? As I understand you already know how to use functions from another file. Do you need to know how to make API requests and pass a result form a request as Response?
Firstly, you need to create fetch_test.rs with using for example reqwest lib:
let client = reqwest::Client::new();
let res = client.post("http://httpbin.org/post")
.json(&map)
.send()
.await?;
Map result or pass it as it is.
Return result in routes.rs: HttpResponse::Ok().json(res)
I hope it will help you.

MySQL COALESCE Function failing to return non null value

I have this very simply MySQL query:
SELECT m.REF_DATA_ID, COALESCE(m.SQL_FUNCTION, m.PHP_FUNCTION ) AS FUNCTION FROM AAB_REFERENCE_DATA_MANAGER m;
which returns the below data:
REF_DATA_ID | FUNCTION
88295 |
88296 |
88297 |
88298 | now()
88299 |
88300 | now()
88301 |
COALESCE() does not seem to be functioning properly in my query for some reason, when I run the below query:
SELECT m.REF_DATA_ID, m.SQL_FUNCTION, m.PHP_FUNCTION FROM AAB_REFERENCE_DATA_MANAGER m;
returns:
REF_DATA_ID SQL_FUNCTION PHP_FUNCTION
88295 | |
88296 | |
88297 | |
88298 | now() |
88299 | | get_session_user_id
88300 | now() |
88301 | | get_session_user_id
I'm just not sure what I'm doing wrong with COALESCE here...
The output I'm looking for is:
REF_DATA_ID FUNCTION
88295 |
88296 |
88297 |
88298 | now()
88299 | get_session_user_id
88300 | now()
88301 | get_session_user_id
A blank string is not NULL (except in Oracle). So, be more explicit with the comparison:
SELECT m.REF_DATA_ID,
(CASE WHEN m.SQL_FUNCTION IS NULL OR
TRIM(m.SQL_FUNCTION) = ''
THEN m.PHP_FUNCTION
ELSE m.SQL_FUNCTION
END) AS FUNCTION
FROM AAB_REFERENCE_DATA_MANAGER m;
SELECT m.REF_DATA_ID,
COALESCE(If(Length(m.SQL_FUNCTION)=0, NULL, m.SQL_FUNCTION),
If(Length(m.PHP_FUNCTION)=0, NULL, m.PHP_FUNCTION)) AS FUNCTION
FROM AAB_REFERENCE_DATA_MANAGER m;

MySQL query executes fine, but returns (false) empty result set when using != NULL?

I have the following result set, that I'm trying to drill down
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| id | auth_id | trusts_number | buy_sell_actions_id | corporate_actions_id | fx_actions_id | submitted | created_at | updated_at |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
| 2 | 6 | N100723 | 2 | NULL | NULL | 0 | 08/05/2015 11:30 | 08/05/2015 15:32 |
| 5 | 6 | N100723 | NULL | NULL | 1 | 0 | 08/05/2015 15:10 | 08/05/2015 15:10 |
| 6 | 6 | N100723 | NULL | NULL | 2 | 1 | 08/05/2015 15:12 | 08/05/2015 15:41 |
+----+---------+---------------+---------------------+----------------------+---------------+-----------+------------------+------------------+
This result set is generated with the query
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723'
I also want to get rid of any field with fx_actions is NULL, so I change the query to
SELECT * FROM actions WHERE auth_id = 6 AND trusts_number = 'N100723' AND fx_actions_id != NULL
However this returns an empty result set. I've never used "negative" query parameters in MySQL before, so I'm not sure if they should take on a different syntax or what?
Any help would be much appreciated.
Normal comparison operators don't work well with NULL. Both Something = NULL and Something != NULL will return 'unknown', which causes the row to be omitted in the result. Use the special operators IS NULL and IS NOT NULL instead:
SELECT * FROM actions
WHERE auth_id = 6
AND trusts_number = 'N100723'
AND fx_actions_id IS NOT NULL
Wikipedia on NULL and its background
Because null isn't a value, you should use IS NOT NULL