From bd67e3ee857629aee5266894fd160556b78b5f0f Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 24 Aug 2023 09:27:42 +0300 Subject: [PATCH] question: split struct for binary/text serialize --- app/src/main.rs | 2 +- app_async/src/main.rs | 2 +- lib/src/questions.rs | 305 ++++++++++++++++++++++++++++++------------ 3 files changed, 224 insertions(+), 85 deletions(-) diff --git a/app/src/main.rs b/app/src/main.rs index fbcb2e7..561a6bd 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -10,7 +10,7 @@ use chgk_ledb_lib::db; use chgk_ledb_lib::questions; use chgk_ledb_lib::source; -use crate::questions::{Question, QuestionsConverter}; +use crate::questions::{binary::Question, QuestionsConverter}; use crate::source::ReadSourceQuestionsBatches; const ZIP_FILENAME: &str = "json.zip"; diff --git a/app_async/src/main.rs b/app_async/src/main.rs index 88e1256..996ee02 100644 --- a/app_async/src/main.rs +++ b/app_async/src/main.rs @@ -16,7 +16,7 @@ use tokio::{fs, io}; use tokio_stream::wrappers::UnboundedReceiverStream; use chgk_ledb_lib::async_db; -use chgk_ledb_lib::questions::Question; +use chgk_ledb_lib::questions::binary::Question; use chgk_ledb_lib::questions::QuestionsConverterAsyncForStream; use chgk_ledb_lib::source::ReadSourceQuestionsBatchesAsync; diff --git a/lib/src/questions.rs b/lib/src/questions.rs index 3f5ee68..9039d7a 100644 --- a/lib/src/questions.rs +++ b/lib/src/questions.rs @@ -2,74 +2,264 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] pub struct BatchInfo { - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub filename: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub description: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub author: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub comment: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub url: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub date: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub processed_by: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub redacted_by: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub copyright: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub theme: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub kind: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub source: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub rating: String, } #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] pub struct Question { - #[serde(default)] + #[serde(default, skip_serializing_if = "u32_is_zero")] pub num: u32, pub id: String, + pub description: String, pub answer: String, - #[serde(default)] + + #[serde(default, skip_serializing_if = "String::is_empty")] pub author: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub comment: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub comment1: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub tour: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub url: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub date: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub processed_by: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub redacted_by: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub copyright: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub theme: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub kind: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub source: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "String::is_empty")] pub rating: String, - #[serde(default)] + #[serde(default, skip_serializing_if = "BatchInfo::is_default")] pub batch_info: BatchInfo, } +fn u32_is_zero(num: &u32) -> bool { + *num == 0 +} + +impl BatchInfo { + pub fn is_default(&self) -> bool { + *self == BatchInfo::default() + } +} + +pub mod binary { + use serde_derive::{Deserialize, Serialize}; + #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] + pub struct BatchInfo { + #[serde(default)] + pub filename: String, + #[serde(default)] + pub description: String, + #[serde(default)] + pub author: String, + #[serde(default)] + pub comment: String, + #[serde(default)] + pub url: String, + #[serde(default)] + pub date: String, + #[serde(default)] + pub processed_by: String, + #[serde(default)] + pub redacted_by: String, + #[serde(default)] + pub copyright: String, + #[serde(default)] + pub theme: String, + #[serde(default)] + pub kind: String, + #[serde(default)] + pub source: String, + #[serde(default)] + pub rating: String, + } + + #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] + pub struct Question { + #[serde(default)] + pub num: u32, + pub id: String, + pub description: String, + pub answer: String, + #[serde(default)] + pub author: String, + #[serde(default)] + pub comment: String, + #[serde(default)] + pub comment1: String, + #[serde(default)] + pub tour: String, + #[serde(default)] + pub url: String, + #[serde(default)] + pub date: String, + #[serde(default)] + pub processed_by: String, + #[serde(default)] + pub redacted_by: String, + #[serde(default)] + pub copyright: String, + #[serde(default)] + pub theme: String, + #[serde(default)] + pub kind: String, + #[serde(default)] + pub source: String, + #[serde(default)] + pub rating: String, + #[serde(default)] + pub batch_info: BatchInfo, + } + + #[cfg(test)] + mod test { + use super::*; + use insta::assert_yaml_snapshot; + use serde_json::json; + pub fn sample_question() -> Question { + Question { + id: "Вопрос 1".into(), + description: "Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2".into(), + answer: "42".into(), + batch_info: BatchInfo { + description: "Тестовый".into(), + date: "00-000-2000".into(), + ..Default::default() + }, + ..Default::default() + } + } + + #[test] + fn test_question_ser() { + assert_yaml_snapshot!(sample_question(), @r#" + --- + num: 0 + id: Вопрос 1 + description: Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2 + answer: "42" + author: "" + comment: "" + comment1: "" + tour: "" + url: "" + date: "" + processed_by: "" + redacted_by: "" + copyright: "" + theme: "" + kind: "" + source: "" + rating: "" + batch_info: + filename: "" + description: Тестовый + author: "" + comment: "" + url: "" + date: 00-000-2000 + processed_by: "" + redacted_by: "" + copyright: "" + theme: "" + kind: "" + source: "" + rating: "" + + "#); + } + #[test] + fn test_question_de() { + let question_from_json: Result = serde_json::from_value(json!({ + "id": "Вопрос 1", + "description": "Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2", + "answer": "42", + "batch_info": { + "description": "Тестовый", + "date": "00-000-2000" + } + })); + assert!(question_from_json.is_ok()); + + assert_yaml_snapshot!(question_from_json.unwrap(), @r#" + --- + num: 0 + id: Вопрос 1 + description: Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2 + answer: "42" + author: "" + comment: "" + comment1: "" + tour: "" + url: "" + date: "" + processed_by: "" + redacted_by: "" + copyright: "" + theme: "" + kind: "" + source: "" + rating: "" + batch_info: + filename: "" + description: Тестовый + author: "" + comment: "" + url: "" + date: 00-000-2000 + processed_by: "" + redacted_by: "" + copyright: "" + theme: "" + kind: "" + source: "" + rating: "" + + "#); + } + } +} + #[cfg(any(feature = "convert", feature = "convert_async"))] pub mod convert_common { - use super::{BatchInfo, Question}; + use super::binary::{BatchInfo, Question}; use crate::source::{SourceQuestion, SourceQuestionsBatch}; macro_rules! make { @@ -117,7 +307,7 @@ pub mod convert_common { #[cfg(feature = "convert")] pub mod convert { - use super::Question; + use super::binary::Question; use crate::source::SourceQuestionsBatch; pub trait QuestionsConverter { @@ -234,7 +424,7 @@ pub mod convert_async { use futures_core::stream::Stream; use futures_util::StreamExt; - use super::Question; + use super::binary::Question; use crate::source::SourceQuestionsBatch; pub struct QuestionsConverterAsync @@ -396,7 +586,6 @@ mod test { use super::*; use insta::assert_yaml_snapshot; use serde_json::json; - #[cfg(any(feature = "convert", feature = "convert_async"))] pub mod convert_common { use crate::source::{SourceQuestion, SourceQuestionsBatch}; @@ -442,38 +631,13 @@ mod test { fn test_question_ser() { assert_yaml_snapshot!(sample_question(), @r#" --- - num: 0 id: Вопрос 1 description: Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2 answer: "42" - author: "" - comment: "" - comment1: "" - tour: "" - url: "" - date: "" - processed_by: "" - redacted_by: "" - copyright: "" - theme: "" - kind: "" - source: "" - rating: "" batch_info: - filename: "" description: Тестовый - author: "" - comment: "" - url: "" date: 00-000-2000 - processed_by: "" - redacted_by: "" - copyright: "" - theme: "" - kind: "" - source: "" - rating: "" - + "#); } #[test] @@ -491,37 +655,12 @@ mod test { assert_yaml_snapshot!(question_from_json.unwrap(), @r#" --- - num: 0 id: Вопрос 1 description: Сколько будет (2 * 2 * 2 + 2) * 2 * 2 + 2 answer: "42" - author: "" - comment: "" - comment1: "" - tour: "" - url: "" - date: "" - processed_by: "" - redacted_by: "" - copyright: "" - theme: "" - kind: "" - source: "" - rating: "" batch_info: - filename: "" description: Тестовый - author: "" - comment: "" - url: "" date: 00-000-2000 - processed_by: "" - redacted_by: "" - copyright: "" - theme: "" - kind: "" - source: "" - rating: "" "#); }