diff --git a/crates/erp-plugin/src/dynamic_table.rs b/crates/erp-plugin/src/dynamic_table.rs index f8dae82..090b4bd 100644 --- a/crates/erp-plugin/src/dynamic_table.rs +++ b/crates/erp-plugin/src/dynamic_table.rs @@ -956,6 +956,7 @@ mod tests { }, ], indexes: vec![], + relations: vec![], }; let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity); @@ -996,6 +997,7 @@ mod tests { ..PluginField::default_for_field() }], indexes: vec![], + relations: vec![], }; let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity); diff --git a/crates/erp-plugin/src/manifest.rs b/crates/erp-plugin/src/manifest.rs index 0a0108a..56d6d0e 100644 --- a/crates/erp-plugin/src/manifest.rs +++ b/crates/erp-plugin/src/manifest.rs @@ -43,6 +43,8 @@ pub struct PluginEntity { pub fields: Vec, #[serde(default)] pub indexes: Vec, + #[serde(default)] + pub relations: Vec, } /// 字段校验规则 @@ -156,6 +158,23 @@ pub struct PluginIndex { pub unique: bool, } +/// 级联删除策略 +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum OnDeleteStrategy { + Nullify, // 置空外键字段 + Cascade, // 级联软删除 + Restrict, // 存在关联时拒绝删除 +} + +/// 实体关联关系声明 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PluginRelation { + pub entity: String, + pub foreign_key: String, + pub on_delete: OnDeleteStrategy, +} + /// 事件订阅配置 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PluginEvents { @@ -690,4 +709,41 @@ no_cycle = true assert_eq!(field.no_cycle, Some(true)); assert_eq!(field.ref_entity.as_deref(), Some("customer")); } + + #[test] + fn parse_entity_with_relations() { + let toml = r#" +[metadata] +id = "test" +name = "Test" +version = "0.1.0" + +[schema] +[[schema.entities]] +name = "customer" +display_name = "客户" + +[[schema.entities.fields]] +name = "code" +field_type = "string" +required = true +display_name = "编码" + +[[schema.entities.relations]] +entity = "contact" +foreign_key = "customer_id" +on_delete = "cascade" + +[[schema.entities.relations]] +entity = "customer_tag" +foreign_key = "customer_id" +on_delete = "cascade" +"#; + let manifest = parse_manifest(toml).unwrap(); + let entity = &manifest.schema.unwrap().entities[0]; + assert_eq!(entity.relations.len(), 2); + assert_eq!(entity.relations[0].entity, "contact"); + assert_eq!(entity.relations[0].foreign_key, "customer_id"); + assert!(matches!(entity.relations[0].on_delete, OnDeleteStrategy::Cascade)); + } }