From 674d89bbabfcb586ea2be20e577a405ea855fd32 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gudkov Date: Thu, 25 Feb 2021 10:04:19 +0300 Subject: [PATCH] Removed unnecessarey preserve_order feature for serde_json. More reliable serialization-desetislization of sqlx-data.json. Added unit tests for sqlx-data.json serialization-deserialization Signed-off-by: Vyacheslav Gudkov --- sqlx-cli/Cargo.toml | 2 +- sqlx-cli/src/prepare.rs | 87 +++++++++++++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/sqlx-cli/Cargo.toml b/sqlx-cli/Cargo.toml index d022ad48..4b497d9f 100644 --- a/sqlx-cli/Cargo.toml +++ b/sqlx-cli/Cargo.toml @@ -36,7 +36,7 @@ url = { version = "2.1.1", default-features = false } async-trait = "0.1.30" console = "0.11.3" dialoguer = "0.7.1" -serde_json = { version = "1.0.53", features = ["preserve_order"] } +serde_json = "1.0.53" serde = { version = "1.0.110", features = ["derive"] } glob = "0.3.0" openssl = { version = "0.10.30", optional = true } diff --git a/sqlx-cli/src/prepare.rs b/sqlx-cli/src/prepare.rs index dcc4748a..648c4a0d 100644 --- a/sqlx-cli/src/prepare.rs +++ b/sqlx-cli/src/prepare.rs @@ -15,14 +15,14 @@ use std::{env, fs}; type QueryData = BTreeMap; type JsonObject = serde_json::Map; -pub fn run(url: &str, merge: bool, cargo_args: Vec) -> anyhow::Result<()> { - #[derive(serde::Serialize)] - struct DataFile { - db: &'static str, - #[serde(flatten)] - data: QueryData, - } +#[derive(serde::Serialize, serde::Deserialize)] +struct DataFile { + db: String, + #[serde(flatten)] + data: QueryData, +} +pub fn run(url: &str, merge: bool, cargo_args: Vec) -> anyhow::Result<()> { let db_kind = get_db_kind(url)?; let data = run_prepare_step(merge, cargo_args)?; @@ -37,7 +37,10 @@ pub fn run(url: &str, merge: bool, cargo_args: Vec) -> anyhow::Result<() BufWriter::new( File::create("sqlx-data.json").context("failed to create/open `sqlx-data.json`")?, ), - &DataFile { db: db_kind, data }, + &DataFile { + db: db_kind.to_owned(), + data, + }, ) .context("failed to write to `sqlx-data.json`")?; @@ -57,15 +60,10 @@ pub fn check(url: &str, merge: bool, cargo_args: Vec) -> anyhow::Result< "failed to open `sqlx-data.json`; you may need to run `cargo sqlx prepare` first", )?; - let mut saved_data: QueryData = serde_json::from_reader(BufReader::new(data_file))?; - - let expected_db = saved_data - .remove("db") - .context("expected key `db` in data file")?; - - let expected_db = expected_db - .as_str() - .context("expected key `db` to be a string")?; + let DataFile { + db: expected_db, + data: saved_data, + } = serde_json::from_reader(BufReader::new(data_file))?; if db_kind != expected_db { bail!( @@ -203,3 +201,58 @@ fn get_db_kind(url: &str) -> anyhow::Result<&'static str> { AnyKind::Mssql => Ok("MSSQL"), } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + use std::assert_eq; + + #[test] + fn data_file_serialization_works() { + let data_file = DataFile { + db: "mysql".to_owned(), + data: { + let mut data = BTreeMap::new(); + data.insert("a".to_owned(), json!({"key1": "value1"})); + data.insert("z".to_owned(), json!({"key2": "value2"})); + data + }, + }; + + let data_file = serde_json::to_string(&data_file).expect("Data file serialized."); + + assert_eq!( + data_file, + "{\"db\":\"mysql\",\"a\":{\"key1\":\"value1\"},\"z\":{\"key2\":\"value2\"}}" + ); + } + + #[test] + fn data_file_deserialization_works() { + let data_file = + "{\"db\":\"mysql\",\"a\":{\"key1\":\"value1\"},\"z\":{\"key2\":\"value2\"}}"; + + let data_file: DataFile = serde_json::from_str(data_file).expect("Data file deserialized."); + let DataFile { db, data } = data_file; + + assert_eq!(db, "mysql"); + assert_eq!(data.len(), 2); + assert_eq!(data.get("a"), Some(&json!({"key1": "value1"}))); + assert_eq!(data.get("z"), Some(&json!({"key2": "value2"}))); + } + + #[test] + fn data_file_deserialization_works_for_ordered_keys() { + let data_file = + "{\"a\":{\"key1\":\"value1\"},\"db\":\"mysql\",\"z\":{\"key2\":\"value2\"}}"; + + let data_file: DataFile = serde_json::from_str(data_file).expect("Data file deserialized."); + let DataFile { db, data } = data_file; + + assert_eq!(db, "mysql"); + assert_eq!(data.len(), 2); + assert_eq!(data.get("a"), Some(&json!({"key1": "value1"}))); + assert_eq!(data.get("z"), Some(&json!({"key2": "value2"}))); + } +}