From d0924f7e6d149f142a5fb6da462bbb18eed6a45b Mon Sep 17 00:00:00 2001 From: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:32:39 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20max=20depth=20error=20for?= =?UTF-8?q?=20active=20sessions=20filter=20in=20targets=20(#3004)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 max depth error for active sessions filter in targets * refactor: 💡 revert route and convert operators in parser * refactor: 💡 add expr limit * refactor: 💡 add parameters to IN/NOT IN conditions * test: 💍 fix tests * docs: ✏️ add comment --- addons/api/addon/utils/sqlite-query.js | 30 +++++++++++++++++++ .../api/tests/unit/utils/sqlite-query-test.js | 6 ++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/addons/api/addon/utils/sqlite-query.js b/addons/api/addon/utils/sqlite-query.js index 75ec96c2c..458a657fa 100644 --- a/addons/api/addon/utils/sqlite-query.js +++ b/addons/api/addon/utils/sqlite-query.js @@ -75,6 +75,34 @@ function addFilterConditions({ filters, parameters, conditions }) { continue; } + // When attribute conditions are a series of equals/notEquals + // replace with in/notIn to avoid hitting the sqlite maximum + // expression tree depth. + const firstOperator = Object.keys(filterValueArray[0])[0]; + const allOperatorsEqual = filterValueArray + .flatMap((item) => Object.keys(item)) + .every((op) => op === firstOperator); + if ( + filterValueArray.length > 1 && + (firstOperator === 'equals' || firstOperator === 'notEquals') && + allOperatorsEqual + ) { + const operation = firstOperator === 'equals' ? 'in' : 'notIn'; + const values = filterValueArray + .filter((f) => f) + .map((filterObjValue) => { + let value = Object.values(filterObjValue)[0]; + if (typeOf(value) === 'date') { + value = value.toISOString(); + } + parameters.push(value); + return value; + }); + const filterCondition = `${key}${OPERATORS[operation](values)}`; + conditions.push(parenthetical(filterCondition)); + continue; + } + const filterConditions = filterValueArray .filter((f) => f) .map((filterObjValue) => { @@ -195,6 +223,8 @@ const OPERATORS = { lt: ' < ?', lte: ' <= ?', contains: ' LIKE ?', + in: (values) => ` IN (${values.map(() => '?').join(', ')})`, + notIn: (values) => ` NOT IN (${values.map(() => '?').join(', ')})`, }; // Logical Operators diff --git a/addons/api/tests/unit/utils/sqlite-query-test.js b/addons/api/tests/unit/utils/sqlite-query-test.js index cac353217..57a47cbfe 100644 --- a/addons/api/tests/unit/utils/sqlite-query-test.js +++ b/addons/api/tests/unit/utils/sqlite-query-test.js @@ -150,7 +150,7 @@ module('Unit | Utility | sqlite-query', function (hooks) { }, }, expectedWhereClause: - 'WHERE (id != ? AND id != ?) AND (status = ? OR status = ?) AND (type = ?)', + 'WHERE (id NOT IN (?, ?)) AND (status IN (?, ?)) AND (type = ?)', expectedParams: ['id1', 'id2', 'active', 'pending', 'ssh'], }, }, @@ -271,7 +271,7 @@ module('Unit | Utility | sqlite-query', function (hooks) { sql, ` SELECT * FROM "target" - WHERE (id != ? AND id != ?) AND (status = ? OR status = ?) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?) + WHERE (id NOT IN (?, ?)) AND (status IN (?, ?)) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?) ORDER BY created_time DESC`.removeExtraWhiteSpace(), ); assert.deepEqual(parameters, [ @@ -307,7 +307,7 @@ module('Unit | Utility | sqlite-query', function (hooks) { sql, ` SELECT data FROM "target" - WHERE (type = ?) AND (status = ? OR status = ?) AND (created_time >= ?) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?) + WHERE (type = ?) AND (status IN (?, ?)) AND (created_time >= ?) AND rowid IN (SELECT rowid FROM target_fts WHERE target_fts MATCH ?) ORDER BY name COLLATE NOCASE DESC, name DESC LIMIT ? OFFSET ?`.removeExtraWhiteSpace(), );