path parameters first, by position; then query parameters, by name
This commit is contained in:
parent
aab5061b56
commit
2a319675b1
123
src/main.rs
123
src/main.rs
|
@ -1171,56 +1171,90 @@ fn gen(api: &OpenAPI, ts: &mut TypeSpace) -> Result<String> {
|
|||
}
|
||||
a(" &self,");
|
||||
|
||||
for par in o.parameters.iter() {
|
||||
match par.item()? {
|
||||
openapiv3::Parameter::Path {
|
||||
parameter_data,
|
||||
style: openapiv3::PathStyle::Simple,
|
||||
} => {
|
||||
/*
|
||||
* Path parameters MUST be required.
|
||||
*/
|
||||
assert!(parameter_data.required);
|
||||
|
||||
let nam = ¶meter_data.name;
|
||||
let tid = ts.select(None, parameter_data.schema()?)?;
|
||||
let typ =
|
||||
ts.render_type(&tid, UseContext::Parameter)?;
|
||||
a(&format!(" {}: {},", nam, typ));
|
||||
}
|
||||
openapiv3::Parameter::Query {
|
||||
parameter_data,
|
||||
allow_reserved: _,
|
||||
style: openapiv3::QueryStyle::Form,
|
||||
allow_empty_value,
|
||||
} => {
|
||||
if let Some(aev) = allow_empty_value {
|
||||
if *aev {
|
||||
bail!("allow empty value is a no go");
|
||||
}
|
||||
}
|
||||
|
||||
let nam = ¶meter_data.name;
|
||||
let tid = ts.select(None, parameter_data.schema()?)?;
|
||||
let tid = if parameter_data.required {
|
||||
tid
|
||||
} else {
|
||||
/*
|
||||
* The order of parameters in the specification is effectively
|
||||
* arbitrary, and both path and query style parameters end up
|
||||
* mingled in the same list.
|
||||
*/
|
||||
let mut parms = o
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|par| {
|
||||
match par.item()? {
|
||||
openapiv3::Parameter::Path {
|
||||
parameter_data,
|
||||
style: openapiv3::PathStyle::Simple,
|
||||
} => {
|
||||
/*
|
||||
* If this is an optional parameter, we need an
|
||||
* Option version of the type.
|
||||
* Path parameters MUST be required.
|
||||
*/
|
||||
ts.id_for_optional(&tid)
|
||||
};
|
||||
let typ =
|
||||
ts.render_type(&tid, UseContext::Parameter)?;
|
||||
a(&format!(" {}: {},", nam, typ));
|
||||
assert!(parameter_data.required);
|
||||
|
||||
query.push((nam.to_string(), !parameter_data.required));
|
||||
let nam = ¶meter_data.name;
|
||||
let tid =
|
||||
ts.select(None, parameter_data.schema()?)?;
|
||||
let typ =
|
||||
ts.render_type(&tid, UseContext::Parameter)?;
|
||||
return Ok((true, nam, typ));
|
||||
}
|
||||
openapiv3::Parameter::Query {
|
||||
parameter_data,
|
||||
allow_reserved: _,
|
||||
style: openapiv3::QueryStyle::Form,
|
||||
allow_empty_value,
|
||||
} => {
|
||||
if let Some(aev) = allow_empty_value {
|
||||
if *aev {
|
||||
bail!("allow empty value is a no go");
|
||||
}
|
||||
}
|
||||
|
||||
let nam = ¶meter_data.name;
|
||||
let tid =
|
||||
ts.select(None, parameter_data.schema()?)?;
|
||||
let tid = if parameter_data.required {
|
||||
tid
|
||||
} else {
|
||||
/*
|
||||
* If this is an optional parameter, we need an
|
||||
* Option version of the type.
|
||||
*/
|
||||
ts.id_for_optional(&tid)
|
||||
};
|
||||
let typ =
|
||||
ts.render_type(&tid, UseContext::Parameter)?;
|
||||
query.push((
|
||||
nam.to_string(),
|
||||
!parameter_data.required,
|
||||
));
|
||||
return Ok((false, nam, typ));
|
||||
}
|
||||
x => bail!("unhandled parameter type: {:#?}", x),
|
||||
}
|
||||
x => bail!("unhandled parameter type: {:#?}", x),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
/*
|
||||
* Deal first with path parameters, ordered by their position in the
|
||||
* path template string.
|
||||
*/
|
||||
let tmp = template::parse(p)?;
|
||||
for pn in tmp.names() {
|
||||
let par = parms.iter().find(|p| p.0 && p.1 == &pn).unwrap();
|
||||
a(&format!(" {}: {},", par.1, par.2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Second, include query parameters, ordered by parameter name.
|
||||
*/
|
||||
parms.sort_by(|a, b| a.1.cmp(&b.1));
|
||||
for par in parms.iter().filter(|p| !p.0) {
|
||||
a(&format!(" {}: {},", par.1, par.2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Include the body parameter, if there is one, last in the list:
|
||||
*/
|
||||
if let Some(bp) = &body_param {
|
||||
a(&format!(" body: {},", bp));
|
||||
}
|
||||
|
@ -1289,7 +1323,6 @@ fn gen(api: &OpenAPI, ts: &mut TypeSpace) -> Result<String> {
|
|||
/*
|
||||
* Generate the URL for the request.
|
||||
*/
|
||||
let tmp = template::parse(p)?;
|
||||
a(&tmp.compile());
|
||||
|
||||
/*
|
||||
|
|
|
@ -35,6 +35,16 @@ impl Template {
|
|||
out.push_str(" );\n");
|
||||
out
|
||||
}
|
||||
|
||||
pub fn names(&self) -> Vec<String> {
|
||||
self.components
|
||||
.iter()
|
||||
.filter_map(|c| match c {
|
||||
Component::Parameter(name) => Some(name.to_string()),
|
||||
Component::Constant(_) => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(t: &str) -> Result<Template> {
|
||||
|
@ -159,6 +169,25 @@ mod test {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names() -> Result<()> {
|
||||
let trials = vec![
|
||||
("/info", vec![]),
|
||||
("/measure/{number}", vec!["number".to_string()]),
|
||||
(
|
||||
"/measure/{one}/{two}/and/{three}/yeah",
|
||||
vec!["one".to_string(), "two".to_string(), "three".to_string()],
|
||||
),
|
||||
];
|
||||
|
||||
for (path, want) in trials.iter() {
|
||||
let t = parse(path).with_context(|| anyhow!("path {}", path))?;
|
||||
assert_eq!(&t.names(), want);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile() -> Result<()> {
|
||||
let t = parse("/measure/{number}")?;
|
||||
|
|
Loading…
Reference in New Issue