Skip to content

Commit 4f21209

Browse files
goffrieConvex, Inc.
authored and
Convex, Inc.
committed
Reject queries that have too many operators (#37200)
GitOrigin-RevId: 4ed1a3de30568fdcd65e892efb99babf3977fc67
1 parent 0706e63 commit 4f21209

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

crates/common/src/json/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::{
2121
QuerySource,
2222
Search,
2323
SearchFilterExpression,
24+
MAX_QUERY_OPERATORS,
2425
},
2526
types::{
2627
IndexName,
@@ -298,6 +299,11 @@ impl TryFrom<JsonValue> for Query {
298299

299300
fn try_from(value: JsonValue) -> Result<Self> {
300301
let json_query: JsonQuery = serde_json::from_value(value)?;
302+
anyhow::ensure!(
303+
json_query.operators.len() <= MAX_QUERY_OPERATORS,
304+
"Query has too many operators: {}",
305+
json_query.operators.len()
306+
);
301307
Ok(Query {
302308
source: json_query.source.try_into()?,
303309
operators: json_query

crates/common/src/query.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,14 @@ pub enum QueryOperator {
10181018
Limit(usize),
10191019
}
10201020

1021+
/// The maximum number of `QueryOperator`s allowed on a single query.
1022+
/// This is only enforced for queries deserialized from JSON as we assume other
1023+
/// queries come from the system.
1024+
///
1025+
/// N.B.: this value is replicated in `query_impl.ts` in the `convex` npm
1026+
/// package.
1027+
pub const MAX_QUERY_OPERATORS: usize = 256;
1028+
10211029
/// A query, represented as a source and a chain of operators to apply as a lazy
10221030
/// iteration.
10231031
#[derive(Clone, Debug, PartialEq)]

npm-packages/convex/src/server/impl/query_impl.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
import { validateArg, validateArgIsNonNegativeInteger } from "./validate.js";
2020
import { version } from "../../index.js";
2121

22+
const MAX_QUERY_OPERATORS = 256;
23+
2224
type QueryOperator = { filter: JSONValue } | { limit: number };
2325
type Source =
2426
| { type: "FullTableScan"; tableName: string; order: "asc" | "desc" | null }
@@ -223,6 +225,11 @@ export class QueryImpl implements Query<GenericTableInfo> {
223225
): any {
224226
validateArg(predicate, 1, "filter", "predicate");
225227
const query = this.takeQuery();
228+
if (query.operators.length >= MAX_QUERY_OPERATORS) {
229+
throw new Error(
230+
`Can't construct query with more than ${MAX_QUERY_OPERATORS} operators`,
231+
);
232+
}
226233
query.operators.push({
227234
filter: serializeExpression(predicate(filterBuilderImpl)),
228235
});

0 commit comments

Comments
 (0)