Skip to main content

ocpi_tariffs_cli/
guess_version.rs

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