Skip to content

Commit 98639f9

Browse files
authored
fix: allow negative-one take for find first (#5616)
Fixes [28107](prisma/prisma#28107) and [5615](#5615)
1 parent 1c57fdc commit 98639f9

File tree

6 files changed

+69
-14
lines changed

6 files changed

+69
-14
lines changed

query-compiler/query-compiler/src/translate/query/read.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub(crate) fn translate_read_query(query: ReadQuery, builder: &dyn QueryBuilder)
7878
}
7979

8080
match take {
81-
Take::One => Expression::Unique(Box::new(expr)),
81+
Take::One | Take::NegativeOne => Expression::Unique(Box::new(expr)),
8282
_ => expr,
8383
}
8484
}

query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/simple/find_first.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ mod find_first_query {
3232
r#"{"data":{"findFirstTestModel":{"id":2}}}"#
3333
);
3434

35+
assert_query!(
36+
runner,
37+
"query { findFirstTestModel(where: { field: { not: null }}, orderBy: { id: asc }, take: -1) { id }}",
38+
r#"{"data":{"findFirstTestModel":{"id":5}}}"#
39+
);
40+
41+
assert_query!(
42+
runner,
43+
"query { findFirstTestModel(where: { field: { not: null }}, cursor: { id: 2 }, orderBy: { id: asc }, take: -1, skip: 1) { id }}",
44+
r#"{"data":{"findFirstTestModel":{"id":1}}}"#
45+
);
46+
47+
assert_query!(
48+
runner,
49+
"query { findFirstTestModel(where: { field: { not: null }}, orderBy: { id: desc }, take: -1) { id }}",
50+
r#"{"data":{"findFirstTestModel":{"id":1}}}"#
51+
);
52+
53+
assert_query!(
54+
runner,
55+
"query { findFirstTestModel(where: { field: { not: null }}, cursor: { id: 2 }, orderBy: { id: desc }, take: -1, skip: 1) { id }}",
56+
r#"{"data":{"findFirstTestModel":{"id":5}}}"#
57+
);
58+
3559
Ok(())
3660
}
3761

@@ -48,6 +72,34 @@ mod find_first_query {
4872
Ok(())
4973
}
5074

75+
#[connector_test]
76+
async fn find_first_with_invalid_take_value(runner: Runner) -> TestResult<()> {
77+
test_data(&runner).await?;
78+
79+
assert_error!(
80+
runner,
81+
r#"query { findFirstTestModel(orderBy: { id: asc }, take: 0) { id }}"#,
82+
2019,
83+
"The 'findFirst' operation cannot be used with a 'take' argument that isn't 1 or -1"
84+
);
85+
86+
assert_error!(
87+
runner,
88+
r#"query { findFirstTestModel(orderBy: { id: asc }, take: 2) { id }}"#,
89+
2019,
90+
"The 'findFirst' operation cannot be used with a 'take' argument that isn't 1 or -1"
91+
);
92+
93+
assert_error!(
94+
runner,
95+
r#"query { findFirstTestModel(orderBy: { id: asc }, take: -2) { id }}"#,
96+
2019,
97+
"The 'findFirst' operation cannot be used with a 'take' argument that isn't 1 or -1"
98+
);
99+
100+
Ok(())
101+
}
102+
51103
async fn test_data(runner: &Runner) -> TestResult<()> {
52104
test_row(runner, r#"{ id: 1, field: "test1" }"#).await?;
53105
test_row(runner, r#"{ id: 2, field: "test2" }"#).await?;

query-engine/connectors/mongodb-query-connector/src/query_builder/read_query_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ fn take(take: Take, ignore: bool) -> Option<i64> {
463463
} else {
464464
match take {
465465
Take::All => None,
466-
Take::One => Some(1),
466+
Take::One | Take::NegativeOne => Some(1),
467467
Take::Some(n) => Some(n.abs()),
468468
}
469469
}

query-engine/core/src/query_ast/read.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ impl ReadQuery {
1919
pub fn is_unique(&self) -> bool {
2020
match self {
2121
ReadQuery::RecordQuery(_) => true,
22-
ReadQuery::ManyRecordsQuery(q) => q.args.take == Take::One,
23-
ReadQuery::RelatedRecordsQuery(q) => q.args.take == Take::One,
22+
ReadQuery::ManyRecordsQuery(q) => q.args.take == Take::One || q.args.take == Take::NegativeOne,
23+
ReadQuery::RelatedRecordsQuery(q) => q.args.take == Take::One || q.args.take == Take::NegativeOne,
2424
ReadQuery::AggregateRecordsQuery(_) => false,
2525
}
2626
}

query-engine/core/src/query_graph_builder/read/first.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ pub(crate) fn find_first_or_throw(
2626
fn try_limit_to_one(mut query: ReadQuery) -> QueryGraphBuilderResult<ReadQuery> {
2727
match query {
2828
ReadQuery::ManyRecordsQuery(ref mut m) => {
29-
if matches!(m.args.take, Take::All | Take::Some(1)) {
30-
m.args.take = Take::One;
31-
} else {
32-
return Err(QueryGraphBuilderError::InputError(
33-
"The 'findFirst' operation cannot be used with a 'take' argument that isn't 1".into(),
34-
));
35-
}
29+
m.args.take = match m.args.take {
30+
Take::All | Take::Some(1) => Take::One,
31+
Take::Some(-1) => Take::NegativeOne,
32+
_ => {
33+
return Err(QueryGraphBuilderError::InputError(
34+
"The 'findFirst' operation cannot be used with a 'take' argument that isn't 1 or -1".into(),
35+
));
36+
}
37+
};
3638
Ok(query)
3739
}
3840
_ => Ok(query),

query-engine/query-structure/src/query_arguments.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub struct QueryArguments {
3232
pub enum Take {
3333
All,
3434
One,
35+
NegativeOne,
3536
Some(i64),
3637
}
3738

@@ -47,15 +48,15 @@ impl Take {
4748
pub fn abs(self) -> Option<i64> {
4849
match self {
4950
Take::All => None,
50-
Take::One => Some(1),
51+
Take::One | Take::NegativeOne => Some(1),
5152
Take::Some(n) => Some(n.abs()),
5253
}
5354
}
5455

5556
pub fn is_reversed(self) -> bool {
5657
match self {
57-
Take::All => false,
58-
Take::One => false,
58+
Take::All | Take::One => false,
59+
Take::NegativeOne => true,
5960
Take::Some(n) => n < 0,
6061
}
6162
}

0 commit comments

Comments
 (0)