@@ -390,11 +390,6 @@ func (m *Method) IsLRO() bool {
390390 return m .OperationInfo != nil
391391}
392392
393- // IsSimpleOrLRO returns true if the method is simple or a long-running operation.
394- func (m * Method ) IsSimpleOrLRO () bool {
395- return m .IsSimple () || m .IsLRO ()
396- }
397-
398393// LongRunningResponseType returns the response type of the long-running operation.
399394func (m * Method ) LongRunningResponseType () * Message {
400395 if m .OperationInfo == nil {
@@ -409,12 +404,23 @@ func (m *Method) LongRunningReturnsEmpty() bool {
409404 return responseType != nil && responseType .ID == ".google.protobuf.Empty"
410405}
411406
407+ // IsList returns true if the method is a list operation.
408+ func (m * Method ) IsList () bool {
409+ return m .OutputType != nil && m .OutputType .Pagination != nil
410+ }
411+
412+ // IsStreaming returns true if the method is client-side or server-side streaming.
413+ func (m * Method ) IsStreaming () bool {
414+ return m .ClientSideStreaming || m .ServerSideStreaming
415+ }
416+
412417// IsAIPStandard returns true if the method is one of the AIP standard methods.
413418// IsAIPStandard simplifies writing mustache templates, mostly for samples.
414419func (m * Method ) IsAIPStandard () bool {
415420 return m .AIPStandardGetInfo () != nil ||
416421 m .AIPStandardDeleteInfo () != nil ||
417- m .AIPStandardUndeleteInfo () != nil
422+ m .AIPStandardUndeleteInfo () != nil ||
423+ m .AIPStandardListInfo () != nil
418424}
419425
420426// AIPStandardGetInfo contains information relevant to get operations
@@ -537,11 +543,67 @@ func (m *Method) AIPStandardUndeleteInfo() *AIPStandardUndeleteInfo {
537543 }
538544}
539545
546+ // AIPStandardListInfo contains information relevant to list operations
547+ // that are like those defined by AIP-132.
548+ type AIPStandardListInfo struct {
549+ // ParentRequestField is the field in the method input that contains the parent resource name
550+ // of the resources that the list operation should fetch.
551+ ParentRequestField * Field
552+ }
553+
554+ // AIPStandardListInfo returns information relevant to a list operation that is like
555+ // a list operation as defined by AIP-132, if the method is such an operation.
556+ func (m * Method ) AIPStandardListInfo () * AIPStandardListInfo {
557+ if ! m .IsList () || m .InputType == nil {
558+ return nil
559+ }
560+
561+ // Standard list methods for resource "Foo" should be named "ListFoos".
562+ maybePlural , found := strings .CutPrefix (strings .ToLower (m .Name ), "list" )
563+ if ! found || maybePlural == "" {
564+ return nil
565+ }
566+
567+ // The request name should be "ListFoosRequest".
568+ if strings .ToLower (m .InputType .Name ) != fmt .Sprintf ("list%srequest" , maybePlural ) {
569+ return nil
570+ }
571+
572+ // The response name should be "ListFoosResponse".
573+ if strings .ToLower (m .OutputType .Name ) != fmt .Sprintf ("list%sresponse" , maybePlural ) {
574+ return nil
575+ }
576+
577+ // Identify the listed resource type.
578+ pageableItem := m .OutputType .Pagination .PageableItem
579+ if pageableItem == nil || pageableItem .MessageType == nil || pageableItem .MessageType .Resource == nil {
580+ // If we can't identify the resource, we can't match strictly.
581+ // However, standard AIP-132 implies we should be able to.
582+ return nil
583+ }
584+ resourceType := pageableItem .MessageType .Resource .Type
585+
586+ // The request needs to have a field for the parent.
587+ parentField := findBestParentFieldByType (m .InputType , resourceType )
588+
589+ if parentField == nil {
590+ return nil
591+ }
592+
593+ return & AIPStandardListInfo {
594+ ParentRequestField : parentField ,
595+ }
596+ }
597+
540598const (
541599 // StandardFieldNameForResourceRef is the standard name for resource references
542600 // to the resource being operated on by standard methods as defined by AIPs.
543601 StandardFieldNameForResourceRef = "name"
544602
603+ // StandardFieldNameForParentResourceRef is the standard name for resource references
604+ // to the child resource being operated on by standard methods as defined by AIPs.
605+ StandardFieldNameForParentResourceRef = "parent"
606+
545607 // GenericResourceType is a special resource type that may be used by resource references
546608 // in contexts where the referenced resource may be of any type, as defined by AIPs.
547609 GenericResourceType = "*"
@@ -614,6 +676,25 @@ func findBestResourceFieldBySingular(message *Message, resourcesByType map[strin
614676 return bestField
615677}
616678
679+ // findBestParentFieldByType finds the best field in the message that references
680+ // the parent of a resource of the given type.
681+ //
682+ // We prioritize the matches as follows:
683+ // 1. The field name is "parent".
684+ // 2. The field references the child type.
685+ func findBestParentFieldByType (message * Message , childType string ) * Field {
686+ var bestField * Field
687+ for _ , field := range message .Fields {
688+ if field .Name == StandardFieldNameForParentResourceRef {
689+ return field
690+ }
691+ if field .ResourceReference != nil && field .ResourceReference .ChildType == childType {
692+ bestField = field
693+ }
694+ }
695+ return bestField
696+ }
697+
617698// PathInfo contains normalized request path information.
618699type PathInfo struct {
619700 // The list of bindings, including the top-level binding.
0 commit comments