1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! [`filter_keys`]: the predicate an action's `run` writes its records through in one statement.
use ;
use cratepk_set_filter;
/// The predicate selecting each of `records` by its primary key, so that an action writes the
/// same change to all of them in one statement rather than one per record:
///
/// ```rust
/// # #[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns)]
/// # struct Post {
/// # #[key] #[auto] id: uuid::Uuid,
/// # title: String,
/// # status: String,
/// # }
/// # use tablo_core::{Action, NoForm, Resource, filter_keys};
/// # use toasty::Executor;
/// # use topcoat::{Result, context::Cx};
/// # struct PostResource;
/// # impl Resource for PostResource {
/// # type Model = Post;
/// # type Form = NoForm<Post>;
/// # }
/// # struct Publish;
/// # impl Action<PostResource> for Publish {
/// # type Input = ();
/// # const NAME: &'static str = "publish";
/// async fn run(
/// _cx: &Cx,
/// posts: &[Post],
/// _: (),
/// ex: &mut dyn Executor,
/// ) -> Result<tablo_core::Outcome, tablo_core::WriteError<std::convert::Infallible>> {
/// Post::filter(filter_keys(posts))
/// .update()
/// .status("published".to_string())
/// .exec(ex)
/// .await?;
/// Ok(tablo_core::Outcome::done())
/// }
/// # }
/// ```
///
/// A single key selects through one `IN` list, a composite key through one equality per record,
/// and no record selects no row. The predicate scopes nothing itself: it selects exactly the
/// records given, which for an [`Action`](crate::Action) the pipeline loaded through the
/// tenant-scoped query and checked against the policy, no more than
/// [`Limits::bulk_records`](crate::Limits::bulk_records) of them.
///
/// The statement binds a value per key, which databases bound: SQLite takes 32,766 values, and
/// nests the equalities of composite keys no more than 1,000 deep. A set the caller loaded itself,
/// as a [`HeaderAction`](crate::HeaderAction) does, has no such bound: write it in chunks, a few
/// hundred records each.