@@ -34,9 +34,6 @@ pub struct Input {
34
34
/// with the top of the hierarchy
35
35
/// (e.g., for an Instance, this would be `[ "Silo", "Project" ]`
36
36
ancestors : Vec < String > ,
37
- /// unordered list of resources that are direct children of this resource
38
- /// (e.g., for a Project, these would include "Instance" and "Disk")
39
- children : Vec < String > ,
40
37
/// whether lookup by name is supported (usually within the parent collection)
41
38
lookup_by_name : bool ,
42
39
/// Description of the primary key columns
@@ -127,11 +124,6 @@ pub struct Config {
127
124
/// [`authz_silo`, `authz_project`])
128
125
path_authz_names : Vec < syn:: Ident > ,
129
126
130
- // Child resources
131
- /// list of names of child resources, in the same form and with the same
132
- /// assumptions as [`Input::name`] (i.e., typically PascalCase)
133
- child_resources : Vec < String > ,
134
-
135
127
// Parent resource, if any
136
128
/// Information about the parent resource, if any
137
129
parent : Option < Resource > ,
@@ -160,7 +152,6 @@ impl Config {
160
152
. collect ( ) ;
161
153
path_authz_names. push ( resource. authz_name . clone ( ) ) ;
162
154
163
- let child_resources = input. children ;
164
155
let parent = input. ancestors . last ( ) . map ( |s| Resource :: for_name ( s) ) ;
165
156
let silo_restricted = !input. visible_outside_silo
166
157
&& input. ancestors . iter ( ) . any ( |s| s == "Silo" ) ;
@@ -177,7 +168,6 @@ impl Config {
177
168
path_types,
178
169
path_authz_names,
179
170
parent,
180
- child_resources,
181
171
lookup_by_name : input. lookup_by_name ,
182
172
primary_key_columns,
183
173
soft_deletes : input. soft_deletes ,
@@ -221,22 +211,22 @@ pub fn lookup_resource(
221
211
let resource_name = & config. resource . name ;
222
212
let the_basics = generate_struct ( & config) ;
223
213
let misc_helpers = generate_misc_helpers ( & config) ;
224
- let child_selectors = generate_child_selectors ( & config) ;
214
+ let child_selector = generate_child_selector ( & config) ;
225
215
let lookup_methods = generate_lookup_methods ( & config) ;
226
216
let database_functions = generate_database_functions ( & config) ;
227
217
228
218
Ok ( quote ! {
229
219
#the_basics
230
220
231
221
impl <' a> #resource_name<' a> {
232
- #child_selectors
233
-
234
222
#lookup_methods
235
223
236
224
#misc_helpers
237
225
238
226
#database_functions
239
227
}
228
+
229
+ #child_selector
240
230
} )
241
231
}
242
232
@@ -287,63 +277,70 @@ fn generate_struct(config: &Config) -> TokenStream {
287
277
}
288
278
}
289
279
290
- /// Generates the child selectors for this resource
280
+ /// Generates the child selector for this resource's parent
291
281
///
292
- /// For example, for the "Project" resource with child resources "Instance" and
293
- /// "Disk", this will generate the `Project::instance_name()` and
294
- /// `Project::disk_name()` functions.
295
- fn generate_child_selectors ( config : & Config ) -> TokenStream {
296
- let child_resource_types: Vec < _ > =
297
- config. child_resources . iter ( ) . map ( |c| format_ident ! ( "{}" , c) ) . collect ( ) ;
298
- let child_selector_fn_names: Vec < _ > = config
299
- . child_resources
300
- . iter ( )
301
- . map ( |c| format_ident ! ( "{}_name" , heck:: AsSnakeCase ( c) . to_string( ) ) )
302
- . collect ( ) ;
303
- let child_selector_fn_names_owned: Vec < _ > = config
304
- . child_resources
305
- . iter ( )
306
- . map ( |c| {
307
- format_ident ! ( "{}_name_owned" , heck:: AsSnakeCase ( c) . to_string( ) )
308
- } )
309
- . collect ( ) ;
310
- let child_selector_fn_docs: Vec < _ > = config
311
- . child_resources
312
- . iter ( )
313
- . map ( |child| {
314
- format ! (
315
- "Select a resource of type {} within this {}, \
316
- identified by its name",
317
- child, config. resource. name,
318
- )
319
- } )
320
- . collect ( ) ;
282
+ /// For example, for the "Instance" resource with parent resource "Project",
283
+ /// this will generate the `Project::instance_name()` and
284
+ /// `Project::instance_name_owned()` functions.
285
+ ///
286
+ /// This is generated by the child resource codegen, rather than by the parent
287
+ /// resource codegen, since such functions are only generated for resources with
288
+ /// `lookup_by_name = true`. Whether or not this is enabled for the child
289
+ /// resource is not known when generating the parent resource code, so it's
290
+ /// performed by the child instead.
291
+ fn generate_child_selector ( config : & Config ) -> TokenStream {
292
+ // If this resource cannot be looked up by name, we don't need to generate
293
+ // child selectors on the parent resource.
294
+ if !config. lookup_by_name {
295
+ return quote ! { } ;
296
+ }
297
+
298
+ // The child selector is generated for the parent resource type. If there
299
+ // isn't one, nothing to do here.
300
+ let Some ( ref parent) = config. parent else { return quote ! { } } ;
301
+
302
+ let parent_resource_type = & parent. name ;
303
+ let child_selector_fn_name = format_ident ! (
304
+ "{}_name" ,
305
+ heck:: AsSnakeCase ( config. resource. name. to_string( ) ) . to_string( )
306
+ ) ;
307
+
308
+ let child_selector_fn_name_owned = format_ident ! (
309
+ "{}_name_owned" ,
310
+ heck:: AsSnakeCase ( config. resource. name. to_string( ) ) . to_string( )
311
+ ) ;
312
+ let child_resource_type = & config. resource . name ;
313
+
314
+ let child_selector_fn_docs = format ! (
315
+ "Select a resource of type {child_resource_type} within this \
316
+ {parent_resource_type}, identified by its name",
317
+ ) ;
321
318
322
319
quote ! {
323
- # (
320
+ impl < ' a> #parent_resource_type< ' a> {
324
321
#[ doc = #child_selector_fn_docs]
325
- pub fn #child_selector_fn_names <' b, ' c>(
322
+ pub fn #child_selector_fn_name <' b, ' c>(
326
323
self ,
327
324
name: & ' b Name
328
- ) -> #child_resource_types <' c>
325
+ ) -> #child_resource_type <' c>
329
326
where
330
327
' a: ' c,
331
328
' b: ' c,
332
329
{
333
- #child_resource_types :: Name ( self , name)
330
+ #child_resource_type :: Name ( self , name)
334
331
}
335
332
336
333
#[ doc = #child_selector_fn_docs]
337
- pub fn #child_selector_fn_names_owned <' c>(
334
+ pub fn #child_selector_fn_name_owned <' c>(
338
335
self ,
339
336
name: Name ,
340
- ) -> #child_resource_types <' c>
337
+ ) -> #child_resource_type <' c>
341
338
where
342
339
' a: ' c,
343
340
{
344
- #child_resource_types :: OwnedName ( self , name)
341
+ #child_resource_type :: OwnedName ( self , name)
345
342
}
346
- ) *
343
+ }
347
344
}
348
345
}
349
346
@@ -991,7 +988,6 @@ mod test {
991
988
let output = lookup_resource ( quote ! {
992
989
name = "Project" ,
993
990
ancestors = [ "Silo" ] ,
994
- children = [ "Disk" , "Instance" ] ,
995
991
lookup_by_name = true ,
996
992
soft_deletes = true ,
997
993
primary_key_columns = [ { column_name = "id" , rust_type = Uuid } ]
@@ -1002,7 +998,6 @@ mod test {
1002
998
let output = lookup_resource ( quote ! {
1003
999
name = "SiloUser" ,
1004
1000
ancestors = [ ] ,
1005
- children = [ ] ,
1006
1001
lookup_by_name = false ,
1007
1002
soft_deletes = true ,
1008
1003
primary_key_columns = [ { column_name = "id" , rust_type = Uuid } ]
@@ -1013,7 +1008,6 @@ mod test {
1013
1008
let output = lookup_resource ( quote ! {
1014
1009
name = "Sled" ,
1015
1010
ancestors = [ ] ,
1016
- children = [ ] ,
1017
1011
lookup_by_name = false ,
1018
1012
soft_deletes = true ,
1019
1013
primary_key_columns = [ { column_name = "id" , uuid_kind = SledKind } ]
@@ -1024,7 +1018,6 @@ mod test {
1024
1018
let output = lookup_resource ( quote ! {
1025
1019
name = "UpdateArtifact" ,
1026
1020
ancestors = [ ] ,
1027
- children = [ ] ,
1028
1021
lookup_by_name = false ,
1029
1022
soft_deletes = false ,
1030
1023
primary_key_columns = [
0 commit comments