Skip to content

Commit

Permalink
fix #24 tuples in Path cause panic
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtbuilds committed Sep 27, 2024
1 parent d9e1181 commit 1ea6242
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 86 deletions.
5 changes: 3 additions & 2 deletions Justfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set dotenv-load := true
set positional-arguments
set export

help:
@just --list --unsorted
Expand All @@ -8,8 +9,8 @@ build:
cargo build
alias b := build

test:
@just oasgen/test
test *ARGS:
@just oasgen/test "$ARGS"

check:
cargo check
Expand Down
70 changes: 50 additions & 20 deletions core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ mod bigdecimal;
mod http;
#[cfg(feature = "sid")]
mod sid;
mod tuple;

pub trait OaSchema {
fn schema() -> Schema;
Expand Down Expand Up @@ -79,6 +78,37 @@ macro_rules! impl_oa_schema_passthrough {
};
}

// We have to define this macro instead of defining OaSchema for tuples because
// the Path types have to implement parameters(). parameters calls out to T::schema_ref()
// because we need to implement something like Path<u64> : OaSchema,
// but tuples don't work the same way, because schema doesn't return multiple schemas.

// The alternative is a second trait interface like OaSchemaTuple, and we'd impl<T: OaSchemaTuple>
// for axum::extract::Path and friends
#[macro_export]
macro_rules! impl_parameters {
// Pattern for generic axum types with tuple generics (A1, A2, etc.)
($($path:ident)::+, $($A:ident),+) => {
impl<$($A: OaSchema),+> OaSchema for $($path)::+<($($A,)+)> {
fn schema() -> Schema {
panic!("Call parameters() for this type, not schema().");
}

fn parameters() -> Vec<ReferenceOr<oa::Parameter>> {
vec![
$(
ReferenceOr::Item(oa::Parameter::path(stringify!($A), $A::schema_ref())),
)+
]
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
None
}
}
};
}

impl OaSchema for () {
fn schema() -> Schema {
panic!("Call body_schema() for (), not schema().")
Expand Down Expand Up @@ -115,21 +145,27 @@ impl<T> OaSchema for Vec<T>
where
T: OaSchema,
{
fn schema_ref() -> ReferenceOr<Schema> {
let inner = T::schema_ref();
ReferenceOr::Item(Schema::new_array(inner))
}

fn schema() -> Schema {
let inner = T::schema();
Schema::new_array(inner)
}

fn schema_ref() -> ReferenceOr<Schema> {
let inner = T::schema_ref();
ReferenceOr::Item(Schema::new_array(inner))
}
}

impl<T> OaSchema for Option<T>
where
T: OaSchema,
{
fn schema() -> Schema {
let mut schema = T::schema();
schema.nullable = true;
schema
}

fn schema_ref() -> ReferenceOr<Schema> {
let mut schema = T::schema_ref();
let Some(s) = schema.as_mut() else {
Expand All @@ -138,26 +174,20 @@ where
s.nullable = true;
schema
}

fn schema() -> Schema {
let mut schema = T::schema();
schema.nullable = true;
schema
}
}

impl<T, E> OaSchema for Result<T, E>
where
T: OaSchema,
{
fn schema_ref() -> ReferenceOr<Schema> {
T::schema_ref()
}

fn schema() -> Schema {
T::schema()
}

fn schema_ref() -> ReferenceOr<Schema> {
T::schema_ref()
}

fn body_schema() -> Option<ReferenceOr<Schema>> {
T::body_schema()
}
Expand All @@ -167,13 +197,13 @@ impl<K, V> OaSchema for HashMap<K, V>
where
V: OaSchema,
{
fn schema_ref() -> ReferenceOr<Schema> {
ReferenceOr::Item(Schema::new_map(V::schema_ref()))
}

fn schema() -> Schema {
Schema::new_map(V::schema())
}

fn schema_ref() -> ReferenceOr<Schema> {
ReferenceOr::Item(Schema::new_map(V::schema_ref()))
}
}

#[cfg(feature = "uuid")]
Expand Down
6 changes: 5 additions & 1 deletion core/src/schema/axum.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use openapiv3::{ReferenceOr, Schema};
use openapiv3 as oa;

use crate::OaSchema;
use crate::{impl_parameters, OaSchema};

impl<T: OaSchema> OaSchema for axum::extract::Json<T> {
fn schema() -> Schema {
Expand Down Expand Up @@ -104,3 +104,7 @@ impl<T: OaSchema> OaSchema for serde_qs::axum::QsQuery<T> {
}
fn body_schema() -> Option<ReferenceOr<Schema>> { None }
}

impl_parameters!(axum::extract::Path, A1);
impl_parameters!(axum::extract::Path, A1, A2);
impl_parameters!(axum::extract::Path, A1, A2, A3);
60 changes: 0 additions & 60 deletions core/src/schema/tuple.rs

This file was deleted.

5 changes: 3 additions & 2 deletions oasgen/Justfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set dotenv-load := true
set positional-arguments
set export

help:
@just --list --unsorted
Expand All @@ -18,8 +19,8 @@ fix:
run *ARGS:
cargo run --example actix --features actix

test:
cargo test --all-features "$@"
test *ARGS:
cargo test --all-features "$ARGS"

alias r := run

Expand Down
2 changes: 1 addition & 1 deletion oasgen/tests/test-axum.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[test]
fn run_tests() {
fn test_axum() {
let t = trybuild::TestCases::new();
t.pass("tests/test-axum/01-hello.rs");
t.pass("tests/test-axum/02-query.rs");
Expand Down
6 changes: 6 additions & 0 deletions oasgen/tests/test-axum/03-path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ async fn get_task(Path(_id): Path<u64>) -> Json<()> {
Json(())
}

#[oasgen]
async fn get_stuff(Path((_id, _tu)): Path<(u64, u64)>) -> Json<()> {
Json(())
}

fn main() {
use pretty_assertions::assert_eq;
let server = Server::axum()
.get("/tasks/:id/", get_task)
.get("/tasks/:id/:tu", get_stuff)
;

let spec = serde_yaml::to_string(&server.openapi).unwrap();
Expand Down
15 changes: 15 additions & 0 deletions oasgen/tests/test-axum/03-path.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ paths:
in: path
style: simple
responses: {}
/tasks/{id}/{tu}:
get:
operationId: get_stuff
parameters:
- name: id
schema:
type: integer
in: path
style: simple
- name: tu
schema:
type: integer
in: path
style: simple
responses: {}
components:
schemas:
TaskFilter:
Expand Down

0 comments on commit 1ea6242

Please sign in to comment.