Rust serde_json::value::RawValue gives errors "the trait bound ... `r2d2_postgres::postgres::types::FromSql<'_>` is not satisfied" - postgresql

I am using r2d2_postgres to run raw SQL and return the result directly in Actix response.
I need to run raw sql with dynamic data, types and unknown at compile time columns/data types etc. To do this, I came across serde_json::value::RawValue:
It states: "A RawValue can be used to defer parsing parts of a payload until later, or to avoid parsing it at all in the case that part of the payload just needs to be transferred verbatim into a different output object."
https://docs.serde.rs/serde_json/value/struct.RawValue.html
I basically want to avoid parsing it at all and just send it to the Actix client.
Here's my code:
let mut conn = pool.get().expect("Couldn't get db connection from pool");
let result = web::block(move || conn.query("select jsonb_agg(t) from (select * from useraccountview) t",&[]))
.await;
match result {
Ok(result) => {
let foo : serde_json::value::RawValue = result[0].get(0);
HttpResponse::Ok().content_type("application/json").json(foo)
},
Err(e) => HttpResponse::NotAcceptable().body(e.to_string())
}
This gives me 2 errors:
error[E0277]: the trait bound `serde_json::value::RawValue: FromSql<'_>` is not satisfied
--> src/main.rs:188:63
|
188 | let foo : serde_json::value::RawValue = result[0].get(0);
| ^^^ the trait `FromSql<'_>` is not implemented for `serde_json::value::RawValue`
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> src/main.rs:188:17
|
188 | let foo : serde_json::value::RawValue = result[0].get(0);
| ^^^ doesn't have a size known at compile-time
I am very new to Rust so I am probably missing some concept on how to fix this.

Related

Unable to query after upgrading Diesel to v2 (Rust)

Getting the following error:
error[E0308]: mismatched types
--> src/u/r/api/products/articles.rs:17:69
|
17 | let query = web::block(move || articles::table.load::<Articles>(&*connection).unwrap()).await;
| ---------------- ^^^^^^^^^^^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut _`
found reference `&PgConnection`
note: associated function defined here
--> /Users/b/.cargo/registry/src/github.com/diesel-2.0.2/src/query_dsl/mod.rs:1497:8
|
1497 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ^^^^
I am using Diesel v2, it worked before I upgraded to the latest version.
What am I doing wrong?
use crate::u::db::connection::DbPool;
use actix_web::{get, web, HttpResponse, Responder};
#[get("/product/articles")]
pub async fn list(db_pool: web::Data<DbPool>) -> impl Responder {
use crate::u::db::models::products::Articles;
use crate::u::db::schemas::products::articles;
let connection = db_pool.get();
if let Err(e) = connection {
return HttpResponse::InternalServerError().body(format!("E1-{:?}", e));
}
let connection = connection.unwrap();
let query = web::block(move || articles::table.load::<Articles>(&*connection).unwrap()).await;
if let Err(e) = query {
return HttpResponse::InternalServerError().body(format!("E2-{:?}", e));
}
let q = query.expect("oops not Ok");
HttpResponse::Ok().json(q)
}
models/products.rs
use chrono::{DateTime, Utc};
use uuid::Uuid;
use crate::u::db::schemas::products::*;
#[derive(Queryable, Debug, Identifiable, serde::Serialize, serde::Deserialize)]
#[table_name = "articles"]
#[primary_key(prod_art_pvt_uuid)]
pub struct Articles {
pub prod_art_pvt_uuid: Uuid,
pub prod_art_pub_uuid: Uuid,
pub prod_article_pub_id: i32,
pub t: DateTime<Utc>,
}
db/connection.rs
use crate::u::config;
use diesel::pg::PgConnection;
use diesel::r2d2::ConnectionManager;
use r2d2::Pool;
pub type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
pub fn get_pool() -> DbPool {
let url: String = config::get("database_url");
println!("Connecting to database...");
let manager = ConnectionManager::<PgConnection>::new(url);
Pool::builder()
.build(manager)
.expect("Failed to create database connection pool.")
}
The error message already indicates what needs to be change. The important part is that one:
error[E0308]: mismatched types
--> src/u/r/api/products/articles.rs:17:69
|
17 | let query = web::block(move || articles::table.load::<Articles>(&*connection).unwrap()).await;
| ---------------- ^^^^^^^^^^^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut _`
found reference `&PgConnection`
As you can see there you need to change the argument of the load function to a mutable reference. You try to pass an immutable reference, which is something that's not accepted by the underlying function.
I recommend to checkout the Diesel Migration guide which contains an overview of most user-facing breaking changes of the 2.0 release.

Convert Json array to list of strings

