Skip to content

Commit ca6eff7

Browse files
authored
Add Many.set (#357)
1 parent f06a128 commit ca6eff7

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

butane/tests/many.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,20 @@ async fn load_sorted_from_many(conn: ConnectionAsync) {
5454
"This post is about a fast cat.",
5555
&cats_blog,
5656
);
57+
post.save(&conn).await.unwrap();
58+
5759
let tag_fast = create_tag(&conn, "fast").await;
5860
let tag_cat = create_tag(&conn, "cat").await;
5961
let tag_european = create_tag(&conn, "european").await;
62+
let tags = vec![tag_fast, tag_cat, tag_european];
6063

61-
post.tags.add(&tag_fast).unwrap();
62-
post.tags.add(&tag_cat).unwrap();
63-
post.tags.add(&tag_european).unwrap();
64-
post.save(&conn).await.unwrap();
64+
post.tags.set(&conn, tags).await.unwrap();
65+
66+
let saved_tags: Vec<&Tag> = post.tags.get().unwrap().into_iter().collect();
67+
assert_eq!(saved_tags.len(), 3);
68+
assert_eq!(saved_tags[0].tag, "fast");
69+
assert_eq!(saved_tags[1].tag, "cat");
70+
assert_eq!(saved_tags[2].tag, "european");
6571

6672
let post2 = Post::get(&conn, post.id).await.unwrap();
6773
let mut tag_iter = post2
@@ -72,6 +78,7 @@ async fn load_sorted_from_many(conn: ConnectionAsync) {
7278
assert_eq!(tag_iter.next().unwrap().tag, "cat");
7379
assert_eq!(tag_iter.next().unwrap().tag, "european");
7480
assert_eq!(tag_iter.next().unwrap().tag, "fast");
81+
assert!(tag_iter.next().is_none());
7582

7683
let post3 = Post::get(&conn, post.id).await.unwrap();
7784
let mut tag_iter = post3
@@ -82,6 +89,7 @@ async fn load_sorted_from_many(conn: ConnectionAsync) {
8289
assert_eq!(tag_iter.next().unwrap().tag, "fast");
8390
assert_eq!(tag_iter.next().unwrap().tag, "european");
8491
assert_eq!(tag_iter.next().unwrap().tag, "cat");
92+
assert!(tag_iter.next().is_none());
8593
}
8694

8795
#[butane_test]

butane_core/src/many.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,23 +198,34 @@ where
198198
async(feature = "async")
199199
)]
200200
pub trait ManyOps<T: DataObject> {
201+
/// Save all unsaved relation changes to the backend.
202+
///
201203
/// Used by macro-generated code. You do not need to call this directly.
204+
///
205+
/// This will insert added values first, and then remove the removed values.
206+
/// Use inside a transaction to provide atomicity.
202207
async fn save(&mut self, conn: &impl ConnectionMethods) -> Result<()>;
203208

204-
/// Delete all references from the database, and any unsaved additions.
209+
/// Delete all references from the backend, and any unsaved additions.
210+
///
211+
/// This operation is atomic.
205212
async fn delete(&mut self, conn: &impl ConnectionMethods) -> Result<()>;
206213

207-
/// Loads the values referred to by this many relationship from the
208-
/// database if necessary and returns a reference to them.
214+
/// Overwrite the references in the backend, and clears unsaved additions.
215+
///
216+
/// This will call `delete()` first, and then insert the items scheduled to be added.
217+
/// Use inside a transaction to provide atomicity.
218+
async fn set(&mut self, conn: &impl ConnectionMethods, values: Vec<T>) -> Result<()>;
219+
220+
/// Loads the values referred to by this many relationship from the backend if necessary.
209221
async fn load<'a>(
210222
&'a self,
211223
conn: &impl ConnectionMethods,
212224
) -> Result<impl Iterator<Item = &'a T>>
213225
where
214226
T: 'a;
215227

216-
/// Loads and orders the values referred to by this many relationship from a
217-
/// database if necessary and returns a reference to them.
228+
/// Loads and orders the values referred to by this many relationship from the backend if necessary.
218229
async fn load_ordered<'a>(
219230
&'a self,
220231
conn: &impl ConnectionMethods,
@@ -274,6 +285,18 @@ impl<T: DataObject> ManyOps<T> for Many<T> {
274285
Ok(())
275286
}
276287

288+
async fn set(&mut self, conn: &impl ConnectionMethods, values: Vec<T>) -> Result<()> {
289+
ManyOps::delete(self, conn).await?;
290+
291+
for value in &values {
292+
self.add(value)?;
293+
}
294+
ManyOps::save(self, conn).await?;
295+
296+
self.all_values = OnceLock::from(values);
297+
Ok(())
298+
}
299+
277300
async fn load<'a>(
278301
&'a self,
279302
conn: &impl ConnectionMethods,

0 commit comments

Comments
 (0)