Skip to content

Commit d062576

Browse files
committed
Impl fk with pk
1 parent 9d58c84 commit d062576

4 files changed

Lines changed: 132 additions & 1 deletion

File tree

crates/vespertide-cli/src/commands/export.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ pub fn cmd_export(orm: OrmArg, export_dir: Option<PathBuf>) -> Result<()> {
3232
let config = load_config()?;
3333
let models = load_models_recursive(config.models_dir()).context("load models recursively")?;
3434

35+
// Normalize tables to convert inline constraints (primary_key, foreign_key, etc.) to table-level constraints
36+
let normalized_models: Vec<(TableDef, PathBuf)> = models
37+
.into_iter()
38+
.map(|(table, rel_path)| {
39+
table
40+
.normalize()
41+
.map_err(|e| anyhow::anyhow!("Failed to normalize table '{}': {}", table.name, e))
42+
.map(|normalized| (normalized, rel_path))
43+
})
44+
.collect::<Result<Vec<_>, _>>()?;
45+
3546
let target_root = resolve_export_dir(export_dir, &config);
3647
if !target_root.exists() {
3748
fs::create_dir_all(&target_root)
@@ -40,7 +51,7 @@ pub fn cmd_export(orm: OrmArg, export_dir: Option<PathBuf>) -> Result<()> {
4051

4152
let orm_kind: Orm = orm.into();
4253

43-
for (table, rel_path) in &models {
54+
for (table, rel_path) in &normalized_models {
4455
let code = render_entity(orm_kind, table).map_err(|e| anyhow::anyhow!(e))?;
4556
let out_path = build_output_path(&target_root, rel_path, orm_kind);
4657
if let Some(parent) = out_path.parent() {

crates/vespertide-core/src/schema/reference.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use schemars::JsonSchema;
22
use serde::{Deserialize, Serialize};
33

44
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
5+
#[serde(rename_all = "snake_case")]
56
pub enum ReferenceAction {
67
Cascade,
78
Restrict,

crates/vespertide-exporter/src/seaorm/mod.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,96 @@ mod tests {
466466
constraints: vec![],
467467
indexes: vec![],
468468
})]
469+
#[case("pk_and_fk_together", {
470+
use vespertide_core::schema::foreign_key::{ForeignKeyDef, ForeignKeySyntax};
471+
use vespertide_core::schema::reference::ReferenceAction;
472+
let mut table = TableDef {
473+
name: "article_user".into(),
474+
columns: vec![
475+
ColumnDef {
476+
name: "article_id".into(),
477+
r#type: ColumnType::Simple(SimpleColumnType::Uuid),
478+
nullable: false,
479+
default: None,
480+
comment: None,
481+
primary_key: Some(PrimaryKeySyntax::Bool(true)),
482+
unique: None,
483+
index: Some(vespertide_core::StrOrBoolOrArray::Bool(true)),
484+
foreign_key: Some(ForeignKeySyntax::Object(ForeignKeyDef {
485+
ref_table: "article".into(),
486+
ref_columns: vec!["id".into()],
487+
on_delete: Some(ReferenceAction::Cascade),
488+
on_update: None,
489+
})),
490+
},
491+
ColumnDef {
492+
name: "user_id".into(),
493+
r#type: ColumnType::Simple(SimpleColumnType::Uuid),
494+
nullable: false,
495+
default: None,
496+
comment: None,
497+
primary_key: Some(PrimaryKeySyntax::Bool(true)),
498+
unique: None,
499+
index: Some(vespertide_core::StrOrBoolOrArray::Bool(true)),
500+
foreign_key: Some(ForeignKeySyntax::Object(ForeignKeyDef {
501+
ref_table: "user".into(),
502+
ref_columns: vec!["id".into()],
503+
on_delete: Some(ReferenceAction::Cascade),
504+
on_update: None,
505+
})),
506+
},
507+
ColumnDef {
508+
name: "author_order".into(),
509+
r#type: ColumnType::Simple(SimpleColumnType::Integer),
510+
nullable: false,
511+
default: Some("1".into()),
512+
comment: None,
513+
primary_key: None,
514+
unique: None,
515+
index: None,
516+
foreign_key: None,
517+
},
518+
ColumnDef {
519+
name: "role".into(),
520+
r#type: ColumnType::Complex(vespertide_core::ComplexColumnType::Varchar { length: 20 }),
521+
nullable: false,
522+
default: Some("'contributor'".into()),
523+
comment: None,
524+
primary_key: None,
525+
unique: None,
526+
index: None,
527+
foreign_key: None,
528+
},
529+
ColumnDef {
530+
name: "is_lead".into(),
531+
r#type: ColumnType::Simple(SimpleColumnType::Boolean),
532+
nullable: false,
533+
default: Some("false".into()),
534+
comment: None,
535+
primary_key: None,
536+
unique: None,
537+
index: None,
538+
foreign_key: None,
539+
},
540+
ColumnDef {
541+
name: "created_at".into(),
542+
r#type: ColumnType::Simple(SimpleColumnType::Timestamptz),
543+
nullable: false,
544+
default: Some("now()".into()),
545+
comment: None,
546+
primary_key: None,
547+
unique: None,
548+
index: None,
549+
foreign_key: None,
550+
},
551+
],
552+
constraints: vec![],
553+
indexes: vec![],
554+
};
555+
// Normalize to convert inline constraints to table-level
556+
table = table.normalize().unwrap();
557+
table
558+
})]
469559
fn render_entity_snapshots(#[case] name: &str, #[case] table: TableDef) {
470560
let rendered = render_entity(&table);
471561
with_settings!({ snapshot_suffix => format!("params_{}", name) }, {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
source: crates/vespertide-exporter/src/seaorm/mod.rs
3+
expression: rendered
4+
---
5+
use sea_orm::entity::prelude::*;
6+
7+
#[sea_orm::model]
8+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
9+
#[sea_orm(table_name = "article_user")]
10+
pub struct Model {
11+
#[sea_orm(primary_key, auto_increment = false)]
12+
pub article_id: Uuid,
13+
#[sea_orm(primary_key, auto_increment = false)]
14+
pub user_id: Uuid,
15+
pub author_order: i32,
16+
pub role: String,
17+
pub is_lead: bool,
18+
pub created_at: DateTimeWithTimeZone,
19+
#[sea_orm(belongs_to, from = "article_id", to = "id")]
20+
pub article: HasOne<super::article::Entity>,
21+
#[sea_orm(belongs_to, from = "user_id", to = "id")]
22+
pub user: HasOne<super::user::Entity>,
23+
}
24+
25+
26+
// Index definitions (SeaORM uses Statement builders externally)
27+
// idx_article_user_article_id on [article_id] unique=false
28+
// idx_article_user_user_id on [user_id] unique=false
29+
impl ActiveModelBehavior for ActiveModel {}

0 commit comments

Comments
 (0)