Skip to content

resolve parameters before codegen #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions services/autorust/codegen/src/codegen_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use heck::SnakeCase;
use indexmap::IndexMap;
use proc_macro2::TokenStream;
use quote::quote;
use std::{collections::HashSet, path::Path};
use std::collections::HashSet;

fn error_variant(operation: &WebOperation) -> Result<TokenStream, Error> {
let function = operation.rust_function_name().to_camel_case();
Expand Down Expand Up @@ -117,16 +117,16 @@ fn create_function(cg: &CodeGen, operation: &WebOperation) -> Result<TokenStream

let fpath = format!("{{}}{}", &format_path(&operation.path));

let parameters: Vec<Parameter> = cg.spec.resolve_parameters(&operation.doc_file, &operation.parameters)?;
let parameters = &operation.parameters;
let param_names: HashSet<_> = parameters.iter().map(|p| p.name.as_str()).collect();
let has_param_api_version = param_names.contains("api-version");
let mut skip = HashSet::new();
if cg.spec.api_version().is_some() {
skip.insert("api-version");
}
let parameters: Vec<_> = parameters.into_iter().filter(|p| !skip.contains(p.name.as_str())).collect();
let parameters: Vec<_> = parameters.iter().filter(|p| !skip.contains(p.name.as_str())).collect();

let fparams = create_function_params(cg, &operation.doc_file, &parameters)?;
let fparams = create_function_params(&parameters)?;

// see if there is a body parameter
// let fresponse = create_function_return(operation_verb)?;
Expand Down Expand Up @@ -550,7 +550,7 @@ fn format_path(path: &str) -> String {
PARAM_RE.replace_all(path, "{}").to_string()
}

fn create_function_params(_cg: &CodeGen, _doc_file: &Path, parameters: &[Parameter]) -> Result<TokenStream, Error> {
fn create_function_params(parameters: &[&Parameter]) -> Result<TokenStream, Error> {
let mut params: Vec<TokenStream> = Vec::new();
for param in parameters {
let name = get_param_name(param)?;
Expand Down
62 changes: 40 additions & 22 deletions services/autorust/codegen/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl Spec {
}

/// Resolve a reference or schema to a resolved schema
pub fn resolve_schema<P: AsRef<Path>>(&self, doc_file: P, ref_or_schema: &ReferenceOr<Schema>) -> Result<ResolvedSchema> {
fn resolve_schema<P: AsRef<Path>>(&self, doc_file: P, ref_or_schema: &ReferenceOr<Schema>) -> Result<ResolvedSchema> {
match ref_or_schema {
ReferenceOr::Item(schema) => Ok(ResolvedSchema {
ref_key: None,
Expand All @@ -177,15 +177,6 @@ impl Spec {
}
}

/// Resolve a collection of references or schemas to a collection of resolved schemas
pub fn resolve_schemas<P: AsRef<Path>>(&self, doc_file: P, ref_or_schemas: &[ReferenceOr<Schema>]) -> Result<Vec<ResolvedSchema>> {
let mut resolved = Vec::new();
for schema in ref_or_schemas {
resolved.push(self.resolve_schema(&doc_file, schema)?);
}
Ok(resolved)
}

/// Resolve a collection of references or schemas to a collection of resolved schemas
pub fn resolve_schema_map<P: AsRef<Path>>(
&self,
Expand Down Expand Up @@ -218,14 +209,14 @@ impl Spec {
Ok(resolved)
}

pub fn resolve_parameter(&self, doc_file: &Path, parameter: &ReferenceOr<Parameter>) -> Result<Parameter> {
fn resolve_parameter(&self, doc_file: &Path, parameter: &ReferenceOr<Parameter>) -> Result<Parameter> {
match parameter {
ReferenceOr::Item(param) => Ok(param.clone()),
ReferenceOr::Reference { reference, .. } => self.resolve_parameter_ref(doc_file, reference.clone()),
}
}

pub fn resolve_parameters(&self, doc_file: &Path, parameters: &[ReferenceOr<Parameter>]) -> Result<Vec<Parameter>> {
fn resolve_parameters(&self, doc_file: &Path, parameters: &[ReferenceOr<Parameter>]) -> Result<Vec<Parameter>> {
let mut resolved = Vec::new();
for param in parameters {
resolved.push(self.resolve_parameter(doc_file, param)?);
Expand All @@ -234,18 +225,37 @@ impl Spec {
}

// only operations from listed input files
pub fn operations(&self) -> Result<Vec<WebOperation>> {
let mut operations: Vec<WebOperation> = Vec::new();
fn operations_unresolved(&self) -> Result<Vec<WebOperationUnresolved>> {
let mut operations: Vec<WebOperationUnresolved> = Vec::new();
for (doc_file, doc) in self.docs() {
if self.is_input_file(&doc_file) {
let paths = self.resolve_path_map(doc_file, doc.paths())?;
for (path, item) in &paths {
operations.extend(path_operations(doc_file, path, item))
operations.extend(path_operations_unresolved(doc_file, path, item))
}
}
}
Ok(operations)
}

// only operations from listed input files
pub fn operations(&self) -> Result<Vec<WebOperation>> {
self.operations_unresolved()?
.into_iter()
.map({
|op| {
Ok(WebOperation {
id: op.id,
path: op.path,
verb: op.verb,
parameters: self.resolve_parameters(&op.doc_file, &op.parameters)?,
responses: op.responses,
examples: op.examples,
})
}
})
.collect()
}
}

type Result<T, E = Error> = std::result::Result<T, E>;
Expand Down Expand Up @@ -330,7 +340,7 @@ pub mod openapi {
match item {
ReferenceOr::Reference { reference, .. } => list.push(TypedReference::PathItem(reference.clone())),
ReferenceOr::Item(item) => {
for operation in path_operations(&doc_file, path, item) {
for operation in path_operations_unresolved(&doc_file, path, item) {
// parameters
for param in &operation.parameters {
match param {
Expand Down Expand Up @@ -386,7 +396,8 @@ pub mod openapi {
}
}

pub struct WebOperation {
// contains unresolved parameters
struct WebOperationUnresolved {
pub doc_file: PathBuf,
pub id: Option<String>,
pub path: String,
Expand All @@ -396,6 +407,16 @@ pub struct WebOperation {
pub examples: MsExamples,
}

// contains resolved parameters
pub struct WebOperation {
pub id: Option<String>,
pub path: String,
pub verb: WebVerb,
pub parameters: Vec<Parameter>,
pub responses: IndexMap<StatusCode, Response>,
pub examples: MsExamples,
}

impl WebOperation {
pub fn rust_module_name(&self) -> Option<String> {
match &self.id {
Expand Down Expand Up @@ -462,7 +483,7 @@ struct OperationVerb<'a> {
pub verb: WebVerb,
}

pub fn path_operations<P: AsRef<Path>>(doc_file: P, path: &str, item: &PathItem) -> Vec<WebOperation> {
fn path_operations_unresolved<P: AsRef<Path>>(doc_file: P, path: &str, item: &PathItem) -> Vec<WebOperationUnresolved> {
vec![
OperationVerb {
operation: item.get.as_ref(),
Expand Down Expand Up @@ -498,7 +519,7 @@ pub fn path_operations<P: AsRef<Path>>(doc_file: P, path: &str, item: &PathItem)
Some(op) => {
let mut parameters = item.parameters.clone();
parameters.append(&mut op.parameters.clone());
Some(WebOperation {
Some(WebOperationUnresolved {
doc_file: doc_file.as_ref().to_path_buf(),
id: op.operation_id.clone(),
path: path.to_string(),
Expand Down Expand Up @@ -588,7 +609,6 @@ mod tests {
#[test]
fn test_function_name_from_operation_id() {
let operation = WebOperation {
doc_file: PathBuf::from(""),
id: Some("PrivateClouds_CreateOrUpdate".to_owned()),
path: "/horse".to_owned(),
verb: WebVerb::Get,
Expand All @@ -603,7 +623,6 @@ mod tests {
#[test]
fn test_function_name_from_verb_and_path() {
let operation = WebOperation {
doc_file: PathBuf::from(""),
id: None,
path: "/horse".to_owned(),
verb: WebVerb::Get,
Expand All @@ -618,7 +637,6 @@ mod tests {
#[test]
fn test_function_name_with_no_module_name() {
let operation = WebOperation {
doc_file: PathBuf::from(""),
id: Some("PerformConnectivityCheck".to_owned()),
path: "/horse".to_owned(),
verb: WebVerb::Put,
Expand Down