Skip to main content

toasty_driver_integration_suite/tests/
select_projection.rs

1use crate::prelude::*;
2
3#[derive(Debug, toasty::Model)]
4struct Item {
5    #[key]
6    id: i64,
7    name: String,
8    quantity: i64,
9}
10
11async fn setup(test: &mut Test) -> toasty::Db {
12    let mut db = test.setup_db(models!(Item)).await;
13
14    toasty::create!(Item::[
15        { id: 1_i64, name: "Alice",   quantity: 7_i64  },
16        { id: 2_i64, name: "Bob",     quantity: 3_i64  },
17        { id: 3_i64, name: "Charlie", quantity: 11_i64 },
18    ])
19    .exec(&mut db)
20    .await
21    .unwrap();
22
23    db
24}
25
26/// `.select(field)` on a `Query<List<Item>>` returns a `Query<List<String>>`
27/// whose `.exec()` produces a `Vec<String>` of the projected column.
28#[driver_test]
29pub async fn select_single_field(test: &mut Test) -> Result<()> {
30    let mut db = setup(test).await;
31
32    let mut names: Vec<String> = Item::all()
33        .select(Item::fields().name())
34        .exec(&mut db)
35        .await?;
36
37    names.sort();
38
39    assert_eq!(
40        names,
41        vec![
42            "Alice".to_string(),
43            "Bob".to_string(),
44            "Charlie".to_string()
45        ]
46    );
47
48    Ok(())
49}
50
51/// `.select((f1, f2))` returns a `Query<List<(T1, T2)>>` whose `.exec()`
52/// produces a `Vec` of tuples.
53#[driver_test]
54pub async fn select_tuple(test: &mut Test) -> Result<()> {
55    let mut db = setup(test).await;
56
57    let mut pairs: Vec<(i64, String)> = Item::all()
58        .select((Item::fields().id(), Item::fields().name()))
59        .exec(&mut db)
60        .await?;
61
62    pairs.sort_by_key(|(id, _)| *id);
63
64    assert_eq!(
65        pairs,
66        vec![
67            (1_i64, "Alice".to_string()),
68            (2_i64, "Bob".to_string()),
69            (3_i64, "Charlie".to_string()),
70        ]
71    );
72
73    Ok(())
74}
75
76/// `.select(...)` composes with `.filter(...)`: the projection sees only rows
77/// matching the filter expression.
78#[driver_test]
79pub async fn select_with_filter(test: &mut Test) -> Result<()> {
80    let mut db = setup(test).await;
81
82    let mut names: Vec<String> = Item::filter(Item::fields().quantity().gt(5_i64))
83        .select(Item::fields().name())
84        .exec(&mut db)
85        .await?;
86
87    names.sort();
88
89    assert_eq!(names, vec!["Alice".to_string(), "Charlie".to_string()]);
90
91    Ok(())
92}
93
94/// `.select(...).first()` lifts the outer container to `Option<T>`.
95#[driver_test]
96pub async fn select_first(test: &mut Test) -> Result<()> {
97    let mut db = setup(test).await;
98
99    let name: Option<String> = Item::filter(Item::fields().id().eq(2_i64))
100        .select(Item::fields().name())
101        .first()
102        .exec(&mut db)
103        .await?;
104
105    assert_eq!(name.as_deref(), Some("Bob"));
106
107    Ok(())
108}
109
110/// `.select(...).first()` returns `None` when no rows match.
111#[driver_test]
112pub async fn select_first_no_match(test: &mut Test) -> Result<()> {
113    let mut db = setup(test).await;
114
115    let name: Option<String> = Item::filter(Item::fields().id().eq(999_i64))
116        .select(Item::fields().name())
117        .first()
118        .exec(&mut db)
119        .await?;
120
121    assert_eq!(name, None);
122
123    Ok(())
124}