mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
remote joins: do not include the join field if it already exists (#402)
For remote joins, if join field already exists in the selection set, do not request it again. Include the join field only if it is not in the selection set. A field selection might be expensive, so we do not want to duplicate it. Fixes: https://hasurahq.atlassian.net/browse/V3API-296 V3_GIT_ORIGIN_REV_ID: d09e4298557ca098433b0758c15703295ccbfd39
This commit is contained in:
parent
dda2fb8eca
commit
10e12d8acf
@ -22,6 +22,7 @@ use crate::metadata::resolved;
|
|||||||
use crate::metadata::resolved::subgraph::{
|
use crate::metadata::resolved::subgraph::{
|
||||||
Qualified, QualifiedBaseType, QualifiedTypeName, QualifiedTypeReference,
|
Qualified, QualifiedBaseType, QualifiedTypeName, QualifiedTypeReference,
|
||||||
};
|
};
|
||||||
|
use crate::metadata::resolved::types::FieldMapping;
|
||||||
use crate::schema::types::TypeKind;
|
use crate::schema::types::TypeKind;
|
||||||
use crate::schema::{
|
use crate::schema::{
|
||||||
types::{Annotation, OutputAnnotation, RootFieldAnnotation},
|
types::{Annotation, OutputAnnotation, RootFieldAnnotation},
|
||||||
@ -104,6 +105,23 @@ pub(crate) struct ResultSelectionSet<'s> {
|
|||||||
pub(crate) fields: IndexMap<String, FieldSelection<'s>>,
|
pub(crate) fields: IndexMap<String, FieldSelection<'s>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'s> ResultSelectionSet<'s> {
|
||||||
|
/// Takes a 'FieldMapping' and returns the alias, if the field is found in
|
||||||
|
/// existing fields
|
||||||
|
pub(crate) fn contains(&self, other_field: &FieldMapping) -> Option<String> {
|
||||||
|
self.fields.iter().find_map(|(alias, field)| match field {
|
||||||
|
FieldSelection::Column { column, .. } => {
|
||||||
|
if *column == other_field.column {
|
||||||
|
Some(alias.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_global_id_fields(
|
fn build_global_id_fields(
|
||||||
global_id_fields: &Vec<FieldName>,
|
global_id_fields: &Vec<FieldName>,
|
||||||
field_mappings: &BTreeMap<FieldName, resolved::types::FieldMapping>,
|
field_mappings: &BTreeMap<FieldName, resolved::types::FieldMapping>,
|
||||||
|
@ -13,6 +13,7 @@ use crate::execute::remote_joins::types::{
|
|||||||
JoinLocations, JoinNode, LocationKind, MonotonicCounter, RemoteJoinType, TargetField,
|
JoinLocations, JoinNode, LocationKind, MonotonicCounter, RemoteJoinType, TargetField,
|
||||||
};
|
};
|
||||||
use crate::execute::remote_joins::types::{Location, RemoteJoin};
|
use crate::execute::remote_joins::types::{Location, RemoteJoin};
|
||||||
|
use crate::metadata::resolved::types::FieldMapping;
|
||||||
|
|
||||||
pub(crate) fn process_nested_selection<'s, 'ir>(
|
pub(crate) fn process_nested_selection<'s, 'ir>(
|
||||||
nested_selection: &'ir NestedSelection<'s>,
|
nested_selection: &'ir NestedSelection<'s>,
|
||||||
@ -154,24 +155,18 @@ pub(crate) fn process_selection_set_ir<'s, 'ir>(
|
|||||||
ir,
|
ir,
|
||||||
relationship_info,
|
relationship_info,
|
||||||
} => {
|
} => {
|
||||||
// For all the left join fields, create an alias and inject
|
|
||||||
// them into the NDC IR
|
|
||||||
let mut join_mapping = HashMap::new();
|
let mut join_mapping = HashMap::new();
|
||||||
for ((src_field_alias, src_field), target_field) in &relationship_info.join_mapping
|
for ((src_field_alias, src_field), target_field) in &relationship_info.join_mapping
|
||||||
{
|
{
|
||||||
let lhs_alias = make_hasura_phantom_field(&src_field.column);
|
let ndc_field_alias = process_remote_relationship_field_mapping(
|
||||||
|
model_selection,
|
||||||
ndc_fields.insert(
|
src_field,
|
||||||
lhs_alias.clone(),
|
&mut ndc_fields,
|
||||||
ndc::models::Field::Column {
|
|
||||||
column: src_field.column.clone(),
|
|
||||||
fields: None,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
join_mapping.insert(
|
join_mapping.insert(
|
||||||
src_field_alias.clone(),
|
src_field_alias.clone(),
|
||||||
(
|
(
|
||||||
lhs_alias.clone(),
|
ndc_field_alias,
|
||||||
TargetField::ModelField(target_field.clone()),
|
TargetField::ModelField(target_field.clone()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -197,24 +192,18 @@ pub(crate) fn process_selection_set_ir<'s, 'ir>(
|
|||||||
ir,
|
ir,
|
||||||
relationship_info,
|
relationship_info,
|
||||||
} => {
|
} => {
|
||||||
// For all the left join fields, create an alias and inject
|
|
||||||
// them into the NDC IR
|
|
||||||
let mut join_mapping = HashMap::new();
|
let mut join_mapping = HashMap::new();
|
||||||
for ((src_field_alias, src_field), target_field) in &relationship_info.join_mapping
|
for ((src_field_alias, src_field), target_field) in &relationship_info.join_mapping
|
||||||
{
|
{
|
||||||
let lhs_alias = make_hasura_phantom_field(&src_field.column);
|
let ndc_field_alias = process_remote_relationship_field_mapping(
|
||||||
|
model_selection,
|
||||||
ndc_fields.insert(
|
src_field,
|
||||||
lhs_alias.clone(),
|
&mut ndc_fields,
|
||||||
ndc::models::Field::Column {
|
|
||||||
column: src_field.column.clone(),
|
|
||||||
fields: None,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
join_mapping.insert(
|
join_mapping.insert(
|
||||||
src_field_alias.clone(),
|
src_field_alias.clone(),
|
||||||
(
|
(
|
||||||
lhs_alias.clone(),
|
ndc_field_alias,
|
||||||
TargetField::CommandField(target_field.clone()),
|
TargetField::CommandField(target_field.clone()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -244,6 +233,34 @@ pub(crate) fn process_selection_set_ir<'s, 'ir>(
|
|||||||
Ok((ndc_fields, join_locations))
|
Ok((ndc_fields, join_locations))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Processes a remote relationship field mapping, and returns the alias used in
|
||||||
|
/// the NDC IR for that field
|
||||||
|
///
|
||||||
|
/// - if the selection set DOES NOT contain the field, insert it into the NDC IR
|
||||||
|
/// (with an internal alias), and return the alias
|
||||||
|
/// - if the selection set already contains the field, do not insert the field
|
||||||
|
/// in NDC IR, and return the existing alias
|
||||||
|
fn process_remote_relationship_field_mapping(
|
||||||
|
selection: &ResultSelectionSet<'_>,
|
||||||
|
field: &FieldMapping,
|
||||||
|
ndc_fields: &mut IndexMap<String, ndc::models::Field>,
|
||||||
|
) -> String {
|
||||||
|
match selection.contains(field) {
|
||||||
|
None => {
|
||||||
|
let internal_alias = make_hasura_phantom_field(&field.column);
|
||||||
|
ndc_fields.insert(
|
||||||
|
internal_alias.clone(),
|
||||||
|
ndc::models::Field::Column {
|
||||||
|
column: field.column.clone(),
|
||||||
|
fields: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
internal_alias
|
||||||
|
}
|
||||||
|
Some(field_alias) => field_alias,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_hasura_phantom_field(field_name: &str) -> String {
|
fn make_hasura_phantom_field(field_name: &str) -> String {
|
||||||
format!("__hasura_phantom_field__{}", field_name)
|
format!("__hasura_phantom_field__{}", field_name)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ mod common;
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_explain_introspection() {
|
fn test_explain_introspection() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/introspection_query/",
|
"explain/introspection_query",
|
||||||
"explain/introspection_query/metadata.json",
|
"explain/introspection_query/metadata.json",
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
@ -13,7 +13,7 @@ fn test_explain_introspection() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_multi_root_field_queries() {
|
fn test_multi_root_field_queries() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/multi_root_field_queries/",
|
"explain/multi_root_field_queries",
|
||||||
"execute/multiple_root_fields/successful_execution/metadata.json",
|
"execute/multiple_root_fields/successful_execution/metadata.json",
|
||||||
&[],
|
&[],
|
||||||
);
|
);
|
||||||
@ -22,7 +22,7 @@ fn test_multi_root_field_queries() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_field_with_remote_relationship() {
|
fn test_field_with_remote_relationship() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/field_with_remote_relationship/",
|
"explain/field_with_remote_relationship",
|
||||||
"execute/remote_relationships/array/metadata.json",
|
"execute/remote_relationships/array/metadata.json",
|
||||||
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
||||||
);
|
);
|
||||||
@ -31,7 +31,7 @@ fn test_field_with_remote_relationship() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_field_with_local_relationship() {
|
fn test_field_with_local_relationship() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/field_with_local_relationship/",
|
"explain/field_with_local_relationship",
|
||||||
"execute/relationships/array/metadata.json",
|
"execute/relationships/array/metadata.json",
|
||||||
&["execute/common_metadata/postgres_connector_schema.json"],
|
&["execute/common_metadata/postgres_connector_schema.json"],
|
||||||
);
|
);
|
||||||
@ -40,7 +40,7 @@ fn test_field_with_local_relationship() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_field_with_multi_remote_relationship_subfields() {
|
fn test_field_with_multi_remote_relationship_subfields() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/field_with_multi_remote_relationship_subfields/",
|
"explain/field_with_multi_remote_relationship_subfields",
|
||||||
"explain/field_with_multi_remote_relationship_subfields/metadata.json",
|
"explain/field_with_multi_remote_relationship_subfields/metadata.json",
|
||||||
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
||||||
);
|
);
|
||||||
@ -49,7 +49,7 @@ fn test_field_with_multi_remote_relationship_subfields() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_field_with_nested_remote_relationship_1() {
|
fn test_field_with_nested_remote_relationship_1() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/field_with_nested_remote_relationship_1/",
|
"explain/field_with_nested_remote_relationship_1",
|
||||||
"explain/field_with_nested_remote_relationship_1/metadata.json",
|
"explain/field_with_nested_remote_relationship_1/metadata.json",
|
||||||
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
||||||
);
|
);
|
||||||
@ -58,7 +58,7 @@ fn test_field_with_nested_remote_relationship_1() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_field_with_nested_remote_relationship_2() {
|
fn test_field_with_nested_remote_relationship_2() {
|
||||||
common::test_execute_explain(
|
common::test_execute_explain(
|
||||||
"explain/field_with_nested_remote_relationship_2/",
|
"explain/field_with_nested_remote_relationship_2",
|
||||||
"explain/field_with_nested_remote_relationship_2/metadata.json",
|
"explain/field_with_nested_remote_relationship_2/metadata.json",
|
||||||
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
&["execute/common_metadata/two_postgres_connector_schema.json"],
|
||||||
);
|
);
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
"column": "ArtistId",
|
"column": "ArtistId",
|
||||||
"fields": null
|
"fields": null
|
||||||
},
|
},
|
||||||
"__hasura_phantom_field__ArtistId": {
|
|
||||||
"type": "column",
|
|
||||||
"column": "ArtistId",
|
|
||||||
"fields": null
|
|
||||||
},
|
|
||||||
"__hasura_phantom_field__AlbumId": {
|
"__hasura_phantom_field__AlbumId": {
|
||||||
"type": "column",
|
"type": "column",
|
||||||
"column": "AlbumId",
|
"column": "AlbumId",
|
||||||
|
@ -22,11 +22,6 @@
|
|||||||
"column": "ArtistId",
|
"column": "ArtistId",
|
||||||
"fields": null
|
"fields": null
|
||||||
},
|
},
|
||||||
"__hasura_phantom_field__ArtistId": {
|
|
||||||
"type": "column",
|
|
||||||
"column": "ArtistId",
|
|
||||||
"fields": null
|
|
||||||
},
|
|
||||||
"Tracks": {
|
"Tracks": {
|
||||||
"type": "relationship",
|
"type": "relationship",
|
||||||
"query": {
|
"query": {
|
||||||
|
@ -21,16 +21,6 @@
|
|||||||
"type": "column",
|
"type": "column",
|
||||||
"column": "ArtistId",
|
"column": "ArtistId",
|
||||||
"fields": null
|
"fields": null
|
||||||
},
|
|
||||||
"__hasura_phantom_field__AlbumId": {
|
|
||||||
"type": "column",
|
|
||||||
"column": "AlbumId",
|
|
||||||
"fields": null
|
|
||||||
},
|
|
||||||
"__hasura_phantom_field__ArtistId": {
|
|
||||||
"type": "column",
|
|
||||||
"column": "ArtistId",
|
|
||||||
"fields": null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -21,11 +21,6 @@
|
|||||||
"type": "column",
|
"type": "column",
|
||||||
"column": "first_name",
|
"column": "first_name",
|
||||||
"fields": null
|
"fields": null
|
||||||
},
|
|
||||||
"__hasura_phantom_field__id": {
|
|
||||||
"type": "column",
|
|
||||||
"column": "id",
|
|
||||||
"fields": null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user