From bbe1b20c1f980b91f248d19ac48cfaf8825273ed Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Sun, 4 Jan 2026 21:23:45 +0900 Subject: [PATCH] Add comment --- .../changepack_log_HRbJ68r6ZvFw900A3A93w.json | 1 + crates/vespertide-config/src/config.rs | 24 ++++ crates/vespertide-exporter/src/seaorm/mod.rs | 104 ++++++++++++++++++ examples/app/models/media.json | 3 +- examples/app/models/user_media_role.json | 4 +- examples/app/src/models/article.rs | 2 +- examples/app/src/models/article_user.rs | 2 +- examples/app/src/models/media.rs | 1 + examples/app/src/models/user_media_role.rs | 4 +- 9 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 .changepacks/changepack_log_HRbJ68r6ZvFw900A3A93w.json diff --git a/.changepacks/changepack_log_HRbJ68r6ZvFw900A3A93w.json b/.changepacks/changepack_log_HRbJ68r6ZvFw900A3A93w.json new file mode 100644 index 0000000..efc3c94 --- /dev/null +++ b/.changepacks/changepack_log_HRbJ68r6ZvFw900A3A93w.json @@ -0,0 +1 @@ +{"changes":{"crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide/Cargo.toml":"Patch","crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch","crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch"},"note":"Export with comment","date":"2026-01-04T12:23:39.579352900Z"} \ No newline at end of file diff --git a/crates/vespertide-config/src/config.rs b/crates/vespertide-config/src/config.rs index 348b5b0..4eaf6d7 100644 --- a/crates/vespertide-config/src/config.rs +++ b/crates/vespertide-config/src/config.rs @@ -137,3 +137,27 @@ impl VespertideConfig { &self.seaorm } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vespertide_config_default() { + let config = VespertideConfig::default(); + + assert_eq!(config.models_dir, PathBuf::from("models")); + assert_eq!(config.migrations_dir, PathBuf::from("migrations")); + assert_eq!(config.table_naming_case, NameCase::Snake); + assert_eq!(config.column_naming_case, NameCase::Snake); + assert_eq!(config.model_format, FileFormat::Json); + assert_eq!(config.migration_format, FileFormat::Json); + assert_eq!(config.migration_filename_pattern, "%04v_%m"); + assert_eq!(config.model_export_dir, PathBuf::from("src/models")); + assert_eq!( + config.seaorm.extra_enum_derives, + vec!["vespera::Schema".to_string()] + ); + assert!(config.seaorm.extra_model_derives.is_empty()); + } +} diff --git a/crates/vespertide-exporter/src/seaorm/mod.rs b/crates/vespertide-exporter/src/seaorm/mod.rs index 4244c86..8f6a4b9 100644 --- a/crates/vespertide-exporter/src/seaorm/mod.rs +++ b/crates/vespertide-exporter/src/seaorm/mod.rs @@ -107,6 +107,13 @@ pub fn render_entity_with_config( .collect(); model_derives.extend(extra_model_derives); + // Add table description as doc comment + if let Some(ref desc) = table.description { + for line in desc.lines() { + lines.push(format!("/// {}", line)); + } + } + lines.push("#[sea_orm::model]".into()); lines.push(format!("#[derive({})]", model_derives.join(", "))); lines.push(format!("#[sea_orm(table_name = \"{}\")]", table.name)); @@ -178,6 +185,13 @@ fn render_column( let is_indexed = indexed_columns.contains(&column.name); let has_default = column.default.is_some(); + // Add column comment as doc comment + if let Some(ref comment) = column.comment { + for line in comment.lines() { + lines.push(format!(" /// {}", line)); + } + } + // Build attribute parts let mut attrs: Vec = Vec::new(); @@ -2854,4 +2868,94 @@ mod tests { // Should NOT contain vespera::Schema since we explicitly set empty assert!(!result.contains("vespera::Schema")); } + + #[test] + fn test_doc_comments_from_description_and_comment() { + use vespertide_core::schema::primary_key::PrimaryKeySyntax; + + let table = TableDef { + name: "users".into(), + description: Some("User account information table".into()), + columns: vec![ + ColumnDef { + name: "id".into(), + r#type: ColumnType::Simple(SimpleColumnType::Integer), + nullable: false, + default: None, + comment: Some("Unique user identifier".into()), + primary_key: Some(PrimaryKeySyntax::Bool(true)), + unique: None, + index: None, + foreign_key: None, + }, + ColumnDef { + name: "email".into(), + r#type: ColumnType::Simple(SimpleColumnType::Text), + nullable: false, + default: None, + comment: Some("User's email address for login".into()), + primary_key: None, + unique: None, + index: None, + foreign_key: None, + }, + ColumnDef { + name: "name".into(), + r#type: ColumnType::Simple(SimpleColumnType::Text), + nullable: true, + default: None, + comment: None, // No comment + primary_key: None, + unique: None, + index: None, + foreign_key: None, + }, + ], + constraints: vec![], + }; + + let rendered = render_entity(&table); + + // Check table description as doc comment + assert!(rendered.contains("/// User account information table")); + + // Check column comments as doc comments + assert!(rendered.contains("/// Unique user identifier")); + assert!(rendered.contains("/// User's email address for login")); + + // name column has no comment, so no doc comment for it + assert!(!rendered.contains("/// name")); + } + + #[test] + fn test_multiline_doc_comments() { + use vespertide_core::schema::primary_key::PrimaryKeySyntax; + + let table = TableDef { + name: "posts".into(), + description: Some("Blog posts table\nContains all user-submitted content".into()), + columns: vec![ColumnDef { + name: "content".into(), + r#type: ColumnType::Simple(SimpleColumnType::Text), + nullable: false, + default: None, + comment: Some("Post content body\nSupports markdown format".into()), + primary_key: Some(PrimaryKeySyntax::Bool(true)), + unique: None, + index: None, + foreign_key: None, + }], + constraints: vec![], + }; + + let rendered = render_entity(&table); + + // Check multiline table description + assert!(rendered.contains("/// Blog posts table")); + assert!(rendered.contains("/// Contains all user-submitted content")); + + // Check multiline column comment + assert!(rendered.contains("/// Post content body")); + assert!(rendered.contains("/// Supports markdown format")); + } } diff --git a/examples/app/models/media.json b/examples/app/models/media.json index 43552b6..2f452c0 100644 --- a/examples/app/models/media.json +++ b/examples/app/models/media.json @@ -7,7 +7,8 @@ "type": "uuid", "nullable": false, "default": "gen_random_uuid()", - "primary_key": true + "primary_key": true, + "comment": "hello" }, { "name": "name", diff --git a/examples/app/models/user_media_role.json b/examples/app/models/user_media_role.json index 9904a37..5b38e46 100644 --- a/examples/app/models/user_media_role.json +++ b/examples/app/models/user_media_role.json @@ -1,6 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/dev-five-git/vespertide/refs/heads/main/schemas/model.schema.json", "name": "user_media_role", + "description": "hello media role", "columns": [ { "name": "user_id", @@ -12,7 +13,8 @@ "on_delete": "cascade" }, "index": true, - "primary_key": true + "primary_key": true, + "comment": "hello" }, { "name": "media_id", diff --git a/examples/app/src/models/article.rs b/examples/app/src/models/article.rs index 3d03887..614952f 100644 --- a/examples/app/src/models/article.rs +++ b/examples/app/src/models/article.rs @@ -1,7 +1,7 @@ use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, vespera::Schema)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "article_status")] pub enum Status { #[sea_orm(string_value = "draft")] diff --git a/examples/app/src/models/article_user.rs b/examples/app/src/models/article_user.rs index 0ec5ce0..5b6c0db 100644 --- a/examples/app/src/models/article_user.rs +++ b/examples/app/src/models/article_user.rs @@ -1,7 +1,7 @@ use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, vespera::Schema)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "article_user_role")] pub enum Role { #[sea_orm(string_value = "lead")] diff --git a/examples/app/src/models/media.rs b/examples/app/src/models/media.rs index e9429cc..028c742 100644 --- a/examples/app/src/models/media.rs +++ b/examples/app/src/models/media.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "media")] pub struct Model { + /// hello #[sea_orm(primary_key, default_value = "gen_random_uuid()")] pub id: Uuid, pub name: String, diff --git a/examples/app/src/models/user_media_role.rs b/examples/app/src/models/user_media_role.rs index 5677946..bcb43c5 100644 --- a/examples/app/src/models/user_media_role.rs +++ b/examples/app/src/models/user_media_role.rs @@ -1,7 +1,7 @@ use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, vespera::Schema)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "user_media_role_role")] pub enum Role { #[sea_orm(string_value = "owner")] @@ -12,10 +12,12 @@ pub enum Role { Reporter, } +/// hello media role #[sea_orm::model] #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] #[sea_orm(table_name = "user_media_role")] pub struct Model { + /// hello #[sea_orm(primary_key)] pub user_id: Uuid, #[sea_orm(primary_key)]