openapi_to_rust/server/
mod.rs1use crate::analysis::{OperationInfo, SchemaAnalysis};
10
11pub mod codegen;
12pub mod edit;
13pub mod list;
14pub mod selector;
15pub(crate) mod validation;
16
17pub use selector::{Resolution, Selector, SelectorParseError, SelectorResolveError, resolve};
18
19pub fn resolve_operation_selectors(
22 selectors: &[String],
23 analysis: &SchemaAnalysis,
24) -> Result<Resolution, OperationSelectionError> {
25 let parsed = selectors
26 .iter()
27 .map(|selector| {
28 Selector::parse(selector).map_err(|source| OperationSelectionError::Parse {
29 selector: selector.clone(),
30 source,
31 })
32 })
33 .collect::<Result<Vec<_>, _>>()?;
34 let index = OperationIndex::from_analysis(analysis);
35 resolve(&parsed, &index).map_err(OperationSelectionError::Resolve)
36}
37
38pub fn resolve_operation_id(
44 operation_id: &str,
45 analysis: &SchemaAnalysis,
46) -> Result<Resolution, OperationSelectionError> {
47 let index = OperationIndex::from_analysis(analysis);
48 resolve(&[Selector::OperationId(operation_id.to_string())], &index)
49 .map_err(OperationSelectionError::Resolve)
50}
51
52#[derive(Debug, thiserror::Error)]
53pub enum OperationSelectionError {
54 #[error("invalid operation selector `{selector}`: {source}")]
55 Parse {
56 selector: String,
57 #[source]
58 source: SelectorParseError,
59 },
60 #[error("operation selector did not resolve: {0}")]
61 Resolve(#[source] SelectorResolveError),
62}
63
64#[derive(Debug, Clone)]
67pub struct OperationIndex {
68 operations: Vec<OperationSummary>,
69 operation_id_aliases: std::collections::BTreeMap<String, Vec<String>>,
70}
71
72#[derive(Debug, Clone, serde::Serialize)]
75pub struct OperationSummary {
76 pub operation_id: String,
77 pub method: String,
78 pub path: String,
79 pub tags: Vec<String>,
80 pub supports_streaming: bool,
83}
84
85impl OperationIndex {
86 pub fn from_analysis(analysis: &SchemaAnalysis) -> Self {
88 let operations = analysis
89 .operations
90 .values()
91 .map(OperationSummary::from)
92 .collect();
93 Self {
94 operations,
95 operation_id_aliases: analysis.operation_id_aliases.clone(),
96 }
97 }
98
99 pub fn from_summaries(operations: Vec<OperationSummary>) -> Self {
103 Self {
104 operations,
105 operation_id_aliases: Default::default(),
106 }
107 }
108
109 pub fn operations(&self) -> &[OperationSummary] {
110 &self.operations
111 }
112
113 pub(crate) fn operation_id_aliases(&self, raw_id: &str) -> Option<&[String]> {
114 self.operation_id_aliases.get(raw_id).map(Vec::as_slice)
115 }
116
117 #[cfg(test)]
118 pub(crate) fn with_aliases(
119 mut self,
120 aliases: std::collections::BTreeMap<String, Vec<String>>,
121 ) -> Self {
122 self.operation_id_aliases = aliases;
123 self
124 }
125
126 pub fn tag_count(&self) -> usize {
130 let mut tags: std::collections::BTreeSet<&str> = std::collections::BTreeSet::new();
131 for op in &self.operations {
132 for t in &op.tags {
133 tags.insert(t.as_str());
134 }
135 }
136 tags.len()
137 }
138}
139
140impl From<&OperationInfo> for OperationSummary {
141 fn from(op: &OperationInfo) -> Self {
142 Self {
143 operation_id: op.operation_id.clone(),
144 method: op.method.clone(),
145 path: op.path.clone(),
146 tags: op.tags.clone(),
147 supports_streaming: op.supports_streaming,
148 }
149 }
150}