Skip to content

Commit aefeff1

Browse files
committed
Sorting an interface by child-level entity
1 parent c2ba787 commit aefeff1

File tree

3 files changed

+176
-56
lines changed

3 files changed

+176
-56
lines changed

graphql/src/store/query.rs

+38-13
Original file line numberDiff line numberDiff line change
@@ -561,22 +561,47 @@ fn build_order_by(
561561
})
562562
}
563563
OrderByValue::Child(parent_field_name, child_field_name) => {
564-
if entity.is_interface() {
565-
return Err(QueryExecutionError::OrderByNotSupportedError(
566-
entity.name().to_owned(),
567-
parent_field_name,
568-
));
569-
}
564+
// Finds the field that connects the parent entity to the child entity.
565+
// In the case of an interface, we need to find the field on one of the types that implement the interface,
566+
// as the `@derivedFrom` directive is only allowed on object types.
567+
let field = match entity {
568+
ObjectOrInterface::Object(_) => {
569+
sast::get_field(entity, parent_field_name.as_str()).ok_or_else(|| {
570+
QueryExecutionError::EntityFieldError(
571+
entity.name().to_owned(),
572+
parent_field_name.clone(),
573+
)
574+
})?
575+
}
576+
ObjectOrInterface::Interface(_) => {
577+
let object_types = schema
578+
.types_for_interface()
579+
.get(&EntityType::new(entity.name().to_string()))
580+
.ok_or(QueryExecutionError::EntityFieldError(
581+
entity.name().to_owned(),
582+
parent_field_name.clone(),
583+
))?;
570584

571-
let field =
572-
sast::get_field(entity, parent_field_name.as_str()).ok_or_else(|| {
573-
QueryExecutionError::EntityFieldError(
574-
entity.name().to_owned(),
575-
parent_field_name.clone(),
576-
)
577-
})?;
585+
if let Some(first_entity) = object_types.first() {
586+
sast::get_field(first_entity, parent_field_name.as_str()).ok_or_else(
587+
|| {
588+
QueryExecutionError::EntityFieldError(
589+
entity.name().to_owned(),
590+
parent_field_name.clone(),
591+
)
592+
},
593+
)?
594+
} else {
595+
Err(QueryExecutionError::EntityFieldError(
596+
entity.name().to_owned(),
597+
parent_field_name.clone(),
598+
))?
599+
}
600+
}
601+
};
578602
let derived = field.is_derived();
579603
let base_type = field.field_type.get_base_type();
604+
580605
let child_entity = schema
581606
.object_or_interface(base_type)
582607
.ok_or_else(|| QueryExecutionError::NamedTypeError(base_type.into()))?;

graphql/tests/query.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ fn can_query_with_sorting_by_child_interface() {
978978
}
979979

980980
#[test]
981-
fn can_not_query_interface_with_sorting_by_child_entity() {
981+
fn can_query_interface_with_sorting_by_child_entity() {
982982
const QUERY: &str = "
983983
query {
984984
desc: medias(first: 100, orderBy: author__name, orderDirection: desc) {
@@ -996,8 +996,27 @@ fn can_not_query_interface_with_sorting_by_child_entity() {
996996
}";
997997

998998
run_query(QUERY, |result, _| {
999-
// Sorting an interface by child-level entity (derived) is not supported
1000-
assert!(result.has_errors());
999+
let author1 = object! { name: "Baden" };
1000+
let author2 = object! { name: "Goodwill" };
1001+
let desc_medias = vec![
1002+
object! { title: "Folk Tune Music Video", author: author2.clone() },
1003+
object! { title: "Rock Tune Music Video", author: author2.clone() },
1004+
object! { title: "Cheesy Tune Music Video", author: author2.clone() },
1005+
object! { title: "Pop Tune Single Cover", author: author1.clone() },
1006+
object! { title: "Rock Tune Single Cover", author: author1.clone() },
1007+
object! { title: "Cheesy Tune Single Cover", author: author1.clone() },
1008+
];
1009+
let mut asc_medias = desc_medias.clone();
1010+
1011+
asc_medias.reverse();
1012+
1013+
let exp = object! {
1014+
desc: desc_medias,
1015+
asc: asc_medias,
1016+
};
1017+
1018+
let data = extract_data!(result).unwrap();
1019+
assert_eq!(data, exp);
10011020
});
10021021
}
10031022

@@ -1020,8 +1039,27 @@ fn can_not_query_interface_with_sorting_by_derived_child_entity() {
10201039
}";
10211040

10221041
run_query(QUERY, |result, _| {
1023-
// Sorting an interface by child-level entity is not supported
1024-
assert!(result.has_errors());
1042+
let exp = object! {
1043+
desc: vec![
1044+
object! { title: "Rock Tune Music Video", song : object! { title: "Rock Tune" } },
1045+
object! { title: "Rock Tune Single Cover", song : object! { title: "Rock Tune" } },
1046+
object! { title: "Pop Tune Single Cover", song : object! { title: "Pop Tune" } },
1047+
object! { title: "Folk Tune Music Video", song : object! { title: "Folk Tune" } },
1048+
object! { title: "Cheesy Tune Music Video", song : object! { title: "Cheesy Tune" } },
1049+
object! { title: "Cheesy Tune Single Cover", song : object! { title: "Cheesy Tune" } },
1050+
],
1051+
asc: vec![
1052+
object! { title: "Cheesy Tune Single Cover", song : object! { title: "Cheesy Tune" } },
1053+
object! { title: "Cheesy Tune Music Video", song : object! { title: "Cheesy Tune" } },
1054+
object! { title: "Folk Tune Music Video", song : object! { title: "Folk Tune" } },
1055+
object! { title: "Pop Tune Single Cover", song : object! { title: "Pop Tune" } },
1056+
object! { title: "Rock Tune Single Cover", song : object! { title: "Rock Tune" } },
1057+
object! { title: "Rock Tune Music Video", song : object! { title: "Rock Tune" } },
1058+
]
1059+
};
1060+
1061+
let data = extract_data!(result).unwrap();
1062+
assert_eq!(data, exp);
10251063
});
10261064
}
10271065

0 commit comments

Comments
 (0)