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
use crate::;
/// A multi-step relation path.
///
/// A `Has` relation declared with `#[has_many(via = a.b)]` or
/// `#[has_one(via = a.b)]` reaches its
/// target by following a path of existing relations rather than pairing with a
/// single `BelongsTo`. The path is resolved at macro-expansion time — the
/// derive emits a chained call on the model's `Fields` struct
/// (e.g. `User::fields().comments().article()`) and converts it into a
/// [`stmt::Path`], so a misspelled or otherwise unresolvable segment is a
/// Rust compile error rather than a runtime schema validation failure.
///
/// The terminal segment of the path is usually another relation (the via
/// reaches a model). It may also be a **scalar field**, in which case the via
/// projects that field through the relation path — e.g.
/// `#[has_many(via = todos.tags.name)] tag_names: Vec<String>` collects the
/// `name` of every tag reachable through todos. For a scalar terminal,
/// [`terminal`](Self::terminal) holds the terminal field's index on
/// [`target`](Self::target) (the model the relation chain reaches), and
/// [`path`](Self::path) still includes that terminal step as its last element.
///
/// A common model-terminal use is many-to-many traversal through a join model.
/// If `User` has many `Membership` records and each membership belongs to a
/// `Group`, `#[has_many(via = memberships.group)]` exposes the distinct groups
/// reachable from a user. The join model owns the foreign keys and any fields
/// that describe the connection.