use std::collections::HashMap;
use serde_json::Value;
use crate::api::client::ApiClient;
use crate::api::error::ApiError;
use crate::model::types::Operation;
pub struct OperationExecutor<'a> {
client: &'a ApiClient,
}
impl<'a> OperationExecutor<'a> {
pub fn new(client: &'a ApiClient) -> Self {
Self { client }
}
pub async fn execute(
&self,
operation: &Operation,
param_values: &HashMap<String, Value>,
) -> Result<Value, ApiError> {
let mut path_params = HashMap::new();
let mut body = serde_json::Map::new();
for (key, value) in &operation.body_defaults {
body.insert(key.clone(), value.clone());
}
for param in &operation.params {
let value = param_values.get(¶m.name);
if param.is_path_param() {
if let Some(val) = value {
let str_val = match val {
Value::String(s) => s.clone(),
other => other.to_string(),
};
path_params.insert(param.name.clone(), str_val);
}
} else if let Some(val) = value {
if !val.is_null() {
body.insert(param.name.clone(), val.clone());
}
}
}
let body_value = if body.is_empty() && operation.method() == "GET" {
None
} else {
Some(Value::Object(body))
};
self.client
.call(
operation.method(),
operation.path(),
Some(&path_params),
body_value.as_ref(),
)
.await
}
pub async fn execute_all_pages(
&self,
operation: &Operation,
param_values: &HashMap<String, Value>,
) -> Result<Vec<Value>, ApiError> {
let pagination = match &operation.pagination {
Some(p) => p,
None => return self.execute(operation, param_values).await.map(|v| vec![v]),
};
let mut all_items = Vec::new();
let mut current_page = 1u64;
let page_size = pagination.default_page_size as u64;
loop {
let mut page_params = param_values.clone();
page_params.insert(
pagination.page_size_param.clone(),
Value::Number(page_size.into()),
);
page_params.insert(
pagination.page_param.clone(),
Value::Number(current_page.into()),
);
let result = self.execute(operation, &page_params).await?;
let items = result
.get(&pagination.data_field)
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
let count = items.len();
all_items.extend(items);
if count < page_size as usize {
break;
}
current_page += 1;
}
Ok(all_items)
}
}