diff --git a/apollo-federation/src/sources/connect/expand/mod.rs b/apollo-federation/src/sources/connect/expand/mod.rs index bf9f8cd3e7..4dbc182c23 100644 --- a/apollo-federation/src/sources/connect/expand/mod.rs +++ b/apollo-federation/src/sources/connect/expand/mod.rs @@ -176,6 +176,7 @@ mod helpers { use apollo_compiler::ast::FieldDefinition; use apollo_compiler::ast::InputValueDefinition; use apollo_compiler::ast::Value; + use apollo_compiler::collections::HashSet; use apollo_compiler::name; use apollo_compiler::schema::Component; use apollo_compiler::schema::ComponentName; @@ -206,6 +207,8 @@ mod helpers { use crate::schema::position::TypeDefinitionPosition; use crate::schema::FederationSchema; use crate::schema::ValidFederationSchema; + use crate::sources::connect::json_selection::ExtractParameters; + use crate::sources::connect::json_selection::StaticParameter; use crate::sources::connect::url_template::Parameter; use crate::sources::connect::ConnectSpecDefinition; use crate::sources::connect::Connector; @@ -390,6 +393,10 @@ mod helpers { connector: &Connector, arguments: &[Node], ) -> Result<(), FederationError> { + // The body of the request might include references to input arguments / sibling fields + // that will need to be handled, so we extract any referenced variables now + let body_parameters = extract_params_from_body(connector)?; + let parameters = connector .transport .connect_template @@ -399,7 +406,7 @@ mod helpers { "could not extract path template parameters: {e}" )) })?; - for parameter in parameters { + for parameter in Iterator::chain(body_parameters.iter(), ¶meters) { match parameter { // Ensure that input arguments are carried over to the new schema, including // any types associated with them. @@ -407,7 +414,7 @@ mod helpers { // Get the argument type let arg = arguments .iter() - .find(|a| a.name.as_str() == argument) + .find(|a| a.name.as_str() == *argument) .ok_or(FederationError::internal(format!( "could not find argument: {argument}" )))?; @@ -460,6 +467,10 @@ mod helpers { let parent_type = self.original_schema.get_type(parent_type_name)?; let output_type = to_schema.get_type(output_type_name)?; + // The body of the request might include references to input arguments / sibling fields + // that will need to be handled, so we extract any referenced variables now + let body_parameters = extract_params_from_body(connector)?; + let parameters = connector .transport .connect_template @@ -472,7 +483,7 @@ mod helpers { // We'll need to collect all synthesized keys for the output type, adding a federation // `@key` directive once completed. let mut keys = Vec::new(); - for parameter in parameters { + for parameter in Iterator::chain(body_parameters.iter(), ¶meters) { match parameter { // Arguments should be added to the synthesized key, since they are mandatory // to resolving the output type. The synthesized key should only include the portions @@ -784,6 +795,41 @@ mod helpers { Ok(()) } } + + fn extract_params_from_body( + connector: &Connector, + ) -> Result, FederationError> { + let body_parameters = connector + .transport + .body + .as_ref() + .and_then(JSONSelection::extract_parameters) + .unwrap_or_default(); + + body_parameters + .iter() + .map(|StaticParameter { name, paths }| { + let mut parts = paths.iter(); + let field = parts.next().ok_or(FederationError::internal( + "expected parameter in JSONSelection to contain a field", + ))?; + + match *name { + "$args" => Ok(Parameter::Argument { + argument: field, + paths: parts.copied().collect(), + }), + "$this" => Ok(Parameter::Sibling { + field, + paths: parts.copied().collect(), + }), + other => Err(FederationError::internal(format!( + "got unsupported parameter: {other}" + ))), + } + }) + .collect::, _>>() + } } #[cfg(test)] diff --git a/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.graphql b/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.graphql index c89095bd9a..7a01562f91 100644 --- a/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.graphql +++ b/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.graphql @@ -84,6 +84,7 @@ enum link__Purpose { type Query @join__type(graph: CONNECTORS) { + filterUsersByEmailDomain(email: EmailAddress!): [User] @join__directive(graphs: [CONNECTORS], name: "connect", args: {source: "example", http: {GET: "/filter/users", body: "emailDomain: $args.email"}, selection: "id\nname"}) usersByCompany(company: CompanyInput!): [User] @join__directive(graphs: [CONNECTORS], name: "connect", args: {source: "example", http: {GET: "/by-company/{$args.company.name}"}, selection: "id\nname\ncompany {\n name\n catchPhrase\n bs\n}"}) user(id: ID!): User @join__directive(graphs: [CONNECTORS], name: "connect", args: {source: "example", http: {GET: "/{$args.id}"}, selection: "id\nname\nusername\nemail\naddress {\n street\n suite\n city\n zipcode\n geo {\n lat\n lng\n }\n}\nphone\nwebsite\ncompany {\n name\n catchPhrase\n bs\n email\n}", entity: true}) } diff --git a/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.yaml b/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.yaml index 0c7c193849..78465f7274 100644 --- a/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.yaml +++ b/apollo-federation/src/sources/connect/expand/tests/schemas/realistic.yaml @@ -13,6 +13,12 @@ subgraphs: @source(name: "example", http: { baseURL: "http://example" }) type Query { + filterUsersByEmailDomain(email: EmailAddress!): [User] + @connect(source: "example", http: { GET: "/filter/users", body: "emailDomain: $$args.email" }, selection: """ + id + name + """) + usersByCompany(company: CompanyInput!): [User] @connect(source: "example", http: { GET: "/by-company/{$$args.company.name}" }, selection: """ id diff --git a/apollo-federation/src/sources/connect/expand/tests/schemas/simple.graphql b/apollo-federation/src/sources/connect/expand/tests/schemas/simple.graphql index ee3549e13c..98e7ceef5a 100644 --- a/apollo-federation/src/sources/connect/expand/tests/schemas/simple.graphql +++ b/apollo-federation/src/sources/connect/expand/tests/schemas/simple.graphql @@ -62,5 +62,5 @@ type User a: String @join__field(graph: CONNECTORS) b: String @join__field(graph: CONNECTORS) c: String @join__field(graph: CONNECTORS, external: true) @join__field(graph: GRAPHQL) - d: String @join__field(graph: CONNECTORS, requires: "c") @join__directive(graphs: [CONNECTORS], name: "connect", args: {source: "example", http: {GET: "/{$this.c}/d"}, selection: "$"}) + d: String @join__field(graph: CONNECTORS, requires: "c") @join__directive(graphs: [CONNECTORS], name: "connect", args: {source: "example", http: {GET: "/{$this.c}/d", body: "with_b: $this.b"}, selection: "$"}) } diff --git a/apollo-federation/src/sources/connect/expand/tests/schemas/simple.yaml b/apollo-federation/src/sources/connect/expand/tests/schemas/simple.yaml index 82d4e93d60..df71b38d23 100644 --- a/apollo-federation/src/sources/connect/expand/tests/schemas/simple.yaml +++ b/apollo-federation/src/sources/connect/expand/tests/schemas/simple.yaml @@ -26,7 +26,7 @@ subgraphs: c: String @external d: String @requires(fields: "c") - @connect(source: "example", http: { GET: "/{$$this.c}/d" }, selection: "$") + @connect(source: "example", http: { GET: "/{$$this.c}/d", body: "with_b: $$this.b" }, selection: "$") } graphql: diff --git a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-2.snap b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-2.snap index 9d385f1c78..6486c77e7a 100644 --- a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-2.snap +++ b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-2.snap @@ -3,6 +3,103 @@ source: apollo-federation/src/sources/connect/expand/tests/mod.rs expression: connectors.by_service_name --- { + "connectors_Query_filterUsersByEmailDomain_0": Connector { + id: ConnectId { + label: "connectors.example http: GET /filter/users", + subgraph_name: "connectors", + source_name: Some( + "example", + ), + directive: ObjectOrInterfaceFieldDirectivePosition { + field: Object(Query.filterUsersByEmailDomain), + directive_name: "connect", + directive_index: 0, + }, + }, + transport: HttpJsonTransport { + source_url: Some( + Url { + scheme: "http", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "example", + ), + ), + port: None, + path: "/", + query: None, + fragment: None, + }, + ), + connect_template: URLTemplate { + base: None, + path: [ + ParameterValue { + parts: [ + Text( + "filter", + ), + ], + }, + ParameterValue { + parts: [ + Text( + "users", + ), + ], + }, + ], + query: {}, + }, + method: Get, + headers: {}, + body: Some( + Named( + SubSelection { + selections: [ + Path( + Alias { + name: "emailDomain", + }, + Var( + "$args", + Key( + Field( + "email", + ), + Empty, + ), + ), + ), + ], + star: None, + }, + ), + ), + }, + selection: Named( + SubSelection { + selections: [ + Field( + None, + "id", + None, + ), + Field( + None, + "name", + None, + ), + ], + star: None, + }, + ), + config: None, + entity_resolver: None, + }, "connectors_Query_usersByCompany_0": Connector { id: ConnectId { label: "connectors.example http: GET /by-company/{$args.company.name!}", diff --git a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-3.snap b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-3.snap index fc4f57de42..d6bb4ee3cb 100644 --- a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-3.snap +++ b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph-3.snap @@ -38,10 +38,30 @@ scalar join__FieldSet scalar join__DirectiveArguments enum join__Graph { + CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0 @join__graph(name: "connectors_Query_filterUsersByEmailDomain_0", url: "none") CONNECTORS_QUERY_USER_0 @join__graph(name: "connectors_Query_user_0", url: "none") CONNECTORS_QUERY_USERSBYCOMPANY_0 @join__graph(name: "connectors_Query_usersByCompany_0", url: "none") } +scalar EmailAddress @join__type(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) @join__type(graph: CONNECTORS_QUERY_USER_0) + +type User @join__type(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) @join__type(graph: CONNECTORS_QUERY_USER_0, key: "id") @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { + id: ID! @join__field(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) + name: String @join__field(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) + address: Address @join__field(graph: CONNECTORS_QUERY_USER_0) + company: CompanyInfo @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) + email: EmailAddress @join__field(graph: CONNECTORS_QUERY_USER_0) + phone: String @join__field(graph: CONNECTORS_QUERY_USER_0) + username: String @join__field(graph: CONNECTORS_QUERY_USER_0) + website: String @join__field(graph: CONNECTORS_QUERY_USER_0) +} + +type Query @join__type(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) @join__type(graph: CONNECTORS_QUERY_USER_0) @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { + filterUsersByEmailDomain(email: EmailAddress!): [User] @join__field(graph: CONNECTORS_QUERY_FILTERUSERSBYEMAILDOMAIN_0) + user(id: ID!): User @join__field(graph: CONNECTORS_QUERY_USER_0) + usersByCompany(company: CompanyInput!): [User] @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) +} + type AddressGeo @join__type(graph: CONNECTORS_QUERY_USER_0) { lat: Float @join__field(graph: CONNECTORS_QUERY_USER_0) lng: Float @join__field(graph: CONNECTORS_QUERY_USER_0) @@ -55,8 +75,6 @@ type Address @join__type(graph: CONNECTORS_QUERY_USER_0) { zipcode: String @join__field(graph: CONNECTORS_QUERY_USER_0) } -scalar EmailAddress @join__type(graph: CONNECTORS_QUERY_USER_0) - type CompanyInfo @join__type(graph: CONNECTORS_QUERY_USER_0) @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { bs: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) catchPhrase: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) @@ -64,22 +82,6 @@ type CompanyInfo @join__type(graph: CONNECTORS_QUERY_USER_0) @join__type(graph: name: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) } -type User @join__type(graph: CONNECTORS_QUERY_USER_0, key: "id") @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { - address: Address @join__field(graph: CONNECTORS_QUERY_USER_0) - company: CompanyInfo @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) - email: EmailAddress @join__field(graph: CONNECTORS_QUERY_USER_0) - id: ID! @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) - name: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) - phone: String @join__field(graph: CONNECTORS_QUERY_USER_0) - username: String @join__field(graph: CONNECTORS_QUERY_USER_0) - website: String @join__field(graph: CONNECTORS_QUERY_USER_0) -} - -type Query @join__type(graph: CONNECTORS_QUERY_USER_0) @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { - user(id: ID!): User @join__field(graph: CONNECTORS_QUERY_USER_0) - usersByCompany(company: CompanyInput!): [User] @join__field(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) -} - input CompanyInput @join__type(graph: CONNECTORS_QUERY_USERSBYCOMPANY_0) { name: String! catchPhrase: String diff --git a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph.snap b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph.snap index bd0d9d6c4a..9908defa24 100644 --- a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph.snap +++ b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__realistic__it_expands_supergraph.snap @@ -32,6 +32,7 @@ input CompanyInput { scalar EmailAddress type Query { + filterUsersByEmailDomain(email: EmailAddress!): [User] usersByCompany(company: CompanyInput!): [User] user(id: ID!): User } diff --git a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-2.snap b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-2.snap index e4df4702c1..3c6571399a 100644 --- a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-2.snap +++ b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-2.snap @@ -199,7 +199,29 @@ expression: connectors.by_service_name }, method: Get, headers: {}, - body: None, + body: Some( + Named( + SubSelection { + selections: [ + Path( + Alias { + name: "with_b", + }, + Var( + "$this", + Key( + Field( + "b", + ), + Empty, + ), + ), + ), + ], + star: None, + }, + ), + ), }, selection: Path( Var( diff --git a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-3.snap b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-3.snap index 6705b8f2b7..85c352968e 100644 --- a/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-3.snap +++ b/apollo-federation/src/sources/connect/expand/tests/snapshots/apollo_federation__sources__connect__expand__tests__simple__it_expands_supergraph-3.snap @@ -46,9 +46,9 @@ enum join__Graph { GRAPHQL @join__graph(name: "graphql", url: "https://graphql") } -type User @join__type(graph: CONNECTORS_QUERY_USER_0, key: "id") @join__type(graph: CONNECTORS_QUERY_USERS_0) @join__type(graph: CONNECTORS_USER_D_1, key: "c") @join__type(graph: GRAPHQL, key: "id") { +type User @join__type(graph: CONNECTORS_QUERY_USER_0, key: "id") @join__type(graph: CONNECTORS_QUERY_USERS_0) @join__type(graph: CONNECTORS_USER_D_1, key: "b c") @join__type(graph: GRAPHQL, key: "id") { a: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERS_0) - b: String @join__field(graph: CONNECTORS_QUERY_USER_0) + b: String @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_USER_D_1) id: ID! @join__field(graph: CONNECTORS_QUERY_USER_0) @join__field(graph: CONNECTORS_QUERY_USERS_0) @join__field(graph: GRAPHQL) d: String @join__field(graph: CONNECTORS_USER_D_1) c: String @join__field(graph: CONNECTORS_USER_D_1) @join__field(graph: GRAPHQL) diff --git a/apollo-federation/src/sources/connect/json_selection/mod.rs b/apollo-federation/src/sources/connect/json_selection/mod.rs index 73f7e74a5e..d380c3d69e 100644 --- a/apollo-federation/src/sources/connect/json_selection/mod.rs +++ b/apollo-federation/src/sources/connect/json_selection/mod.rs @@ -1,12 +1,14 @@ mod apply_to; mod graphql; mod helpers; +mod parameter_extraction; mod parser; mod pretty; mod selection_set; mod visitor; pub use apply_to::*; +pub use parameter_extraction::*; pub use parser::*; // Pretty code is currently only used in tests, so this cfg is to suppress the // unused lint warning. If pretty code is needed in not test code, feel free to diff --git a/apollo-federation/src/sources/connect/json_selection/parameter_extraction.rs b/apollo-federation/src/sources/connect/json_selection/parameter_extraction.rs new file mode 100644 index 0000000000..0a037ba176 --- /dev/null +++ b/apollo-federation/src/sources/connect/json_selection/parameter_extraction.rs @@ -0,0 +1,113 @@ +use std::collections::HashSet; + +use super::JSONSelection; +use super::NamedSelection; +use super::PathSelection; +use super::SubSelection; + +/// A representation of a static parameter. +/// +/// Each parameter can include path components for drilling down into specific +/// members of a parameter. +/// +/// Note: This is somewhat related to [crate::sources::connect::Parameter] +/// but is less restrictive as it does not do any formal validation of parameters. +/// +/// e.g. A parameter like below +/// ```json_selection +/// $this.a.b.c +/// ``` +/// +/// would have the following representation: +/// ```rust +/// # use apollo_federation::sources::connect::StaticParameter; +/// StaticParameter { +/// name: "this", +/// paths: vec!["a", "b", "c"], +/// } +/// # ; +/// ``` +#[derive(Debug, Hash, PartialEq, Eq)] +pub struct StaticParameter<'a> { + /// The name of the parameter, after the $ + /// TODO: This might be nice to have as an enum, but it requires making + /// extraction fallible. Another option would be to have JSONSelection aware + /// of which variables it knows about, but that might not make sense to have + /// as a responsibility of JSONSelection. + pub name: &'a str, + + /// Any paths after the name + pub paths: Vec<&'a str>, +} + +pub trait ExtractParameters { + /// Extract parameters for static analysis + fn extract_parameters(&self) -> Option>; +} + +impl ExtractParameters for JSONSelection { + fn extract_parameters(&self) -> Option> { + match &self { + JSONSelection::Named(named) => named.extract_parameters(), + JSONSelection::Path(path) => path.extract_parameters(), + } + } +} + +impl ExtractParameters for PathSelection { + fn extract_parameters(&self) -> Option> { + let param = match &self { + PathSelection::Var(name, rest) => Some(StaticParameter { + name: name.as_str(), + paths: rest + .collect_paths() + .iter() + // We don't run `to_string` here since path implements display and prepends + // a '.' to the path components + .map(|k| match k { + super::Key::Field(val) | super::Key::Quoted(val) => val.as_str(), + super::Key::Index(_) => "[]", // TODO: Remove when JSONSelection removes it + }) + .collect(), + }), + PathSelection::Key(_, _) | PathSelection::Selection(_) | PathSelection::Empty => None, + }; + + param.map(|p| { + let mut set = HashSet::with_hasher(Default::default()); + set.insert(p); + + set + }) + } +} + +impl ExtractParameters for SubSelection { + fn extract_parameters(&self) -> Option> { + let params: HashSet<_> = self + .selections + .iter() + .filter_map(NamedSelection::extract_parameters) + .flatten() + .collect(); + + if params.is_empty() { + None + } else { + Some(params) + } + } +} + +impl ExtractParameters for NamedSelection { + fn extract_parameters(&self) -> Option> { + match &self { + NamedSelection::Field(_, _, Some(sub)) + | NamedSelection::Quoted(_, _, Some(sub)) + | NamedSelection::Group(_, sub) => sub.extract_parameters(), + + NamedSelection::Path(_, path) => path.extract_parameters(), + _ => None, + } + } +} diff --git a/apollo-federation/src/sources/connect/json_selection/parser.rs b/apollo-federation/src/sources/connect/json_selection/parser.rs index f73762f223..fb1ccab784 100644 --- a/apollo-federation/src/sources/connect/json_selection/parser.rs +++ b/apollo-federation/src/sources/connect/json_selection/parser.rs @@ -147,19 +147,6 @@ impl NamedSelection { } } - /// Extracts the property path for a given named selection - /// - // TODO: Expand on what this means once I have a better understanding - pub(crate) fn property_path(&self) -> Vec { - match self { - NamedSelection::Field(_, name, _) => vec![Key::Field(name.to_string())], - NamedSelection::Quoted(_, _, Some(_)) => todo!(), - NamedSelection::Quoted(_, name, None) => vec![Key::Quoted(name.to_string())], - NamedSelection::Path(_, path) => path.collect_paths(), - NamedSelection::Group(alias, _) => vec![Key::Field(alias.name.to_string())], - } - } - /// Find the next subselection, if present pub(crate) fn next_subselection(&self) -> Option<&SubSelection> { match self { @@ -293,13 +280,13 @@ impl PathSelection { /// /// This method attempts to collect as many paths as possible, shorting out once /// a non path selection is encountered. - pub(crate) fn collect_paths(&self) -> Vec { + pub(crate) fn collect_paths(&self) -> Vec<&Key> { let mut results = Vec::new(); // Collect as many as possible let mut current = self; while let Self::Key(key, rest) = current { - results.push(key.clone()); + results.push(key); current = rest; } diff --git a/apollo-federation/src/sources/connect/mod.rs b/apollo-federation/src/sources/connect/mod.rs index 0f90a45708..ce33b09e02 100644 --- a/apollo-federation/src/sources/connect/mod.rs +++ b/apollo-federation/src/sources/connect/mod.rs @@ -17,9 +17,11 @@ pub use json_selection::ApplyToError; pub use json_selection::JSONSelection; pub use json_selection::Key; pub use json_selection::PathSelection; +pub use json_selection::StaticParameter; pub use json_selection::SubSelection; pub use models::CustomConfiguration; pub(crate) use spec::ConnectSpecDefinition; +pub use url_template::Parameter; pub use url_template::URLTemplate; pub use self::models::Connector;