From 221b241b194caf01da0835174bc4609e9ff0acf5 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 1 Apr 2026 23:13:21 +0900 Subject: [PATCH 1/3] Fix schema_type has_one --- .../changepack_log_FHWJJPPxJTLxVPGXE7Tf3.json | 1 + .../src/schema_macro/type_utils.rs | 10 ++-- examples/axum-example/models/single.json | 12 +++++ examples/axum-example/models/single_rel.json | 17 ++++++ examples/axum-example/openapi.json | 54 +++++++++++++++++++ examples/axum-example/src/models/mod.rs | 2 + examples/axum-example/src/models/single.rs | 14 +++++ .../axum-example/src/models/single_rel.rs | 14 +++++ openapi.json | 54 +++++++++++++++++++ 9 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 .changepacks/changepack_log_FHWJJPPxJTLxVPGXE7Tf3.json create mode 100644 examples/axum-example/models/single.json create mode 100644 examples/axum-example/models/single_rel.json create mode 100644 examples/axum-example/src/models/single.rs create mode 100644 examples/axum-example/src/models/single_rel.rs diff --git a/.changepacks/changepack_log_FHWJJPPxJTLxVPGXE7Tf3.json b/.changepacks/changepack_log_FHWJJPPxJTLxVPGXE7Tf3.json new file mode 100644 index 0000000..84a3c50 --- /dev/null +++ b/.changepacks/changepack_log_FHWJJPPxJTLxVPGXE7Tf3.json @@ -0,0 +1 @@ +{"changes":{"Cargo.toml":"Patch"},"note":"Fix schema_type has_one","date":"2026-04-01T14:13:09.811093500Z"} \ No newline at end of file diff --git a/crates/vespera_macro/src/schema_macro/type_utils.rs b/crates/vespera_macro/src/schema_macro/type_utils.rs index 6658fa7..08937ab 100644 --- a/crates/vespera_macro/src/schema_macro/type_utils.rs +++ b/crates/vespera_macro/src/schema_macro/type_utils.rs @@ -16,15 +16,19 @@ pub const PRIMITIVE_TYPE_NAMES: &[&str] = &[ "f64", "bool", "String", "Decimal", ]; -/// Normalize a `TokenStream` or `Type` to a compact string by removing spaces. +/// Normalize a `TokenStream` or `Type` to a compact string by removing all whitespace. /// /// This replaces the common `.to_string().replace(' ', "")` pattern used throughout /// the codebase to produce deterministic path strings for comparison and cache keys. +/// +/// Removes spaces, newlines, and carriage returns — `proc_macro2`'s `Display` impl +/// may insert newlines when token sequences exceed an internal line-length threshold, +/// which would break substring checks like `contains("HasOne<")`. #[inline] pub fn normalize_token_str(displayable: &impl std::fmt::Display) -> String { let s = displayable.to_string(); - if s.contains(' ') { - s.replace(' ', "") + if s.contains(|c: char| c.is_ascii_whitespace()) { + s.replace(|c: char| c.is_ascii_whitespace(), "") } else { s } diff --git a/examples/axum-example/models/single.json b/examples/axum-example/models/single.json new file mode 100644 index 0000000..8e65f4c --- /dev/null +++ b/examples/axum-example/models/single.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://raw.githubusercontent.com/dev-five-git/vespertide/refs/heads/main/schemas/model.schema.json", + "name": "single", + "columns": [ + { + "name": "username", + "type": { "kind": "varchar", "length": 32 }, + "nullable": false, + "primary_key": true + } + ] +} diff --git a/examples/axum-example/models/single_rel.json b/examples/axum-example/models/single_rel.json new file mode 100644 index 0000000..7eb6773 --- /dev/null +++ b/examples/axum-example/models/single_rel.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://raw.githubusercontent.com/dev-five-git/vespertide/refs/heads/main/schemas/model.schema.json", + "name": "single_rel", + "columns": [ + { + "name": "username", + "type": { "kind": "varchar", "length": 32 }, + "nullable": false, + "primary_key": true, + "foreign_key": { + "ref_table": "single", + "ref_columns": ["username"], + "on_delete": "cascade" + } + } + ] +} diff --git a/examples/axum-example/openapi.json b/examples/axum-example/openapi.json index bf41bd6..df9656c 100644 --- a/examples/axum-example/openapi.json +++ b/examples/axum-example/openapi.json @@ -3467,6 +3467,60 @@ "createdAt" ] }, + "SingleRelSchema": { + "type": "object", + "properties": { + "single": { + "$ref": "#/components/schemas/SingleRelSchema_Single" + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username", + "single" + ] + }, + "SingleRelSchema_Single": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema": { + "type": "object", + "properties": { + "singleRel": { + "$ref": "#/components/schemas/SingleSchema_SingleRel", + "nullable": true + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema_SingleRel": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, "SkipResponse": { "type": "object", "properties": { diff --git a/examples/axum-example/src/models/mod.rs b/examples/axum-example/src/models/mod.rs index 02ee003..0c26e48 100644 --- a/examples/axum-example/src/models/mod.rs +++ b/examples/axum-example/src/models/mod.rs @@ -1,5 +1,7 @@ pub mod config; pub mod memo; pub mod memo_comment; +pub mod single; +pub mod single_rel; pub mod user; pub mod uuid_item; diff --git a/examples/axum-example/src/models/single.rs b/examples/axum-example/src/models/single.rs new file mode 100644 index 0000000..5ad3836 --- /dev/null +++ b/examples/axum-example/src/models/single.rs @@ -0,0 +1,14 @@ +use sea_orm::entity::prelude::*; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "single")] +pub struct Model { + #[sea_orm(primary_key)] + pub username: String, + #[sea_orm(has_one)] + pub single_rel: HasOne, +} + +vespera::schema_type!(Schema from Model, name = "SingleSchema"); +impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/axum-example/src/models/single_rel.rs b/examples/axum-example/src/models/single_rel.rs new file mode 100644 index 0000000..4dcd2e9 --- /dev/null +++ b/examples/axum-example/src/models/single_rel.rs @@ -0,0 +1,14 @@ +use sea_orm::entity::prelude::*; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] +#[sea_orm(table_name = "single_rel")] +pub struct Model { + #[sea_orm(primary_key)] + pub username: String, + #[sea_orm(belongs_to, from = "username", to = "username")] + pub single: HasOne, +} + +vespera::schema_type!(Schema from Model, name = "SingleRelSchema"); +impl ActiveModelBehavior for ActiveModel {} diff --git a/openapi.json b/openapi.json index bf41bd6..df9656c 100644 --- a/openapi.json +++ b/openapi.json @@ -3467,6 +3467,60 @@ "createdAt" ] }, + "SingleRelSchema": { + "type": "object", + "properties": { + "single": { + "$ref": "#/components/schemas/SingleRelSchema_Single" + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username", + "single" + ] + }, + "SingleRelSchema_Single": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema": { + "type": "object", + "properties": { + "singleRel": { + "$ref": "#/components/schemas/SingleSchema_SingleRel", + "nullable": true + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema_SingleRel": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, "SkipResponse": { "type": "object", "properties": { From a49af998cea36b4bedc2dfffe68125bd13149a6e Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 1 Apr 2026 23:19:31 +0900 Subject: [PATCH 2/3] Fix lint --- examples/axum-example/src/models/single.rs | 1 + examples/axum-example/src/models/single_rel.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/axum-example/src/models/single.rs b/examples/axum-example/src/models/single.rs index 5ad3836..9e3a48a 100644 --- a/examples/axum-example/src/models/single.rs +++ b/examples/axum-example/src/models/single.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use sea_orm::entity::prelude::*; #[sea_orm::model] diff --git a/examples/axum-example/src/models/single_rel.rs b/examples/axum-example/src/models/single_rel.rs index 4dcd2e9..14323d6 100644 --- a/examples/axum-example/src/models/single_rel.rs +++ b/examples/axum-example/src/models/single_rel.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use sea_orm::entity::prelude::*; #[sea_orm::model] From 25780ad5095d570db3caa98b0506ab83f20b2404 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 1 Apr 2026 23:24:47 +0900 Subject: [PATCH 3/3] Fix lint --- .../snapshots/integration_test__openapi.snap | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/examples/axum-example/tests/snapshots/integration_test__openapi.snap b/examples/axum-example/tests/snapshots/integration_test__openapi.snap index be6d493..b7d5c7b 100644 --- a/examples/axum-example/tests/snapshots/integration_test__openapi.snap +++ b/examples/axum-example/tests/snapshots/integration_test__openapi.snap @@ -3471,6 +3471,60 @@ expression: "std::fs::read_to_string(\"openapi.json\").unwrap()" "createdAt" ] }, + "SingleRelSchema": { + "type": "object", + "properties": { + "single": { + "$ref": "#/components/schemas/SingleRelSchema_Single" + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username", + "single" + ] + }, + "SingleRelSchema_Single": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema": { + "type": "object", + "properties": { + "singleRel": { + "$ref": "#/components/schemas/SingleSchema_SingleRel", + "nullable": true + }, + "username": { + "type": "string", + "default": "" + } + }, + "required": [ + "username" + ] + }, + "SingleSchema_SingleRel": { + "type": "object", + "properties": { + "username": { + "type": "string" + } + }, + "required": [ + "username" + ] + }, "SkipResponse": { "type": "object", "properties": {