Skip to content

Commit bde6631

Browse files
committed
[SeaORM] Update
1 parent ab0e0cd commit bde6631

File tree

3 files changed

+183
-27
lines changed

3 files changed

+183
-27
lines changed

SeaORM/docs/06-relation/04-complex-relations.md

Lines changed: 146 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ assert_eq!(
7979

8080
## Self Referencing Relations
8181

82+
### Belongs To
83+
8284
```rust title="staff.rs"
8385
use sea_orm::entity::prelude::*;
8486

8587
#[sea_orm::model]
86-
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
88+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
8789
#[sea_orm(table_name = "staff")]
8890
pub struct Model {
8991
#[sea_orm(primary_key)]
@@ -93,37 +95,76 @@ pub struct Model {
9395
#[sea_orm(
9496
self_ref,
9597
relation_enum = "ReportsTo",
98+
relation_reverse = "Manages",
9699
from = "reports_to_id",
97100
to = "id"
98101
)]
99102
pub reports_to: HasOne<Entity>,
103+
#[sea_orm(self_ref, relation_enum = "Manages", relation_reverse = "ReportsTo")]
104+
pub manages: HasMany<Entity>,
100105
}
101106

102107
impl ActiveModelBehavior for ActiveModel {}
103108
```
104109

105-
### Entity Loader
110+
(or using `compact_model` shim)
111+
112+
```rust title="staff.rs"
113+
use sea_orm::entity::prelude::*;
114+
115+
#[sea_orm::compact_model]
116+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
117+
#[sea_orm(table_name = "staff")]
118+
pub struct Model {
119+
#[sea_orm(primary_key)]
120+
pub id: i32,
121+
pub name: String,
122+
pub reports_to_id: Option<i32>,
123+
#[sea_orm(self_ref, relation_enum = "ReportsTo")]
124+
pub reports_to: HasOne<Entity>,
125+
#[sea_orm(self_ref, relation_enum = "Manages")]
126+
pub manages: HasMany<Entity>,
127+
}
128+
129+
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
130+
pub enum Relation {
131+
#[sea_orm(belongs_to = "Entity", from = "Column::ReportsToId", to = "Column::Id")]
132+
ReportsTo,
133+
#[sea_orm(has_many = "Entity", via_rel = "Relation::ReportsTo")]
134+
Manages,
135+
}
136+
137+
impl ActiveModelBehavior for ActiveModel {}
138+
```
139+
140+
#### Entity Loader
106141

107142
```rust
108-
let staff = staff::Entity::load()
109-
.with(staff::Relation::ReportsTo)
143+
let staff = staff_compact::Entity::load()
144+
.with(staff_compact::Relation::ReportsTo)
145+
.with(staff_compact::Relation::Manages)
110146
.all(db)
111147
.await?;
112148

113149
assert_eq!(staff[0].name, "Alan");
114150
assert_eq!(staff[0].reports_to, None);
151+
assert_eq!(staff[0].manages[0].name, "Ben");
152+
assert_eq!(staff[0].manages[1].name, "Alice");
115153

116154
assert_eq!(staff[1].name, "Ben");
117155
assert_eq!(staff[1].reports_to.as_ref().unwrap().name, "Alan");
156+
assert!(staff[1].manages.is_empty());
118157

119158
assert_eq!(staff[2].name, "Alice");
120-
assert_eq!(staff[2].reports_to.as_ref().unwrap().name, "Alan");
159+
assert_eq!(staff[1].reports_to.as_ref().unwrap().name, "Alan");
160+
assert!(staff[2].manages.is_empty());
121161

122162
assert_eq!(staff[3].name, "Elle");
123163
assert_eq!(staff[3].reports_to, None);
164+
assert!(staff[3].manages.is_empty());
124165
```
125166

126-
### Model Loader
167+
#### Model Loader
127168

128169
```rust
129170
let staff = staff::Entity::find()
@@ -139,10 +180,10 @@ assert_eq!(staff[0].name, "Alan");
139180
assert_eq!(reports_to[0], None);
140181

141182
assert_eq!(staff[1].name, "Ben");
142-
assert_eq!(reports_to[1].unwrap().name, "Alan");
183+
assert_eq!(reports_to[1].as_ref().unwrap().name, "Alan");
143184

144185
assert_eq!(staff[2].name, "Alice");
145-
assert_eq!(reports_to[2].unwrap().name, "Alan");
186+
assert_eq!(reports_to[2].as_ref().unwrap().name, "Alan");
146187

147188
assert_eq!(staff[3].name, "Elle");
148189
assert_eq!(reports_to[3], None);
@@ -152,11 +193,7 @@ It can work in reverse too.
152193

153194
```rust
154195
let manages = staff
155-
.load_self_rev(
156-
staff::Entity::find().order_by_asc(staff::Column::Id),
157-
staff::Relation::ReportsTo,
158-
db,
159-
)
196+
.load_self_many(staff::Entity, staff::Relation::Manages, db)
160197
.await?;
161198

162199
assert_eq!(staff[0].name, "Alan");
@@ -174,6 +211,102 @@ assert_eq!(staff[3].name, "Elle");
174211
assert_eq!(manages[3].len(), 0);
175212
```
176213

214+
### Has Many (M-N)
215+
216+
```rust title="user.rs"
217+
#[sea_orm::model]
218+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
219+
#[sea_orm(table_name = "user")]
220+
pub struct Model {
221+
#[sea_orm(primary_key)]
222+
pub id: i32,
223+
pub name: String,
224+
#[sea_orm(self_ref, via = "user_follower", from = "User", to = "Follower")]
225+
pub followers: HasMany<Entity>,
226+
#[sea_orm(self_ref, via = "user_follower", reverse)]
227+
pub following: HasMany<Entity>,
228+
}
229+
```
230+
231+
```rust title="user_follower.rs"
232+
#[sea_orm::model]
233+
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
234+
#[sea_orm(table_name = "user_follower")]
235+
pub struct Model {
236+
#[sea_orm(primary_key)]
237+
pub user_id: i32,
238+
#[sea_orm(primary_key)]
239+
pub follower_id: i32,
240+
#[sea_orm(belongs_to, from = "user_id", to = "id")]
241+
pub user: Option<super::user::Entity>,
242+
#[sea_orm(belongs_to, relation_enum = "Follower", from = "follower_id", to = "id")]
243+
pub follower: Option<super::user::Entity>,
244+
}
245+
```
246+
247+
(or with `compact_model`)
248+
249+
```rust
250+
#[sea_orm::compact_model]
251+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
252+
#[sea_orm(table_name = "user")]
253+
pub struct Model {
254+
#[sea_orm(primary_key)]
255+
pub id: i32,
256+
pub name: String,
257+
#[sea_orm(self_ref, via = "user_follower")]
258+
pub followers: HasMany<Entity>,
259+
#[sea_orm(self_ref, via = "user_follower", reverse)]
260+
pub following: HasMany<Entity>,
261+
}
262+
263+
impl RelatedSelfVia<super::user_follower::Entity> for Entity {
264+
fn to() -> RelationDef {
265+
super::user_follower::Relation::Follower.def()
266+
}
267+
fn via() -> RelationDef {
268+
super::user_follower::Relation::User.def().rev()
269+
}
270+
}
271+
```
272+
273+
#### Entity Loader
274+
275+
Join paths:
276+
277+
```rust
278+
user -> profile
279+
-> user_follower -> user -> profile
280+
-> user_follower (reverse) -> user -> profile
281+
```
282+
283+
```rust
284+
let users = user::Entity::load()
285+
.with(profile::Entity)
286+
.with((user_follower::Entity, profile::Entity))
287+
.with((user_follower::Entity::REVERSE, profile::Entity))
288+
.all(db)
289+
.await?;
290+
291+
assert_eq!(users[1].profile, bob.profile);
292+
assert_eq!(users[1].followers.len(), 1);
293+
assert_eq!(users[1].followers[0], sam);
294+
assert_eq!(users[1].following.len(), 1);
295+
assert_eq!(users[1].following[0], alice);
296+
```
297+
298+
#### Model Loader
299+
300+
```rust
301+
let users = user::Entity::find().all(db).await?;
302+
let followers = users.load_self_via(user_follower::Entity, db).await?;
303+
let following = users.load_self_via_rev(user_follower::Entity, db).await?;
304+
305+
assert_eq!(users[1], bob);
306+
assert_eq!(followers[1], [sam.clone()]);
307+
assert_eq!(following[1], [alice.clone()]);
308+
```
309+
177310
## Diamond Relations
178311

179312
Sometimes there exist multiple relations between a pair of entities. Here we take the simplest example, where `Bakery` can have multiple `Worker`.

SeaORM/src/components/HomepageExample.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,32 @@ smart_user
6060
posts: HasMany::Loaded(vec![post::ModelEx {
6161
title: "Nice weather".into(),
6262
tags: HasMany::Loaded(vec![tag::ModelEx {
63-
tag: "diary".into(),
63+
tag: "sunny".into(),
6464
}]),
6565
}]),
6666
};`,
6767
},
68+
{
69+
title: 'Nested ActiveModel',
70+
summary: `Persist an entire object graph: user, profile (1-1), posts (1-N), and tags (M-N) in a single operation using a fluent builder API. SeaORM automatically determines the dependencies and inserts or deletes objects in the correct order.`,
71+
code: `let user = user::ActiveModel::builder()
72+
.set_name("Bob")
73+
.set_email("[email protected]")
74+
.set_profile(profile::ActiveModel::builder().set_picture("image.jpg"))
75+
.add_post(
76+
post::ActiveModel::builder()
77+
.set_title("Nice weather")
78+
.add_tag(tag::ActiveModel::builder().set_tag("sunny")),
79+
)
80+
.save(db)
81+
.await?;`
82+
},
6883
{
6984
title: 'Entity First Workflow',
7085
summary: `SeaORM 2.0 supports a first-class Entity First Workflow: simply define new entities or add columns to existing ones, and SeaORM will automatically detect the changes and create the new tables, columns, unique keys, and foreign keys.`,
71-
code: `let item = Item { name: "Bob" }; // nested parameter access
72-
let ids = [2, 3, 4]; // expanded by the .. operator
73-
74-
let user: Option<user::Model> = user::Entity::find()
75-
.from_raw_sql(raw_sql!(
76-
Sqlite,
77-
r#"SELECT "id", "name" FROM "user"
78-
WHERE "name" LIKE {item.name}
79-
AND "id" in ({..ids})
80-
"#
81-
))
82-
.one(db)
83-
.await?;`
86+
code: `// SeaORM resolves foreign key dependencies and creates the tables in topological order.
87+
// Requires the entity-registry and schema-sync feature flags.
88+
db.get_schema_registry("my_crate::entity::*").sync(db).await;`
8489
},
8590
{
8691
title: 'Ergonomic Raw SQL',

SeaORM/src/components/HomepageFeatures.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ import styles from './HomepageFeatures.module.css';
44
import { MdCloud, MdCheckCircle, MdFlashOn, MdFlight } from "react-icons/md";
55

66
const FeatureList = [
7+
{
8+
title: 'Advanced Relations',
9+
icon: <MdFlashOn size={26} />,
10+
description: (
11+
<>
12+
Model complex relationships 1-1, 1-N, M-N, and even self-referential in a high-level, conceptual way.
13+
</>
14+
),
15+
},
16+
{
17+
title: 'Familiar Concepts',
18+
icon: <MdFlight size={26} />,
19+
description: (
20+
<>
21+
Inspired by popular ORMs in the Ruby, Python, and Node.js ecosystem, SeaORM offers a developer experience that feels instantly recognizable.
22+
</>
23+
),
24+
},
725
{
826
title: 'Feature Rich',
927
icon: <MdCloud size={26} />,

0 commit comments

Comments
 (0)