Skip to main content

toasty_driver_integration_suite/tests/
index_unique_collection.rs

1//! Tests for whole-value unique constraints on `Vec<scalar>` fields.
2
3use crate::prelude::*;
4
5#[driver_test(requires(unique_list_index))]
6pub async fn unique_vec_uses_ordered_complete_value(t: &mut Test) -> Result<()> {
7    #[derive(Debug, toasty::Model)]
8    struct Item {
9        #[key]
10        #[auto]
11        id: uuid::Uuid,
12        #[unique]
13        tags: Vec<String>,
14    }
15
16    let mut db = t.setup_db(models!(Item)).await;
17
18    toasty::create!(Item {
19        tags: ["rust", "toasty"],
20    })
21    .exec(&mut db)
22    .await?;
23
24    assert_err!(
25        toasty::create!(Item {
26            tags: ["rust", "toasty"],
27        })
28        .exec(&mut db)
29        .await
30    );
31
32    toasty::create!(Item {
33        tags: ["toasty", "rust"],
34    })
35    .exec(&mut db)
36    .await?;
37    toasty::create!(Item {
38        tags: ["rust", "rust"],
39    })
40    .exec(&mut db)
41    .await?;
42    toasty::create!(Item {
43        tags: Vec::<String>::new(),
44    })
45    .exec(&mut db)
46    .await?;
47
48    assert_err!(
49        toasty::create!(Item {
50            tags: Vec::<String>::new(),
51        })
52        .exec(&mut db)
53        .await
54    );
55
56    Ok(())
57}
58
59#[driver_test(requires(and(unique_list_index, upsert_unique)))]
60pub async fn unique_vec_generated_operations(t: &mut Test) -> Result<()> {
61    #[derive(Debug, toasty::Model)]
62    struct Item {
63        #[key]
64        #[auto]
65        id: uuid::Uuid,
66        #[unique]
67        tags: Vec<String>,
68        name: String,
69    }
70
71    let mut db = t.setup_db(models!(Item)).await;
72    let item = toasty::create!(Item {
73        tags: ["one", "two"],
74        name: "original",
75    })
76    .exec(&mut db)
77    .await?;
78
79    let found = Item::get_by_tags(&mut db, ["one", "two"]).await?;
80    assert_eq!(found.id, item.id);
81
82    let filtered = Item::filter_by_tags(["one", "two"]).exec(&mut db).await?;
83    assert_eq!(filtered.len(), 1);
84
85    Item::update_by_tags(["one", "two"])
86        .tags(["three"])
87        .exec(&mut db)
88        .await?;
89
90    let updated = Item::upsert_by_tags(["three"])
91        .name("updated")
92        .exec(&mut db)
93        .await?;
94    assert_eq!(updated.id, item.id);
95    assert_eq!(updated.name, "updated");
96
97    Item::delete_by_tags(&mut db, ["three"]).await?;
98    assert_none!(
99        Item::filter_by_tags(["three"])
100            .first()
101            .exec(&mut db)
102            .await?
103    );
104
105    Ok(())
106}
107
108#[driver_test(requires(unique_list_index))]
109pub async fn unique_vec_newtype(t: &mut Test) -> Result<()> {
110    #[derive(Debug, toasty::Embed)]
111    struct Tags(Vec<String>);
112
113    #[derive(Debug, toasty::Model)]
114    struct Item {
115        #[key]
116        #[auto]
117        id: uuid::Uuid,
118        #[unique]
119        tags: Tags,
120    }
121
122    let mut db = t.setup_db(models!(Item)).await;
123
124    toasty::create!(Item {
125        tags: Tags(vec!["rust".into(), "toasty".into()]),
126    })
127    .exec(&mut db)
128    .await?;
129
130    assert_err!(
131        toasty::create!(Item {
132            tags: Tags(vec!["rust".into(), "toasty".into()]),
133        })
134        .exec(&mut db)
135        .await
136    );
137
138    let found = Item::get_by_tags(&mut db, Tags(vec!["rust".into(), "toasty".into()])).await?;
139    assert_eq!(found.tags.0, ["rust", "toasty"]);
140
141    Ok(())
142}
143
144#[driver_test(requires(and(vec_scalar, not(unique_list_index))))]
145pub async fn unique_vec_unsupported_backend(t: &mut Test) {
146    #[derive(Debug, toasty::Model)]
147    struct Item {
148        #[key]
149        #[auto]
150        id: uuid::Uuid,
151        #[unique]
152        tags: Vec<String>,
153    }
154
155    let err = assert_err!(t.try_setup_db(models!(Item)).await);
156    assert!(err.is_unsupported_feature());
157
158    let message = err.to_string();
159    assert!(
160        message.contains("#[unique]")
161            && message.contains("Vec<T>")
162            && message.contains("complete collection values"),
163        "unexpected schema-build error: {message}"
164    );
165}
166
167#[driver_test(requires(vec_scalar))]
168pub async fn non_unique_vec_index_is_rejected(t: &mut Test) {
169    #[derive(Debug, toasty::Model)]
170    struct Item {
171        #[key]
172        #[auto]
173        id: uuid::Uuid,
174        #[index]
175        tags: Vec<String>,
176    }
177
178    let err = assert_err!(t.try_setup_db(models!(Item)).await);
179    assert!(err.is_unsupported_feature());
180
181    let message = err.to_string();
182    assert!(
183        message.contains("#[index]") && message.contains("Vec<T>"),
184        "unexpected schema-build error: {message}"
185    );
186}