Skip to main content

toasty_driver_integration_suite/tests/
select_projection_has_many.rs

1//! `.select(...)` projection through a `HasMany` relation field.
2//!
3//! Field handles for `HasMany` relations return
4//! `<Target as Relation>::ManyField<__Origin>` (the macro-generated
5//! `*FieldList` struct).  An `IntoExpr<List<TargetModel>>` impl on that
6//! struct lets the field handle flow through `.select(...)` the same way
7//! `BelongsTo`/`HasOne` handles do; each parent row projects to a list of
8//! related rows, and the executor decodes the result as `Vec<Vec<Target>>`.
9
10use crate::prelude::*;
11
12#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to), requires(sql))]
13pub async fn select_has_many_basic(t: &mut Test) -> Result<()> {
14    let mut db = setup(t).await;
15
16    toasty::create!(User {
17        name: "Alice",
18        todos: [Todo::create().title("alpha"), Todo::create().title("beta"),],
19    })
20    .exec(&mut db)
21    .await?;
22
23    let todos_per_user: Vec<Vec<Todo>> = User::all()
24        .select(User::fields().todos())
25        .exec(&mut db)
26        .await?;
27
28    assert_eq!(todos_per_user.len(), 1);
29    let mut titles: Vec<String> = todos_per_user[0].iter().map(|p| p.title.clone()).collect();
30    titles.sort();
31    assert_eq!(titles, vec!["alpha".to_string(), "beta".to_string()]);
32
33    Ok(())
34}
35
36#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to), requires(sql))]
37pub async fn select_has_many_with_filter(t: &mut Test) -> Result<()> {
38    let mut db = setup(t).await;
39
40    toasty::create!(User {
41        name: "Alice",
42        todos: [Todo::create().title("alpha")],
43    })
44    .exec(&mut db)
45    .await?;
46    toasty::create!(User {
47        name: "Bob",
48        todos: [
49            Todo::create().title("beta one"),
50            Todo::create().title("beta two"),
51        ],
52    })
53    .exec(&mut db)
54    .await?;
55
56    let todos_per_user: Vec<Vec<Todo>> = User::filter(User::fields().name().eq("Bob"))
57        .select(User::fields().todos())
58        .exec(&mut db)
59        .await?;
60
61    assert_eq!(todos_per_user.len(), 1);
62    let mut titles: Vec<String> = todos_per_user[0].iter().map(|p| p.title.clone()).collect();
63    titles.sort();
64    assert_eq!(titles, vec!["beta one".to_string(), "beta two".to_string()]);
65
66    Ok(())
67}
68
69#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to), requires(sql))]
70pub async fn select_has_many_first(t: &mut Test) -> Result<()> {
71    let mut db = setup(t).await;
72
73    toasty::create!(User {
74        name: "Alice",
75        todos: [Todo::create().title("alpha"), Todo::create().title("beta"),],
76    })
77    .exec(&mut db)
78    .await?;
79
80    let todos: Option<Vec<Todo>> = User::filter(User::fields().name().eq("Alice"))
81        .select(User::fields().todos())
82        .first()
83        .exec(&mut db)
84        .await?;
85
86    let todos = todos.expect("first() returned None for a matching user");
87    let mut titles: Vec<String> = todos.iter().map(|p| p.title.clone()).collect();
88    titles.sort();
89    assert_eq!(titles, vec!["alpha".to_string(), "beta".to_string()]);
90
91    Ok(())
92}