I am reading this tutorial https://www.stackbuilders.com/blog/nonsense-getting-started-with-reason-and-reason-react/. One of the problems I am facing is that api.noopschallenge.com is now dead. I replaced the API call to this https://random-word-api.herokuapp.com/word?number=20 This works but returns a Json Array. I have to convert the Json Array to list(string).
I modified the decodeWords function as
let decodeWord = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.map(Js.Json.decodeString, array)
};
But this gives me error
This has type:
Js.Json.t => option(Js.String.t) But somewhere wanted:
array('a)
How do I convert the Json Array to list(string)?
Two problems:
You've switched the arguments to Belt.Array.map around.´array` should come first.
Since decodeString returns an option(string) instead of just a string, you'll have to deal with the Nones somehow. Using Belt.Array.keepMap is a shorter way of just ignoring them.
let decodeWords = (json: Js.Json.t): list(string) =>
switch (Js.Json.decodeArray(json)) {
| None => []
| Some(array) =>
array->Belt.Array.keepMap(Js.Json.decodeString)->Belt.List.fromArray
};
But using the Js.Json API directly is rather cumbersome. You might want to consider using a third-party json decoding library such as bs-json (disclaimer: authored by me) instead. Then it would be as simple as:
let decodeWords = Json.Decode.(list(string))
Or, if you still want it to return an empty list instead of raising an exception on decode failure:
let decodeWords = Json.Decode.(withDefault([], list(string)))
I think I resolved it myself. but if you know of a better solution then please let me know
let decodeWords = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.reduce(array, [], (acc, value) => {
switch(Js.Json.decodeString(value)) {
| None => acc
| Some(v) => [v, ...acc]
}
})
};

How to Specify field MongoDB Definition dynamically using a string in F#

I started out using quite strongly typed definitions
let coll: IMongoCollection<NZPostDataItem> = MongoUtil.getNzpostCollection()
let filter = Builders<NZPostDataItem>.Filter.And(
Builders<NZPostDataItem>.Filter.Gte((fun n -> n.dateLodged),DateTime(2020,10,1)),
Builders<NZPostDataItem>.Filter.Eq((fun n -> n.eshipMatched.Value) , true)
)// ... etc
The problem is, I need to dynamically run a query because one of the objects contains a BSONDocument
let coll: IMongoCollection<NZPostDataItem> = MongoUtil.getNzpostCollection()
let t = Nullable<bool> true
let filter =
FilterDefinition<BsonDocument>.op_Implicit(
"{
eshipMatched:true,
'eship.order.carrier_service_code':'TDEAUS',
dateLodged: {$gte: new Date('01-Oct-2020')}}
)"
)
Which works directly on MongoDB. But when I try and query it, I get a compile time error.
let results = coll.Find(filter).Limit(10000).ToList<NZPostDataItem>()
Severity Code Description Project File Line Suppression State
Error FS0041 No overloads match for method 'Find'.
Known type of argument: FilterDefinition
Available overloads:
- (extension) IMongoCollection.Find<'TDocument>(filter: FilterDefinition<'TDocument>,?options:
FindOptions) : IFindFluent<'TDocument,'TDocument> // Argument 'filter' doesn't match
- (extension) IMongoCollection.Find<'TDocument>(filter:
Linq.Expressions.Expression<Func<'TDocument,bool>>,?options: FindOptions) :
IFindFluent<'TDocument,'TDocument> // Argument 'filter' doesn't match
So - I can sort of see what is wrong - maybe 2 types of definitions - but I need to filter dynamically but return a strongly typed object.
As you said, you want the filter to be both dynamic and strongly-typed, so that's what you should create:
let filter =
FilterDefinition<NZPostDataItem>.op_Implicit("{ ... }")

try! won't compile mismatched types

Why doesn't this Rust code compile?
use std::fs;
use std::io;
use std::path::Path;
fn do_job(path: &Path) -> io::Result<()> {
let mut files: Vec<&Path> = Vec::new();
for entry in try!(fs::read_dir(path)) {
entry = try!(entry);
}
}
it's very similar to code in the docs.
compile error:
<std macros>:3:43: 3:46 error: mismatched types:
expected `core::result::Result<std::fs::DirEntry, std::io::error::Error>`,
found `std::fs::DirEntry`
(expected enum `core::result::Result`,
found struct `std::fs::DirEntry`) [E0308]
<std macros>:3 $ crate:: result:: Result:: Ok ( val ) => val , $ crate:: result:: Result::
^~~
src/main.rs:13:17: 13:28 note: in this expansion of try! (defined in <std macros>)
<std macros>:3:43: 3:46 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:12:5: 14:6 error: mismatched types:
expected `core::result::Result<(), std::io::error::Error>`,
found `()`
(expected enum `core::result::Result`,
found ()) [E0308]
src/main.rs:12 for entry in try!(fs::read_dir(path)) {
src/main.rs:13 entry = try!(entry);
src/main.rs:14 }
src/main.rs:12:5: 14:6 help: run `rustc --explain E0308` to see a detailed explanation
It looks like you want a new binding for each directory entry in your loop:
for entry in fs::read_dir(path)? {
let entry = entry?;
}
this new binding will shadow the one introduced in the for expression.
The type of entry introduced by the loop is Result<DirEntry> which you are trying to unwrap using ? (formerly try!). However you are attempting to assign the resulting DirEntry to a binding with type Result<DirEntry>, hence the error.
The second error indicates that the return value from your function does not match the declared type of io::Result<()>. You can simply return Ok(()):
fn do_job(path: &Path) -> io::Result<()> {
let mut files: Vec<&Path> = Vec::new();
for entry in fs::read_dir(path)? {
let entry = entry?;
//process entry
}
Ok(())
}

