1

How to properly define the data types such that the JSON de-serialize works fine with Serde/Rust for the following examples? I believe the Hashmap is the culprit somehow. Unable to tell what precisely is wrong. I hope for more complex examples involving logical and comparison operators to work as well.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

pub type Single = MetadataColumnValue;
pub type Multiple = Vec<MetadataColumnValue>;

// Define the generic MetadataColumn type
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum MetadataColumnValue {
    StringValue(String),
    IntValue(i32),
    FloatValue(f64),
    // Add other types as needed
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum ComparisonOperator {
    #[serde(rename = "$eq")]
    Eq(Single),

    #[serde(rename = "$ne")]
    Ne(Single),

    #[serde(rename = "$gt")]
    Gt(Single),

    #[serde(rename = "$gte")]
    Gte(Single),

    #[serde(rename = "$ge")] // Assuming $ge is the same as $gte for this example
    Ge(Single),

    #[serde(rename = "$lt")]
    Lt(Single),

    #[serde(rename = "$lte")]
    Lte(Single),

    #[serde(rename = "$in")]
    In(Multiple),

    #[serde(rename = "$nin")]
    Nin(Multiple),
    // Add other operators as needed
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum LogicalOperator {
    #[serde(rename = "$and")]
    And(Vec<Filter>),

    #[serde(rename = "$or")]
    Or(Vec<Filter>),
    // Add other logical operators as needed
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum Filter {
    Comparison {
        #[serde(flatten)]
        column: HashMap<String, ComparisonOperator>,
    },
    Logical(LogicalOperator),
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct SomeThing {
    pub name: String,
    pub filter: Option<Filter>,
    pub count: Option<i32>,
}

fn main() {
    let json_data1 = r#"
    {
        "name": "example",
        "filter": {
            "genre": { "$eq": "drama" }
        },
        "count": 10
    }
    "#;

    let json_data2 = r#"
    {
        "name": "example",
        "filter": {
            "year": { "$ge": 2020 }
        },
        "count": 5
    }
    "#;

    let ann1: SomeThing = serde_json::from_str(json_data1).unwrap();
    let ann2: SomeThing = serde_json::from_str(json_data2).unwrap();

    println!("{:?}", ann1);
    println!("{:?}", ann2);
}
   Compiling playground v0.0.1 (/playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.42s
     Running `target/debug/playground`
thread 'main' panicked at src/main.rs:98:60:
called `Result::unwrap()` on an `Err` value: Error("data did not match any variant of untagged enum Filter", line: 6, column: 9)
1
  • 1
    Having rename on an untagged enum doesn't make any sense since untagged means you don't use the name (a.k.a. the tag). Commented Jun 5, 2024 at 11:58

1 Answer 1

2

ComparisonOperator must be tagged. So just remove untagged from ComparisonOperator and it will work:

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub enum ComparisonOperator {
}

Read more on Enum representations for serde.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.