1- use  std:: collections:: BTreeMap ; 
1+ use  std:: collections:: { BTreeMap ,   HashSet } ; 
22use  std:: convert:: TryInto ; 
33
44use  graph:: data:: query:: Trace ; 
@@ -565,37 +565,54 @@ impl<S: Store> IndexNodeResolver<S> {
565565        field :  & a:: Field , 
566566    )  -> Result < r:: Value ,  QueryExecutionError >  { 
567567        // We can safely unwrap because the argument is non-nullable and has been validated. 
568-         let  subgraph_id = field. get_required :: < String > ( "subgraphId" ) . unwrap ( ) ; 
568+         let  subgraph_ids:  HashSet < String >  = field
569+             . get_required :: < Vec < String > > ( "subgraphs" ) 
570+             . unwrap ( ) 
571+             . into_iter ( ) 
572+             . collect ( ) ; 
569573
570-         // Try to build a deployment hash with the input string 
571-         let  deployment_hash = DeploymentHash :: new ( subgraph_id) . map_err ( |invalid_qm_hash| { 
572-             QueryExecutionError :: SubgraphDeploymentIdError ( invalid_qm_hash) 
573-         } ) ?; 
574+         if  subgraph_ids. is_empty ( )  { 
575+             return  Ok ( r:: Value :: List ( Vec :: new ( ) ) ) ; 
576+         } 
574577
575578        let  subgraph_store = self . store . subgraph_store ( ) ; 
576-         let  features = match  subgraph_store. subgraph_features ( & deployment_hash) . await ? { 
577-             Some ( features)  => { 
578-                 let  mut  deployment_features = features. clone ( ) ; 
579-                 let  features = & mut  deployment_features. features ; 
579+         let  mut  all_features = vec ! [ ] ; 
580580
581-                  if  deployment_features . has_declared_calls  { 
582-                     features . push ( "declaredEthCalls" . to_string ( ) ) ; 
583-                 } 
584-                 if  deployment_features . has_aggregations  { 
585-                     features . push ( "aggregations" . to_string ( ) ) ; 
581+         for  subgraph_id  in  subgraph_ids  { 
582+             let  deployment_hash =  match   DeploymentHash :: new ( subgraph_id )   { 
583+                 Ok ( hash )  => hash , 
584+                 Err ( _ )  =>  { 
585+                     continue ; 
586586                } 
587-                 if  !deployment_features. immutable_entities . is_empty ( )  { 
588-                     features. push ( "immutableEntities" . to_string ( ) ) ; 
589-                 } 
590-                 if  deployment_features. has_bytes_as_ids  { 
591-                     features. push ( "bytesAsIds" . to_string ( ) ) ; 
587+             } ; 
588+ 
589+             // Fetch features from store or IPFS 
590+             let  features = match  subgraph_store. subgraph_features ( & deployment_hash) . await ? { 
591+                 Some ( features)  => { 
592+                     let  mut  deployment_features = features. clone ( ) ; 
593+                     let  features = & mut  deployment_features. features ; 
594+ 
595+                     if  deployment_features. has_declared_calls  { 
596+                         features. push ( "declaredEthCalls" . to_string ( ) ) ; 
597+                     } 
598+                     if  deployment_features. has_aggregations  { 
599+                         features. push ( "aggregations" . to_string ( ) ) ; 
600+                     } 
601+                     if  !deployment_features. immutable_entities . is_empty ( )  { 
602+                         features. push ( "immutableEntities" . to_string ( ) ) ; 
603+                     } 
604+                     if  deployment_features. has_bytes_as_ids  { 
605+                         features. push ( "bytesAsIds" . to_string ( ) ) ; 
606+                     } 
607+                     deployment_features
592608                } 
593-                 deployment_features
594-             } 
595-             None  => self . get_features_from_ipfs ( & deployment_hash) . await ?, 
596-         } ; 
609+                 None  => self . get_features_from_ipfs ( & deployment_hash) . await ?, 
610+             } ; 
597611
598-         Ok ( features. into_value ( ) ) 
612+             all_features. push ( features. into_value ( ) ) ; 
613+         } 
614+ 
615+         Ok ( r:: Value :: List ( all_features) ) 
599616    } 
600617
601618    fn  resolve_api_versions ( & self ,  _field :  & a:: Field )  -> Result < r:: Value ,  QueryExecutionError >  { 
@@ -817,6 +834,11 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
817834                self . resolve_public_proofs_of_indexing ( field) . await 
818835            } 
819836
837+             // The top-level `subgraphFeatures` field 
838+             ( None ,  "SubgraphFeatures" ,  "subgraphFeatures" )  => { 
839+                 self . resolve_subgraph_features ( field) . await 
840+             } 
841+ 
820842            // Resolve fields of `Object` values (e.g. the `chains` field of `ChainIndexingStatus`) 
821843            ( value,  _,  _)  => Ok ( value. unwrap_or ( r:: Value :: Null ) ) , 
822844        } 
@@ -837,7 +859,6 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
837859            ( None ,  "indexingStatusForPendingVersion" )  => { 
838860                self . resolve_indexing_status_for_version ( field,  false ) 
839861            } 
840-             ( None ,  "subgraphFeatures" )  => self . resolve_subgraph_features ( field) . await , 
841862            ( None ,  "entityChangesInBlock" )  => self . resolve_entity_changes_in_block ( field) , 
842863            // The top-level `subgraphVersions` field 
843864            ( None ,  "apiVersions" )  => self . resolve_api_versions ( field) , 
0 commit comments