How do I define a datetime field in sqlx rust - rust

I have a struct as follows?
pub struct Instrument {
pub id:i32,
pub expiry_on: <this should be a date field>
}
What should I give the type of expiry_on. I want to use the struct inside sqlx::query_as!() to fetch records from postgres ?
expiry_on is a timestampz Postgres field.

Under the assumption that your expiry_on field in postgres is a timestamptz: Depending on the time library you use, you will either want to add the chrono feature or the time feature to sqlx. Which you can do in Cargo.toml like this:
[dependencies]
sqlx = { version = "*", features = [ "chrono" ] }
or
sqlx = { version = "*", features = [ "time" ] }
instead of
sqlx = "*"
Where * is whatever version you're using.
You then change the following in Instrument (assuming chrono):
pub struct Instrument {
pub id: i32,
pub expiry_on: chrono::DateTime<chrono::Utc>,
}

Related

Retrieve the version of a dependency in build.rs script

I would like to expose in my REPL (built on top of Boa) the version of the js engine:
I'm trying to use a build.rs file for that:
use std::env;
fn main() {
println!("cargo:rustc-env=BOA_VERSION={}", "0.16.0");
}
And somewhere in my main.rs:
context.register_global_property("BOA_VERSION", env!("BOA_VERSION"), Attribute::all());
Obviously I have hardcoded the version of the crate but wondering if there is a programmatically way to get the version.
If all you need is to get access to the version information in your code, you can skip making a build.rs file for it. Instead, we can use the serde and toml crates to parse your Cargo.toml file directly. Below is a sample of how that might look.
Cargo.toml:
[package]
name = "dependency-information"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.152", features = ["derive"] }
toml = "0.7.0"
main.rs:
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum DependencyValue {
String(String),
Object {
version: String,
features: Vec<String>,
},
}
#[derive(Debug, Serialize, Deserialize)]
struct CargoToml {
dependencies: HashMap<String, DependencyValue>,
}
fn main() {
let cargo_toml_raw = include_str!("../Cargo.toml");
let cargo_toml: CargoToml = toml::from_str(cargo_toml_raw).unwrap();
println!("{cargo_toml:#?}");
}
And if we run it, we get this output:
CargoToml {
dependencies: {
"toml": String(
"0.7.0",
),
"serde": Object {
version: "1.0.152",
features: [
"derive",
],
},
},
}
Note that you probably would want to include the Cargo.toml file dynamically instead of using include_str!. I used include_str! for the sake of the example.

(De)serialize RFC-3339 timestamp with serde to time-rs OffsetDateTime

My goal is to (de)serialize objects with RFC-3339 timestamps from Json to Rust structs (and vice versa) using serde and time-rs.
I would expect this ...
use serde::Deserialize;
use time::{OffsetDateTime};
#[derive(Deserialize)]
pub struct DtoTest {
pub timestamp: OffsetDateTime,
}
fn main() {
let deserialization_result = serde_json::from_str::<DtoTest>("{\"timestamp\": \"2022-07-08T09:10:11Z\"}");
let dto = deserialization_result.expect("This should not panic");
println!("{}", dto.timestamp);
}
... to create the struct and display the timestamp as the output, but I get ...
thread 'main' panicked at 'This should not panic: Error("invalid type: string \"2022-07-08T09:10:11Z\", expected an `OffsetDateTime`", line: 1, column: 36)', src/main.rs:12:38
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
My dependencies look like this:
[dependencies]
serde = { version = "1.0.138", features = ["derive"] }
serde_json = "1.0.82"
time = { version = "0.3.11", features = ["serde"] }
According to the documentation of the time-rs crate, this seems to be possible but I must be missing something.
The default serialization format for time is some internal format. If you want other formats, you should enable the serde-well-known feature and use the serde module to choose the format you want:
#[derive(Deserialize)]
pub struct DtoTest {
#[serde(with = "time::serde::rfc3339")]
pub timestamp: OffsetDateTime,
}
The solution below is based on the serde_with crate. As per its documentation, it aims to be more flexible and composable.
use serde_with::serde_as;
use time::OffsetDateTime;
use time::format_description::well_known::Rfc3339;
#[serde_as]
#[derive(Deserialize)]
pub struct DtoTest {
#[serde_as(as = "Rfc3339")]
pub timestamp: OffsetDateTime,
}
And the Cargo.toml file should have:
[dependencies]
serde_with = { version = "2", features = ["time_0_3"] }
At the following page are listed all De/Serialize transformations available.

