use super::{ArgPart, IntoArgPart, IntoReturnPart, ReturnPart, ReturnSpec, Operation};
use axum::routing::MethodFilter;
use std::borrow::Cow;
#[derive(Debug, Default, Clone)]
pub struct PatchOp {
name: Option<String>,
description: Option<String>,
arg_patches: Vec<ArgPatchData>,
return_patch: Option<ReturnPatchData>,
append_returns: Vec<ReturnPatchData>,
tags: Option<Vec<Cow<'static, str>>>,
}
#[derive(Debug, Clone)]
struct ArgPatchData {
position: usize,
name: Option<String>,
description: Option<String>,
part: Option<ArgPart>,
}
impl ArgPatchData {
fn apply_to_op(self, op: &mut Operation) {
if let Some(arg) = op.args.get_mut(self.position) {
if let Some(name) = self.name {
arg.name = name;
}
if let Some(description) = self.description {
arg.description = Some(description);
}
if let Some(part) = self.part {
arg.part = part;
}
}
}
}
#[derive(Debug, Clone)]
struct ReturnPatchData {
description: Option<String>,
status_code: Option<u16>,
part: Option<ReturnPart>,
}
impl ReturnPatchData {
fn apply(self, ret: &mut ReturnSpec) {
if let Some(description) = self.description {
ret.description = Some(description);
}
if let Some(status_code) = self.status_code {
ret.status_code = Some(status_code);
}
if let Some(part) = self.part {
ret.part = part;
}
}
fn to_return_spec(&self) -> ReturnSpec {
ReturnSpec {
description: self.description.clone(),
status_code: self.status_code,
part: self.part.clone().unwrap_or_else(|| ReturnPart::Body(
super::TypeSchema::wrap::<()>(),
"application/json".into(),
)),
}
}
}
impl PatchOp {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn tags(mut self, tags: Vec<Cow<'static, str>>) -> Self {
self.tags = Some(tags);
self
}
pub fn tag(mut self, tag: impl Into<Cow<'static, str>>) -> Self {
let tag_value = tag.into();
if let Some(ref mut tags) = self.tags {
tags.push(tag_value);
} else {
self.tags = Some(vec![tag_value]);
}
self
}
pub fn arg(self, position: usize) -> ArgPatch {
ArgPatch {
spec: self,
position,
name: None,
description: None,
part: None,
}
}
pub fn ret(self) -> ReturnPatch {
ReturnPatch {
spec: self,
is_append: false,
description: None,
status_code: None,
part: None,
}
}
pub fn append(self) -> ReturnPatch {
ReturnPatch {
spec: self,
is_append: true,
description: None,
status_code: None,
part: None,
}
}
pub fn apply(self, op: &mut Operation) {
if let Some(name) = self.name {
op.name = name;
}
if let Some(description) = self.description {
op.description = Some(description);
}
if let Some(tags) = self.tags {
op.tags = tags;
}
for arg_patch in self.arg_patches {
arg_patch.apply_to_op(op);
}
if let Some(return_patch) = self.return_patch {
if let Some(last_ret) = op.returns.last_mut() {
return_patch.apply(last_ret);
}
}
for append_patch in self.append_returns {
op.returns.push(append_patch.to_return_spec());
}
}
}
pub struct ArgPatch {
spec: PatchOp,
position: usize,
name: Option<String>,
description: Option<String>,
part: Option<ArgPart>,
}
impl ArgPatch {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.description = Some(doc.into());
self
}
pub fn typed<T: IntoArgPart>(mut self) -> Self {
self.part = Some(T::into_arg_part());
self
}
pub fn arg(self, position: usize) -> ArgPatch {
let arg_patch_data = ArgPatchData {
position: self.position,
name: self.name,
description: self.description,
part: self.part,
};
let mut spec = self.spec;
spec.arg_patches.push(arg_patch_data);
ArgPatch {
spec,
position,
name: None,
description: None,
part: None,
}
}
fn finalize(self) -> PatchOp {
let arg_patch_data = ArgPatchData {
position: self.position,
name: self.name,
description: self.description,
part: self.part,
};
let mut spec = self.spec;
spec.arg_patches.push(arg_patch_data);
spec
}
pub fn done(self) -> PatchOp {
self.finalize()
}
pub fn ret(self) -> ReturnPatch {
self.finalize().ret()
}
pub fn append(self) -> ReturnPatch {
self.finalize().append()
}
pub fn apply_to_operation(self, op: &mut Operation) {
self.finalize().apply(op);
}
}
pub struct ReturnPatch {
spec: PatchOp,
is_append: bool,
description: Option<String>,
status_code: Option<u16>,
part: Option<ReturnPart>,
}
impl ReturnPatch {
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.description = Some(doc.into());
self
}
pub fn status(mut self, status_code: u16) -> Self {
self.status_code = Some(status_code);
self
}
pub fn typed<T: IntoReturnPart>(mut self) -> Self {
self.part = Some(T::into_return_part());
self
}
pub fn arg(self, position: usize) -> ArgPatch {
self.finalize().arg(position)
}
pub fn ret(self) -> ReturnPatch {
self.finalize().ret()
}
pub fn append(self) -> ReturnPatch {
self.finalize().append()
}
fn finalize(self) -> PatchOp {
let return_patch_data = ReturnPatchData {
description: self.description,
status_code: self.status_code,
part: self.part,
};
let mut spec = self.spec;
if self.is_append {
spec.append_returns.push(return_patch_data);
} else {
spec.return_patch = Some(return_patch_data);
}
spec
}
pub fn done(self) -> PatchOp {
self.finalize()
}
pub fn apply_to_operation(self, op: &mut Operation) {
self.finalize().apply(op);
}
}