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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! The call shape of a read that composes embedded levels into one statement.
//!
//! A REST `?select=posts(id,comments(id))` used to be answered by a parent read and one
//! sub-read per parent row per level. [`ComposedLevel`] is that request as **one**
//! statement: each embedded level is a correlated subquery joined `LATERAL`, carrying its
//! own filter, ordering and page, so the database returns the whole tree in a single
//! round trip and under a single snapshot.
//!
//! Every value here is already resolved. Which rows a level may read (its security
//! predicate), which keys it may return, and in what order are decided by the engine
//! before this type is built; an adapter renders what it is given and decides nothing.
//!
//! # Where an embedded level's rows come from
//!
//! Either from its own view, correlated to the parent row ([`EmbedSource::Correlated`]),
//! or from the parent row itself ([`EmbedSource::Materialised`]): the objects a view has
//! already embedded in its document, read one by one as the level's rows. The second is
//! how a GraphQL selection into a nested type is gated — its type's predicate filters the
//! elements the parent's view materialised, exactly as it filters rows of the type's own
//! view — without a join the schema may not be able to express.
//!
//! # What a composed read returns
//!
//! Every row, at every level, is the object
//!
//! ```text
//! { "d": <the level's document>, "e": { <output_key>: <embedded value>, … } }
//! ```
//!
//! rather than the document with the embeds merged into it. A relationship may share its
//! name with a stored key, and the engine projects the document before it attaches the
//! embeds; keeping the two apart means neither can overwrite the other on the way.
use FraiseQLError;
use crate::;
/// The refusal a composed read of `view` gets from an adapter that cannot compose.
///
/// One constructor for both places that refuse — the trait's default
/// `execute_composed_with_session` and the engine, which refuses from
/// `supports_composed_reads()` before it would call it — so the two cannot word it
/// differently. `Unsupported` is a `501`.
/// The key under which a composed row carries its level's document.
pub const COMPOSED_DOCUMENT_KEY: &str = "d";
/// The key under which a composed row carries its embedded values.
pub const COMPOSED_EMBEDS_KEY: &str = "e";
/// One level of a composed read: a relation, filtered, ordered and paged, with the levels
/// embedded beneath it.
/// A root level paged by keyset, as a Relay connection pages.
///
/// The rows past `cursor` on `cursor_column`, in `order_by` then `cursor_column`, forward
/// or backward, `limit` of them — `RelayDatabaseAdapter::execute_relay_page`'s page. A
/// backward page is read descending and returned in ascending `cursor_column` order, as
/// the relay page is, so a connection answers the same page whichever of the two reads it.
/// Which keys of a stored document a composed level returns.
/// How an embedded level is attached to each row of its parent.
/// An embedded level and where its rows come from.
/// Where an embedded level's rows come from.