how to make diesel auto generate model

I am now using this command to generate schema in rust diesel:
diesel --database-url postgres://postgres:kZLxttcZSN#127.0.0.1:5432/rhythm \
migration run --config-file="${CURRENT_DIR}"/diesel-rhythm.toml
and this is the toml config:
[print_schema]
file = "src/model/diesel/rhythm/rhythm_schema.rs"
# This will cause only the users and posts tables to be output
filter = { only_tables = ["favorites", "songs", "playlist"] }
is it possible to make diesel auto generate the model entity? the entity may look like this:
#[derive( Serialize, Queryable, Deserialize,Default)]
pub struct Music {
pub id: i64,
pub name: String,
pub source_id: String
}
now I write the entity by handle. what should I do to make it generate by diesel cli, I read the document and did not found any useful configuration about this.
You are looking for diesel_cli_ext
First install diesel_cli_ext:
cargo install diesel_cli_ext
[Then] you would have to generate your schema file the diesel way if you haven't yet:
diesel print-schema > src/schema.rs
Finally you have to generate the models file:
diesel_ext --model > src/models.rs
The models in your schema file would be generated in src/models.rs eg:
#[derive(Queryable)]
pub struct Music {
pub id: i64,
pub name: String,
pub source_id: String
}

Create struct that is usable with sqlx, has a datetime AND is serializable. Or how to enable serde?

I have a struct that contains a date and I use it with sqlx to retrieve data from my database. So something like:
use sqlx::types::chrono::{DateTime, Utc};
pub struct Account {
pub id: i32,
pub primary_email_id: i32,
pub created: DateTime<Utc>,
}
and
sqlx::query_as!(Account, "select * ...")
This works fine so far. But I also want Account to be serializable via serde. The obvious approach is:
#[derive(Serialize)]
pub struct Account {
...
This fails, because the Serialize trait is not implemented for DateTime<Utc>. I tried the same with PrimitiveDateTime from the time crate with the same result. In theory both should support serde as a feature.
I tried to explicitly add time or chrono as dependency, to enable serde as feature and use the type without the sqlx::types prefix. But in that case it fails because some sqlx traits are not implemented.
I assume that I somehow have to enable the serde feature for the classes brought in by sqlx, but I have no idea how to specify a feature for a feature!?
How to I tell sqlx to enable serde for the time/chrono types?
This depends on the time and chrono Cargo features of sqlx. So ensure the [dependencies] section of your Cargo.toml file includes these. As an example:
sqlx = { version = "0.6.0", features = [ "postgres", "runtime-tokio-native-tls", "offline", "time", "chrono" ] }
(This is essentially the comment of #Stargateur above. All credit to them.)

Deserialize XML with multiple schema structures

How can I deserialize an XML-string (using serde derive) returned by an API that might have different children?
If I call an API it might return one of the following result sets:
use serde::Deserialize;
use serde_xml_rs::from_str;
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Error {
code: u32,
message: String,
}
#[derive(Debug, Deserialize)]
struct Item {
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct DataSet {
error: Option<Error>,
data: Option<Vec<Item>>
}
fn main() {
let error = r#"
<DataSet>
<Error>
<Code>0</Code>
<Message>error</Message>
</Error>
</DataSet>
"#;
let dataset: DataSet = from_str(error).unwrap();
println!("{:#?}", dataset);
let items = r#"
<DataSet>
<Item>..</Item>
<Item>..</Item>
</DataSet>
"#;
let dataset: DataSet = from_str(items).unwrap();
println!("{:#?}", dataset);
}
[package]
name = "dataset"
version = "0.1.0"
edition = "2018"
[dependencies]
serde = { version = "1", features = ["derive"] }
serde-xml-rs = "0.3"
But I feel like there should be a more idiomatic way of achieving this. Especially since it would make matching off the data a lot easier.
I've tried using #[serde(flatten)], and I've tried setting ApiResponse to a tuple-struct and a struct with a single tuple parameter. No luck.
Is this possible without having to build a custom deserializer?
Take a look at some of the serde examples which might be able to help you here. Specifically the examples/docs on untagged enums which allow you to define many ways to deserialize into a single enum type.

Resources