Skip to main content

ocpi_tariffs_cli/
guess_version.rs

1use std::{fmt, path::PathBuf};
2
3use console::style;
4use ocpi_tariffs::{cdr, guess, json, tariff};
5
6use crate::{load_object_file, load_object_from_stdin, print, Error, ObjectKind};
7
8#[derive(clap::Parser)]
9pub struct Command {
10    #[command(flatten)]
11    args: Args,
12}
13
14#[derive(clap::Args)]
15pub struct Args {
16    /// The type of OCPI object contained in the given JSON.
17    #[arg(short = 't', long = "type")]
18    kind: ObjectKind,
19
20    /// A path to JSON file for the specified object.
21    #[arg(short = 'f', long)]
22    file: Option<PathBuf>,
23
24    /// Check if all fields are allowed to be there according to the OCPI spec.
25    #[arg(long)]
26    validate: bool,
27}
28
29impl fmt::Display for ObjectKind {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            ObjectKind::Cdr => f.write_str("CDR"),
33            ObjectKind::Tariff => f.write_str("tariff"),
34        }
35    }
36}
37
38enum Outcome<'buf> {
39    Version {
40        object_kind: ObjectKind,
41
42        version: guess::Version<ocpi_tariffs::Version, ()>,
43    },
44    Report {
45        object_kind: ObjectKind,
46
47        /// A list of fields that were not expected: The schema did not define them.
48        ///
49        /// This list will always be empty if the guessed `Version` is `Uncertain`.
50        unexpected_fields: json::UnexpectedFields<'buf>,
51
52        version: guess::Version<ocpi_tariffs::Version, ()>,
53    },
54}
55
56impl Command {
57    pub fn run(self) -> Result<(), Error> {
58        let Self {
59            args:
60                Args {
61                    kind: object_kind,
62                    file: path,
63                    validate,
64                },
65        } = self;
66
67        let json = if let Some(path) = path.as_deref() {
68            load_object_file(path, object_kind)?
69        } else {
70            load_object_from_stdin(object_kind)?
71        };
72
73        let outcome = match object_kind {
74            ObjectKind::Cdr => {
75                if validate {
76                    let report = cdr::parse_and_report(&json)?;
77                    let guess::Report {
78                        unexpected_fields,
79                        version,
80                    } = report;
81
82                    Outcome::Report {
83                        object_kind,
84                        unexpected_fields,
85                        version: version.into_version(),
86                    }
87                } else {
88                    let version = cdr::parse(&json)?;
89                    Outcome::Version {
90                        object_kind,
91                        version: version.into_version(),
92                    }
93                }
94            }
95            ObjectKind::Tariff => {
96                if validate {
97                    let report = tariff::parse_and_report(&json)?;
98                    let guess::Report {
99                        unexpected_fields,
100                        version,
101                    } = report;
102
103                    Outcome::Report {
104                        object_kind,
105                        unexpected_fields,
106                        version: version.into_version(),
107                    }
108                } else {
109                    let version = tariff::parse(&json)?;
110                    Outcome::Version {
111                        object_kind,
112                        version: version.into_version(),
113                    }
114                }
115            }
116        };
117
118        match outcome {
119            Outcome::Version {
120                object_kind,
121                version,
122            } => print_version(object_kind, &version),
123            Outcome::Report {
124                object_kind,
125                unexpected_fields,
126                version,
127            } => {
128                print::unexpected_fields(object_kind, &unexpected_fields);
129                print_version(object_kind, &version);
130            }
131        }
132
133        Ok(())
134    }
135}
136
137fn print_version(object_kind: ObjectKind, version: &guess::Version<ocpi_tariffs::Version, ()>) {
138    match version {
139        guess::Version::Uncertain(()) => {
140            eprintln!(
141                "Unable to guess the version of the given {} JSON",
142                style(object_kind).green()
143            );
144        }
145        guess::Version::Certain(version) => {
146            println!("{version}");
147        }
148    }
149}