convert string to System.DateTime in F#

if I get a string from the command line and it looks like this:
'1-1-2011'
how can I convert that string to a DateTime object in F#?
Depending on your specific need, .NET's DateTime class has several static methods for converting strings to DateTime instances, these are DateTime.Parse, DateTime.ParseExact, and DateTime.TryParse and their several overloads.
#7sharp9 demonstrated the most basic way to perform date parsing, with a direct method call to DateTime.Parse. But where things get interesting in F# is with DateTime.TryParse. Whereas DateTime.Parse will throw an exception if the parse fails, the simplest overload of DateTime.TryParse has the signature string * byref<DateTime> -> bool which will return whether the parse succeeds setting the byref argument to the parsed date if true, or to it's default value (null in this case) otherwise. However, the syntax for using this in F# is cumbersome (and indeed it's not pleasant from any .NET language), so the F# language was designed with a special feature which allows a much nicer calling convention for methods like these as #Thomas Petricek pointed out.
But even F#'s (bool, result) return type pattern here is not ideal. Most of the time you don't need the default value if a parse fails. A nicer signature for DateTime.TryParse would be string -> option<DateTime>. Luckily, we can easily extend DateTime as we like:
type System.DateTime with
static member TryParseOption str =
match DateTime.TryParse str with
| true, r -> Some(r)
| _ -> None
We use the above extension like so:
match System.DateTime.TryParseOption "11/11/11" with
| Some r -> stdout.WriteLine r
| None -> stdout.WriteLine "none"
Which is more consistent with F# conventions (like List.tryFind, for example). But even this is can get "better". Notice how we are matching on the result of the try parse. Using Partial Active Patterns (of course!), we can wrap a whole class of try parses and move the match to the match case for greater flexibility. Take the following
open System
let (|DateTime|_|) str =
match DateTime.TryParse str with
| true, dt -> Some(dt)
| _ -> None
let (|Int|_|) str =
match Int32.TryParse str with
| true, num -> Some(num)
| _ -> None
let (|Float|_|) str =
match Double.TryParse str with
| true, num -> Some(num)
| _ -> None
Using these, we can write a neat little console application:
let rec loop() =
stdout.WriteLine "
Please select an option:
1) Parse something
2) Exit
"
match stdin.ReadLine() with
| Int 1 ->
stdout.WriteLine "Enter something to parse: "
match stdin.ReadLine() with
| Int num -> stdout.WriteLine("Successfully parsed int: {0}", num)
| Float num -> stdout.WriteLine("Successfully parsed float: {0}", num)
| DateTime dt -> stdout.WriteLine("Successfully parsed DateTime: {0}", dt)
| _ -> stdout.WriteLine "Parse Failed!"
loop()
| Int 2 ->
stdout.WriteLine "Now exiting"
| _ ->
stdout.WriteLine "Invalid option, please try again"
loop()
The key thing to notice is the nested match, where Int, Float, DateTime perform their try parses within the same match expression.
There are other neat applications of these active patterns too, for example, we can succinctly simultaneously filter and map a list of date strings
> ["11/23/2003"; "not a date"; "1/1/23 23:23pm"] |> Seq.choose(|DateTime|_|);;
val it : seq<DateTime> =
seq
[11/23/2003 12:00:00 AM {Date = 11/23/2003 12:00:00 AM;
Day = 23;
DayOfWeek = Sunday;
DayOfYear = 327;
Hour = 0;
Kind = Unspecified;
Millisecond = 0;
Minute = 0;
Month = 11;
Second = 0;
Ticks = 632051424000000000L;
TimeOfDay = 00:00:00;
Year = 2003;};
1/1/2023 11:23:00 PM {Date = 1/1/2023 12:00:00 AM;
Day = 1;
DayOfWeek = Sunday;
DayOfYear = 1;
Hour = 23;
Kind = Unspecified;
Millisecond = 0;
Minute = 23;
Month = 1;
Second = 0;
Ticks = 638082121800000000L;
TimeOfDay = 23:23:00;
Year = 2023;}]
To add one nice thing to what 7sharp9 wrote, if you also want to handle failures, you can write:
match System.DateTime.TryParse "1-1-2011" with
| true, date -> printfn "Success: %A" date
| false, _ -> printfn "Failed!"
This is not obvious, because the TryParse method has a byref<DateTime> as the last argument (and it is used using out in C#), but F# allows you to call the method like this.
You could do it as simply as this:
let dateTime = System.DateTime.Parse "1-1-2011"