Skip to content

Commit dfc9ca9

Browse files
committed
Nested Sorting: interface by child entity
1 parent 1d9d19d commit dfc9ca9

File tree

3 files changed

+116
-56
lines changed

3 files changed

+116
-56
lines changed

graphql/src/store/query.rs

-7
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,6 @@ fn build_order_by(
451451
})
452452
}
453453
OrderByValue::Child(parent_field_name, child_field_name) => {
454-
if entity.is_interface() {
455-
return Err(QueryExecutionError::OrderByNotSupportedError(
456-
entity.name().to_owned(),
457-
parent_field_name.clone(),
458-
));
459-
}
460-
461454
let field =
462455
sast::get_field(entity, parent_field_name.as_str()).ok_or_else(|| {
463456
QueryExecutionError::EntityFieldError(

graphql/tests/query.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ fn can_query_with_sorting_by_child_interface() {
810810
}
811811

812812
#[test]
813-
fn can_not_query_interface_with_sorting_by_child_entity() {
813+
fn can_query_interface_with_sorting_by_child_entity() {
814814
const QUERY: &str = "
815815
query {
816816
desc: medias(first: 100, orderBy: author__name, orderDirection: desc) {
@@ -828,8 +828,27 @@ fn can_not_query_interface_with_sorting_by_child_entity() {
828828
}";
829829

830830
run_query(QUERY, |result, _| {
831-
// Sorting an interface by child-level entity (derived) is not supported
832-
assert!(result.has_errors());
831+
let author1 = object! { name: "Baden" };
832+
let author2 = object! { name: "Goodwill" };
833+
let desc_medias = vec![
834+
object! { title: "Folk Tune Music Video", author: author2.clone() },
835+
object! { title: "Rock Tune Music Video", author: author2.clone() },
836+
object! { title: "Cheesy Tune Music Video", author: author2.clone() },
837+
object! { title: "Pop Tune Single Cover", author: author1.clone() },
838+
object! { title: "Rock Tune Single Cover", author: author1.clone() },
839+
object! { title: "Cheesy Tune Single Cover", author: author1.clone() },
840+
];
841+
let mut asc_medias = desc_medias.clone();
842+
843+
asc_medias.reverse();
844+
845+
let exp = object! {
846+
desc: desc_medias,
847+
asc: asc_medias,
848+
};
849+
850+
let data = extract_data!(result).unwrap();
851+
assert_eq!(data, exp);
833852
});
834853
}
835854

@@ -852,7 +871,7 @@ fn can_not_query_interface_with_sorting_by_derived_child_entity() {
852871
}";
853872

854873
run_query(QUERY, |result, _| {
855-
// Sorting an interface by child-level entity is not supported
874+
// Sorting an interface by child-level entity (derived) is not supported
856875
assert!(result.has_errors());
857876
});
858877
}

store/postgres/src/relational_queries.rs

+93-45
Original file line numberDiff line numberDiff line change
@@ -1953,7 +1953,7 @@ impl<'a> ParentLimit<'a> {
19531953
fn restrict(&self, out: &mut AstPass<Pg>) -> QueryResult<()> {
19541954
if let ParentLimit::Ranked(sort_key, range) = self {
19551955
out.push_sql(" ");
1956-
sort_key.order_by(out)?;
1956+
sort_key.order_by(out, false)?;
19571957
range.walk_ast(out.reborrow())?;
19581958
}
19591959
Ok(())
@@ -2319,7 +2319,7 @@ impl<'a> FilterWindow<'a> {
23192319
out.push_sql("select '");
23202320
out.push_sql(self.table.object.as_str());
23212321
out.push_sql("' as entity, c.id, c.vid, p.id::text as g$parent_id");
2322-
sort_key.select(&mut out)?;
2322+
sort_key.select(&mut out, false)?;
23232323
self.children(ParentLimit::Outer, block, out)
23242324
}
23252325

@@ -2810,15 +2810,20 @@ impl<'a> SortKey<'a> {
28102810
}
28112811

28122812
/// Generate selecting the sort key if it is needed
2813-
fn select(&self, out: &mut AstPass<Pg>) -> QueryResult<()> {
2813+
fn select(&self, out: &mut AstPass<Pg>, select_sort_key_directly: bool) -> QueryResult<()> {
28142814
match self {
2815-
SortKey::None => Ok(()),
2815+
SortKey::None => {}
28162816
SortKey::IdAsc(br_column) | SortKey::IdDesc(br_column) => {
28172817
if let Some(br_column) = br_column {
28182818
out.push_sql(", ");
2819-
br_column.name(out);
2819+
2820+
if select_sort_key_directly {
2821+
out.push_sql("sort_key$");
2822+
} else {
2823+
br_column.name(out);
2824+
out.push_sql(" as sort_key$");
2825+
}
28202826
}
2821-
Ok(())
28222827
}
28232828
SortKey::Key {
28242829
column,
@@ -2828,46 +2833,62 @@ impl<'a> SortKey<'a> {
28282833
if column.is_primary_key() {
28292834
return Err(constraint_violation!("SortKey::Key never uses 'id'"));
28302835
}
2831-
out.push_sql(", c.");
2832-
out.push_identifier(column.name.as_str())?;
2833-
Ok(())
2836+
if select_sort_key_directly {
2837+
out.push_sql(", sort_key$");
2838+
} else {
2839+
out.push_sql(", c.");
2840+
out.push_identifier(column.name.as_str())?;
2841+
out.push_sql(" as sort_key$");
2842+
}
28342843
}
2835-
SortKey::ChildKey(nested) => {
2836-
match nested {
2837-
ChildKey::Single(child) => {
2844+
SortKey::ChildKey(nested) => match nested {
2845+
ChildKey::Single(child) => {
2846+
if child.column.is_primary_key() {
2847+
return Err(constraint_violation!("SortKey::Key never uses 'id'"));
2848+
}
2849+
if select_sort_key_directly {
2850+
out.push_sql(", sort_key$");
2851+
} else {
2852+
out.push_sql(format!(", {}.", child.prefix).as_str());
2853+
out.push_identifier(child.column.name.as_str())?;
2854+
out.push_sql(" as sort_key$");
2855+
}
2856+
}
2857+
ChildKey::Many(children) => {
2858+
if select_sort_key_directly {
2859+
return Err(constraint_violation!("Kamil, please fix me :("));
2860+
}
2861+
2862+
for child in children.iter() {
28382863
if child.column.is_primary_key() {
28392864
return Err(constraint_violation!("SortKey::Key never uses 'id'"));
28402865
}
28412866
out.push_sql(format!(", {}.", child.prefix).as_str());
28422867
out.push_identifier(child.column.name.as_str())?;
28432868
}
2844-
ChildKey::Many(children) => {
2845-
for child in children.iter() {
2846-
if child.column.is_primary_key() {
2847-
return Err(constraint_violation!("SortKey::Key never uses 'id'"));
2848-
}
2849-
out.push_sql(format!(", {}.", child.prefix).as_str());
2850-
out.push_identifier(child.column.name.as_str())?;
2851-
}
2852-
}
2853-
}
28542869

2855-
Ok(())
2856-
}
2870+
out.push_sql(" as sort_key$");
2871+
}
2872+
},
28572873
}
2874+
Ok(())
28582875
}
28592876

28602877
/// Generate
28612878
/// order by [name direction], id
2862-
fn order_by(&self, out: &mut AstPass<Pg>) -> QueryResult<()> {
2879+
fn order_by(&self, out: &mut AstPass<Pg>, use_sort_key_alias: bool) -> QueryResult<()> {
28632880
match self {
28642881
SortKey::None => Ok(()),
28652882
SortKey::IdAsc(br_column) => {
28662883
out.push_sql("order by ");
28672884
out.push_identifier(PRIMARY_KEY_COLUMN)?;
28682885
if let Some(br_column) = br_column {
2869-
out.push_sql(", ");
2870-
br_column.bare_name(out);
2886+
if use_sort_key_alias {
2887+
out.push_sql(", sort_key$");
2888+
} else {
2889+
out.push_sql(", ");
2890+
br_column.bare_name(out);
2891+
}
28712892
}
28722893
Ok(())
28732894
}
@@ -2876,8 +2897,12 @@ impl<'a> SortKey<'a> {
28762897
out.push_identifier(PRIMARY_KEY_COLUMN)?;
28772898
out.push_sql(" desc");
28782899
if let Some(br_column) = br_column {
2879-
out.push_sql(", ");
2880-
br_column.bare_name(out);
2900+
if use_sort_key_alias {
2901+
out.push_sql(", sort_key$");
2902+
} else {
2903+
out.push_sql(", ");
2904+
br_column.bare_name(out);
2905+
}
28812906
out.push_sql(" desc");
28822907
}
28832908
Ok(())
@@ -2888,7 +2913,15 @@ impl<'a> SortKey<'a> {
28882913
direction,
28892914
} => {
28902915
out.push_sql("order by ");
2891-
SortKey::sort_expr(column, value, direction, None, None, out)
2916+
SortKey::sort_expr(
2917+
column,
2918+
value,
2919+
direction,
2920+
None,
2921+
None,
2922+
use_sort_key_alias,
2923+
out,
2924+
)
28922925
}
28932926
SortKey::ChildKey(child) => {
28942927
out.push_sql("order by ");
@@ -2899,6 +2932,7 @@ impl<'a> SortKey<'a> {
28992932
child.direction,
29002933
Some(&child.prefix),
29012934
Some("c"),
2935+
use_sort_key_alias,
29022936
out,
29032937
),
29042938
ChildKey::Many(children) => {
@@ -2939,7 +2973,7 @@ impl<'a> SortKey<'a> {
29392973
direction,
29402974
} => {
29412975
out.push_sql("order by g$parent_id, ");
2942-
SortKey::sort_expr(column, value, direction, None, None, out)
2976+
SortKey::sort_expr(column, value, direction, None, None, false, out)
29432977
}
29442978
SortKey::ChildKey(_) => {
29452979
return Err(diesel::result::Error::QueryBuilderError(
@@ -2957,6 +2991,7 @@ impl<'a> SortKey<'a> {
29572991
direction: &str,
29582992
column_prefix: Option<&str>,
29592993
rest_prefix: Option<&str>,
2994+
use_sort_key_alias: bool,
29602995
out: &mut AstPass<Pg>,
29612996
) -> QueryResult<()> {
29622997
if column.is_primary_key() {
@@ -2980,18 +3015,27 @@ impl<'a> SortKey<'a> {
29803015
FulltextAlgorithm::ProximityRank => "ts_rank_cd(",
29813016
};
29823017
out.push_sql(algorithm);
2983-
let name = column.name.as_str();
2984-
push_prefix(column_prefix, out);
2985-
out.push_identifier(name)?;
3018+
if use_sort_key_alias {
3019+
out.push_sql("sort_key$");
3020+
} else {
3021+
let name = column.name.as_str();
3022+
push_prefix(column_prefix, out);
3023+
out.push_identifier(name)?;
3024+
}
3025+
29863026
out.push_sql(", to_tsquery(");
29873027

29883028
out.push_bind_param::<Text, _>(&value.unwrap())?;
29893029
out.push_sql("))");
29903030
}
29913031
_ => {
2992-
let name = column.name.as_str();
2993-
push_prefix(column_prefix, out);
2994-
out.push_identifier(name)?;
3032+
if use_sort_key_alias {
3033+
out.push_sql("sort_key$");
3034+
} else {
3035+
let name = column.name.as_str();
3036+
push_prefix(column_prefix, out);
3037+
out.push_identifier(name)?;
3038+
}
29953039
}
29963040
}
29973041
if ENV_VARS.store.reversible_order_by_off {
@@ -3000,13 +3044,17 @@ impl<'a> SortKey<'a> {
30003044
out.push_sql(direction);
30013045
out.push_sql(" nulls last");
30023046
out.push_sql(", ");
3003-
push_prefix(rest_prefix, out);
3047+
if !use_sort_key_alias {
3048+
push_prefix(rest_prefix, out);
3049+
}
30043050
out.push_identifier(PRIMARY_KEY_COLUMN)?;
30053051
} else {
30063052
out.push_sql(" ");
30073053
out.push_sql(direction);
30083054
out.push_sql(", ");
3009-
push_prefix(rest_prefix, out);
3055+
if !use_sort_key_alias {
3056+
push_prefix(rest_prefix, out);
3057+
}
30103058
out.push_identifier(PRIMARY_KEY_COLUMN)?;
30113059
out.push_sql(" ");
30123060
out.push_sql(direction);
@@ -3314,7 +3362,7 @@ impl<'a> FilterQuery<'a> {
33143362
write_column_names(column_names, table, Some("c"), &mut out)?;
33153363
self.filtered_rows(table, filter, out.reborrow())?;
33163364
out.push_sql("\n ");
3317-
self.sort_key.order_by(&mut out)?;
3365+
self.sort_key.order_by(&mut out, false)?;
33183366
self.range.walk_ast(out.reborrow())?;
33193367
out.push_sql(") c");
33203368
Ok(())
@@ -3389,11 +3437,11 @@ impl<'a> FilterQuery<'a> {
33893437
out.push_sql("select '");
33903438
out.push_sql(table.object.as_str());
33913439
out.push_sql("' as entity, c.id, c.vid");
3392-
self.sort_key.select(&mut out)?;
3440+
self.sort_key.select(&mut out, false)?;
33933441
self.filtered_rows(table, filter, out.reborrow())?;
33943442
}
33953443
out.push_sql("\n ");
3396-
self.sort_key.order_by(&mut out)?;
3444+
self.sort_key.order_by(&mut out, true)?;
33973445
self.range.walk_ast(out.reborrow())?;
33983446

33993447
out.push_sql(")\n");
@@ -3406,7 +3454,7 @@ impl<'a> FilterQuery<'a> {
34063454
out.push_sql("select m.entity, ");
34073455
jsonb_build_object(column_names, "c", table, &mut out)?;
34083456
out.push_sql(" as data, c.id");
3409-
self.sort_key.select(&mut out)?;
3457+
self.sort_key.select(&mut out, true)?;
34103458
out.push_sql("\n from ");
34113459
out.push_sql(table.qualified_name.as_str());
34123460
out.push_sql(" c,");
@@ -3415,7 +3463,7 @@ impl<'a> FilterQuery<'a> {
34153463
out.push_bind_param::<Text, _>(&table.object.as_str())?;
34163464
}
34173465
out.push_sql("\n ");
3418-
self.sort_key.order_by(&mut out)?;
3466+
self.sort_key.order_by(&mut out, true)?;
34193467
Ok(())
34203468
}
34213469

@@ -3466,7 +3514,7 @@ impl<'a> FilterQuery<'a> {
34663514
window.children_uniform(&self.sort_key, self.block, out.reborrow())?;
34673515
}
34683516
out.push_sql("\n");
3469-
self.sort_key.order_by(&mut out)?;
3517+
self.sort_key.order_by(&mut out, true)?;
34703518
self.range.walk_ast(out.reborrow())?;
34713519
out.push_sql(") c)\n");
34723520

0 commit comments

Comments
 (0)