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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! The application's features, one directory each.
//!
//! A module owns everything one feature needs: its routes, its controller, its
//! migrations, the permissions that guard it, and the settings that configure
//! it. The alternative — a directory per technical layer, every controller
//! together and every model together — is what this application had, and the
//! cost of it is that changing one feature means opening six files in four
//! directories and nothing in the tree says those six belong together.
//!
//! **Nothing is discovered.** `all()` below is a hand-written list, the way
//! `main.rs` is. A module that registers itself by existing is a module whose
//! registration nobody can find.
//!
//! Modules may use `support` and each other only downward and only where the
//! edge is written down. Today there are none: `backup` uses `support` and
//! nothing else uses `backup`, which is why it went first.
use Plugin;
/// A feature, and everything it needs to work.
///
/// Extends `Plugin`, which already carries routes, middleware and state. The
/// four below are the parts a plugin cannot register today because the
/// application collects them centrally — so they are collected from here
/// instead, and `main.rs` flattens the list rather than naming each feature
/// four times.
/// Every module, in the order they are registered and migrated.
/// Every migration the modules own, flattened for `App::migrations`.
/// The migrations belonging to the named modules, and no others.
///
/// For an application where each tenant enables a different subset: one
/// company runs accounting and finance and no HR, a subsidiary runs only
/// sales. Provisioning that tenant means creating its database and running
/// *these* migrations into it — a tenant that never enabled HR must not be
/// given HR's tables.
///
/// ```no_run
/// # use rustlavel::db::{Database, Migrator};
/// # // Named rather than `crate::`: a doctest is its own crate, linking this
/// # // one by name, and the placeholder becomes that name when the project is
/// # // scaffolded.
/// # async fn provision(tenant: &Database, enabled: &[&str]) -> rustlavel::Result<()> {
/// let migrator = Migrator::new(tenant, {{crate_name}}::modules::migrations_for(enabled));
/// migrator.prepare().await?;
/// migrator.run().await?;
/// # Ok(())
/// # }
/// ```
///
/// A name that matches no module contributes nothing rather than failing: the
/// list usually comes from a database column, and one stale row should not stop
/// a tenant being provisioned. Check the names against `all()` where they are
/// *set*, which is where somebody can still do something about a typo.
/// Every module's name, for a screen that offers them.
/// Every seeder the modules own.
/// Every permission the modules declare, for the seeder that creates them.
/// Every setting the modules declare, for the catalogue.