Skip to main content

gleif_rs/model/
field_modification.rs

1//! Model definitions for the GLEIF field modification endpoint.
2//!
3//! This module contains the data structures used to deserialize responses from the `/field-modifications` endpoint of the GLEIF API.
4//! It provides Rust models for the field modification resource, matching the JSON structure returned by the API.
5//!
6//! For endpoint usage and client methods, see [`crate::endpoint::field_modification`] (`src/endpoint/field_modification.rs`).
7
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10
11/// Represents a field modification record as returned by the GLEIF API.
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
13pub struct FieldModification {
14    /// The type of the data (e.g., "fieldModifications").
15    pub r#type: String,
16    /// The unique identifier of the field modification.
17    pub id: String,
18    /// The attributes of the field modification.
19    pub attributes: FieldModificationAttributes,
20}
21
22/// Attributes of a field modification as returned by the GLEIF API.
23#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct FieldModificationAttributes {
26    /// The LEI associated with the modification.
27    pub lei: String,
28    /// The type of record being modified.
29    pub record_type: String,
30    /// The type of modification performed.
31    pub modification_type: String,
32    /// The field that was modified.
33    pub field: String,
34    /// The date and time of the modification.
35    pub date: DateTime<Utc>,
36    /// The old value of the field, if available.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub value_old: Option<String>,
39    /// The new value of the field.
40    pub value_new: String,
41    /// Additional context for the modification, if available.
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub context: Option<FieldModificationContext>,
44}
45
46/// Context information for a field modification, if available.
47#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct FieldModificationContext {
50    /// The type of relationship, if applicable.
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub relationship_type: Option<String>,
53    /// The end node of the relationship, if applicable.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub end_node: Option<String>,
56    /// The exception category, if applicable.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub exception_category: Option<String>,
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::{model::common::GleifApiResponse, test_utils::test_model_files};
65    use serde_json;
66    use std::path::Path;
67
68    #[test]
69    fn test_deserialize_multi_field_modifications() {
70        let dir = Path::new("tests/data/field_modifications");
71        test_model_files(
72            |filename| {
73                filename.starts_with("field_modifications_")
74                    && Path::new(filename)
75                        .extension()
76                        .is_some_and(|ext| ext.eq_ignore_ascii_case("json"))
77            },
78            |data| serde_json::from_str::<GleifApiResponse<Vec<FieldModification>>>(data),
79            |filename, list| {
80                if list.data.is_empty() {
81                    return;
82                }
83                assert!(
84                    !list.data[0].id.is_empty(),
85                    "FieldModification id should not be empty in first record of {filename}"
86                );
87                assert!(
88                    !list.data[0].attributes.lei.is_empty(),
89                    "FieldModification LEI should not be empty in first record of {filename}"
90                );
91            },
92            dir,
93        );
94    }
95}