Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_HRbJ68r6ZvFw900A3A93w.json
Original file line number Diff line number Diff line change
@@ -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"}
24 changes: 24 additions & 0 deletions crates/vespertide-config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
104 changes: 104 additions & 0 deletions crates/vespertide-exporter/src/seaorm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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<String> = Vec::new();

Expand Down Expand Up @@ -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"));
}
}
3 changes: 2 additions & 1 deletion examples/app/models/media.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"type": "uuid",
"nullable": false,
"default": "gen_random_uuid()",
"primary_key": true
"primary_key": true,
"comment": "hello"
},
{
"name": "name",
Expand Down
4 changes: 3 additions & 1 deletion examples/app/models/user_media_role.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -12,7 +13,8 @@
"on_delete": "cascade"
},
"index": true,
"primary_key": true
"primary_key": true,
"comment": "hello"
},
{
"name": "media_id",
Expand Down
2 changes: 1 addition & 1 deletion examples/app/src/models/article.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion examples/app/src/models/article_user.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand Down
1 change: 1 addition & 0 deletions examples/app/src/models/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion examples/app/src/models/user_media_role.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand All @@ -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)]
Expand Down