starfish_core/schema/
relation.rs1use super::{format_node_table_name, Schema};
4use crate::{entities::relation, lang::RelationJson};
5use sea_orm::{
6 ActiveModelTrait, ConnectionTrait, DbConn, DbErr, DeriveIden, ForeignKeyAction, Set,
7};
8use sea_query::{Alias, ColumnDef, ForeignKey, Index, Table};
9
10impl Schema {
11 pub async fn create_relation(db: &DbConn, relation_json: RelationJson) -> Result<(), DbErr> {
13 relation::ActiveModel {
14 name: Set(relation_json.name.clone()),
15 from_entity: Set(relation_json.from_entity.clone()),
16 to_entity: Set(relation_json.to_entity.clone()),
17 directed: Set(relation_json.directed),
18 ..Default::default()
19 }
20 .insert(db)
21 .await?;
22
23 let edge_name = relation_json.name.as_str();
24 let from_entity = format_node_table_name(&relation_json.from_entity);
25 let to_entity = format_node_table_name(&relation_json.to_entity);
26
27 Self::add_in_connectivity_columns(db, edge_name, to_entity.as_str()).await?;
28 Self::add_out_connectivity_columns(db, edge_name, from_entity.as_str()).await?;
29
30 Self::create_edge_table(db, &relation_json, from_entity, to_entity).await
31 }
32
33 async fn add_in_connectivity_columns(
34 db: &DbConn,
35 edge_name: &str,
36 node_table: &str,
37 ) -> Result<(), DbErr> {
38 for col in [
39 "in_conn",
40 "in_conn_compound",
41 "in_conn_complex03",
42 "in_conn_complex05",
43 "in_conn_complex07",
44 ] {
45 Self::add_connectivity_column(db, node_table, &format!("{}_{}", edge_name, col))
46 .await?;
47 }
48
49 Ok(())
50 }
51
52 async fn add_out_connectivity_columns(
53 db: &DbConn,
54 edge_name: &str,
55 node_table: &str,
56 ) -> Result<(), DbErr> {
57 Self::add_connectivity_column(db, node_table, &format!("{}_out_conn", edge_name)).await
58 }
59
60 async fn add_connectivity_column(
61 db: &DbConn,
62 node_table: &str,
63 col: &str,
64 ) -> Result<(), DbErr> {
65 let builder = db.get_database_backend();
66 let mut stmt = Table::alter();
67 stmt.table(Alias::new(node_table)).add_column(
68 ColumnDef::new(Alias::new(col))
69 .double()
70 .not_null()
71 .default(0.0f64),
72 );
73 db.execute(builder.build(&stmt)).await?;
74
75 let mut stmt = Index::create();
76 stmt.name(&format!("idx-{}-{}", node_table, col))
77 .table(Alias::new(node_table))
78 .col(Alias::new(col));
79 db.execute(builder.build(&stmt)).await?;
80
81 Ok(())
82 }
83
84 async fn create_edge_table(
85 db: &DbConn,
86 relation_json: &RelationJson,
87 from_entity: String,
88 to_entity: String,
89 ) -> Result<(), DbErr> {
90 let table = Alias::new(relation_json.get_table_name().as_str());
91 let mut stmt = Table::create();
92 stmt.table(table.clone())
93 .col(
94 ColumnDef::new(Alias::new("id"))
95 .integer()
96 .not_null()
97 .auto_increment()
98 .primary_key(),
99 )
100 .col(ColumnDef::new(Alias::new("from_node")).string().not_null())
101 .col(ColumnDef::new(Alias::new("to_node")).string().not_null())
102 .index(
103 Index::create()
104 .name(&format!("idx-{}-{}", table.to_string(), "from_node"))
105 .table(table.clone())
106 .col(Alias::new("from_node")),
107 )
108 .index(
109 Index::create()
110 .name(&format!("idx-{}-{}", table.to_string(), "to_node"))
111 .table(table.clone())
112 .col(Alias::new("to_node")),
113 )
114 .index(
115 Index::create()
116 .unique()
117 .name(&format!(
118 "idx-{}-from_node-to_node",
119 relation_json.get_table_name()
120 ))
121 .col(Alias::new("from_node"))
122 .col(Alias::new("to_node")),
123 )
124 .foreign_key(
125 ForeignKey::create()
126 .name(&format!(
127 "fk-{}-from-{}",
128 relation_json.get_table_name(),
129 from_entity
130 ))
131 .from_tbl(Alias::new(relation_json.get_table_name().as_str()))
132 .from_col(Alias::new("from_node"))
133 .to_tbl(Alias::new(from_entity.as_str()))
134 .to_col(Alias::new("name"))
135 .on_delete(ForeignKeyAction::Cascade),
136 )
137 .foreign_key(
138 ForeignKey::create()
139 .name(&format!(
140 "fk-{}-to-{}",
141 relation_json.get_table_name(),
142 to_entity
143 ))
144 .from_tbl(Alias::new(relation_json.get_table_name().as_str()))
145 .from_col(Alias::new("to_node"))
146 .to_tbl(Alias::new(to_entity.as_str()))
147 .to_col(Alias::new("name"))
148 .on_delete(ForeignKeyAction::Cascade),
149 );
150
151 let builder = db.get_database_backend();
152 db.execute(builder.build(&stmt)).await?;
153
154 Ok(())
155 }
156}