这是indexloc提供的服务,不要输入任何密码
Skip to content

ensure correct order of sort criteria in mongodb query #172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This changelog documents the changes between release versions.
### Fixed

- Filtering on field of related collection inside nested object that is not selected for output ([#171](https://github.com/hasura/ndc-mongodb/pull/171))
- Ensure correct ordering of sort criteria in MongoDB query plan ([#172](https://github.com/hasura/ndc-mongodb/pull/172))

## [1.8.2] - 2025-06-13

Expand Down
31 changes: 31 additions & 0 deletions crates/integration-tests/src/tests/filtering.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use insta::assert_yaml_snapshot;
use ndc_test_helpers::{binop, field, query, query_request, target, value, variable};
use serde_json::json;

use crate::{connector::Connector, graphql_query, run_connector_query};

Expand Down Expand Up @@ -105,3 +106,33 @@ async fn filters_by_uuid() -> anyhow::Result<()> {
);
Ok(())
}

#[tokio::test]
async fn filters_by_multiple_criteria_using_variable() -> anyhow::Result<()> {
assert_yaml_snapshot!(
graphql_query(
r#"
query TestQuery($filter: [MoviesOrderBy!] = {}) {
movies(
order_by: $filter
where: { year: { _gt: 0 }, imdb: { rating: { _gt: 9 } } }
limit: 15
) {
title
year
rated
}
}
"#
)
.variables(json!({
"filter": [
{ "year": "Desc" },
{ "rated": "Desc" },
]
}))
.run()
.await?
);
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
source: crates/integration-tests/src/tests/filtering.rs
expression: "graphql_query(r#\"\n query TestQuery($filter: [MoviesOrderBy!] = {}) {\n movies(\n order_by: $filter\n where: { year: { _gt: 0 }, imdb: { rating: { _gt: 9 } } }\n limit: 15\n ) {\n title\n year\n rated\n }\n }\n \"#).variables(json!({\n \"filter\": [{ \"year\": \"Desc\" }, { \"rated\": \"Desc\" },]\n})).run().await?"
---
data:
movies:
- title: "A Brave Heart: The Lizzie Velasquez Story"
year: 2015
rated: PG-13
- title: The Real Miyagi
year: 2015
rated: ~
- title: Over the Garden Wall
year: 2014
rated: TV-PG
- title: Frozen Planet
year: 2011
rated: ~
- title: Human Planet
year: 2011
rated: ~
- title: Life
year: 2009
rated: PG
- title: Planet Earth
year: 2006
rated: TV-G
- title: Band of Brothers
year: 2001
rated: TV-MA
- title: The Blue Planet
year: 2001
rated: ~
- title: Pride and Prejudice
year: 1995
rated: ~
- title: Baseball
year: 1994
rated: TV-PG
- title: The Shawshank Redemption
year: 1994
rated: R
- title: The Shawshank Redemption
year: 1994
rated: R
- title: The Civil War
year: 1990
rated: ~
- title: The Civil War
year: 1990
rated: ~
errors: ~
47 changes: 44 additions & 3 deletions crates/mongodb-agent-common/src/query/make_sort.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{collections::BTreeMap, iter::once};

use indexmap::IndexMap;
use itertools::join;
use mongodb::bson::bson;
use mongodb_support::aggregate::{SortDocument, Stage};
Expand Down Expand Up @@ -42,7 +43,7 @@ pub fn make_sort_stages(order_by: &OrderBy) -> Result<Vec<Stage>> {
fn make_sort(order_by: &OrderBy) -> Result<(SortDocument, RequiredAliases<'_>)> {
let OrderBy { elements } = order_by;

let keys_directions_expressions: BTreeMap<String, (OrderDirection, Option<ColumnRef<'_>>)> =
let keys_directions_expressions: IndexMap<String, (OrderDirection, Option<ColumnRef<'_>>)> =
elements
.iter()
.map(|obe| {
Expand All @@ -53,7 +54,7 @@ fn make_sort(order_by: &OrderBy) -> Result<(SortDocument, RequiredAliases<'_>)>
};
Ok((key, (obe.order_direction, required_alias)))
})
.collect::<Result<BTreeMap<_, _>>>()?;
.collect::<Result<IndexMap<_, _>>>()?; // IndexMap preserves insertion order
Comment on lines -56 to +57
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the fix - the rest of the PR is testing


let sort_document = keys_directions_expressions
.iter()
Expand Down Expand Up @@ -112,7 +113,7 @@ fn safe_alias(target: &OrderByTarget) -> Result<String> {

#[cfg(test)]
mod tests {
use mongodb::bson::doc;
use mongodb::bson::{self, doc};
use mongodb_support::aggregate::SortDocument;
use ndc_models::{FieldName, OrderDirection};
use ndc_query_plan::OrderByElement;
Expand Down Expand Up @@ -175,4 +176,44 @@ mod tests {
assert_eq!(actual, (expected_sort_doc, expected_aliases));
Ok(())
}

#[test]
fn serializes_sort_criteria_in_expected_order() -> anyhow::Result<()> {
let first_criteria = "year";
let second_criteria = "rated";
let order_by = OrderBy {
elements: vec![
OrderByElement {
order_direction: OrderDirection::Desc,
target: ndc_query_plan::OrderByTarget::Column {
name: first_criteria.into(),
field_path: None,
path: Default::default(),
},
},
OrderByElement {
order_direction: OrderDirection::Desc,
target: ndc_query_plan::OrderByTarget::Column {
name: second_criteria.into(),
field_path: None,
path: Default::default(),
},
},
],
};
let (sort_doc, _) = make_sort(&order_by)?;
let serialized = bson::to_document(&sort_doc)?;
let mut sort_keys = serialized.keys();
assert_eq!(
sort_keys.next(),
Some(&first_criteria.to_string()),
"first sort criteria"
);
assert_eq!(
sort_keys.next(),
Some(&second_criteria.to_string()),
"second sort criteria"
);
Ok(())
}
}