[PR #7138] [CLOSED] Fix AQL filter dropping all but first operator on a single field #21320

Closed
opened 2026-04-14 22:01:23 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/actualbudget/actual/pull/7138
Author: @shmup
Created: 3/6/2026
Status: Closed

Base: masterHead: fix/aql-multi-operator-filter


📝 Commits (2)

  • 14cd28c Fix AQL filter dropping all but first operator on a single field
  • 94405aa Add release notes for #7138

📊 Changes

3 files changed (+33 additions, -0 deletions)

View changed files

📝 packages/loot-core/src/server/aql/compiler.test.ts (+15 -0)
📝 packages/loot-core/src/server/aql/compiler.ts (+12 -0)
upcoming-release-notes/7138.md (+6 -0)

📄 Description

Description

I was querying transactions by date range using the API:

q('transactions')
  .filter({ date: { $gte: '2025-03-01', $lt: '2025-04-01' } })
  .select(['id', 'date', 'amount', 'category'])

Expected 76 transactions for March 2025, got 1398, everything from
March onward. The $gte was applied but $lt was silently ignored.

compileOp only reads the first key from the operator object via
const [op] = Object.keys(opExpr), so when a filter has multiple
operators on one field, everything after the first is dropped.

The array form { date: [{ $gte: ... }, { $lt: ... }] } works fine
because that path already maps each element to a separate compileOp
call. This fix applies the same split-and-AND pattern to multi-key
operator objects.

Fixes #7137

Testing

  • Added a test in compiler.test.ts for multi-operator object filters
  • Verified against a live Actual Budget instance that runQuery with
    { $gte, $lt } now returns only transactions in the expected range

Checklist

  • Release notes added (see link above)
  • No obvious regressions in affected areas
  • Self-review has been performed

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 27 14.89 MB → 14.89 MB (-1.15 kB) -0.01%
loot-core 1 5.82 MB → 5.82 MB (+299 B) +0.00%
api 1 4.43 MB → 4.43 MB (+275 B) +0.01%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
27 14.89 MB → 14.89 MB (-1.15 kB) -0.01%
Changeset
File Δ Size
locale/pl.json 📈 +985 B (+1.09%) 88.37 kB → 89.33 kB
locale/en.json 📈 +88 B (+0.05%) 170.33 kB → 170.42 kB
locale/ca.json 📉 -185 B (-0.10%) 188.11 kB → 187.93 kB
locale/de.json 📉 -183 B (-0.10%) 180.07 kB → 179.89 kB
locale/nb-NO.json 📉 -166 B (-0.10%) 156.96 kB → 156.8 kB
locale/it.json 📉 -182 B (-0.10%) 171.16 kB → 170.98 kB
locale/es.json 📉 -186 B (-0.10%) 174.55 kB → 174.37 kB
locale/uk.json 📉 -232 B (-0.11%) 214.88 kB → 214.65 kB
locale/fr.json 📉 -194 B (-0.11%) 179.6 kB → 179.41 kB
locale/nl.json 📉 -156 B (-0.13%) 113.21 kB ��� 113.06 kB
locale/da.json 📉 -158 B (-0.15%) 106.35 kB → 106.2 kB
locale/th.json 📉 -303 B (-0.16%) 181.87 kB → 181.58 kB
locale/pt-BR.json 📉 -307 B (-0.16%) 183.19 kB → 182.89 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/pl.js 88.37 kB → 89.33 kB (+985 B) +1.09%
static/js/en.js 170.33 kB → 170.42 kB (+88 B) +0.05%

Smaller

Asset File Size % Changed
static/js/pt-BR.js 183.19 kB → 182.89 kB (-307 B) -0.16%
static/js/th.js 181.87 kB → 181.58 kB (-303 B) -0.16%
static/js/uk.js 214.88 kB → 214.65 kB (-232 B) -0.11%
static/js/fr.js 179.6 kB → 179.41 kB (-194 B) -0.11%
static/js/es.js 174.55 kB → 174.37 kB (-186 B) -0.10%
static/js/ca.js 188.11 kB → 187.93 kB (-185 B) -0.10%
static/js/de.js 180.07 kB → 179.89 kB (-183 B) -0.10%
static/js/it.js 171.16 kB → 170.98 kB (-182 B) -0.10%
static/js/nb-NO.js 156.96 kB → 156.8 kB (-166 B) -0.10%
static/js/da.js 106.35 kB → 106.2 kB (-158 B) -0.15%
static/js/nl.js 113.21 kB → 113.06 kB (-156 B) -0.13%

Unchanged

Asset File Size % Changed
static/js/index.js 9.54 MB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 12.94 kB 0%
static/js/workbox-window.prod.es5.js 5.64 kB 0%
static/js/en-GB.js 7.18 kB 0%
static/js/resize-observer.js 18.37 kB 0%
static/js/BackgroundImage.js 120.54 kB 0%
static/js/ReportRouter.js 1.16 MB 0%
static/js/narrow.js 638.11 kB 0%
static/js/TransactionList.js 106.22 kB 0%
static/js/wide.js 164.15 kB 0%
static/js/AppliedFilters.js 9.71 kB 0%
static/js/usePayeeRuleCounts.js 10.04 kB 0%
static/js/useTransactionBatchActions.js 13.23 kB 0%
static/js/FormulaEditor.js 1.04 MB 0%

loot-core

Total

Files count Total bundle size % Changed
1 5.82 MB → 5.82 MB (+299 B) +0.00%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts 📈 +299 B (+0.95%) 30.87 kB → 31.16 kB
View detailed bundle breakdown

Added

Asset File Size % Changed
kcab.worker.DUK7Xc7n.js 0 B → 5.82 MB (+5.82 MB) -

Removed

Asset File Size % Changed
kcab.worker.MNtpiHkH.js 5.82 MB → 0 B (-5.82 MB) -100%

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged
No assets were unchanged


api

Total

Files count Total bundle size % Changed
1 4.43 MB → 4.43 MB (+275 B) +0.01%
Changeset
File Δ Size
src/server/aql/compiler.ts 📈 +275 B (+0.98%) 27.33 kB → 27.6 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
bundle.api.js 4.43 MB → 4.43 MB (+275 B) +0.01%

Smaller
No assets were smaller

Unchanged
No assets were unchanged


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/actualbudget/actual/pull/7138 **Author:** [@shmup](https://github.com/shmup) **Created:** 3/6/2026 **Status:** ❌ Closed **Base:** `master` ← **Head:** `fix/aql-multi-operator-filter` --- ### 📝 Commits (2) - [`14cd28c`](https://github.com/actualbudget/actual/commit/14cd28c89ec13e893dd4d09c74ef2d4fc7715fb8) Fix AQL filter dropping all but first operator on a single field - [`94405aa`](https://github.com/actualbudget/actual/commit/94405aa93eae8ed356894118bee51d8d54bb7f50) Add release notes for #7138 ### 📊 Changes **3 files changed** (+33 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `packages/loot-core/src/server/aql/compiler.test.ts` (+15 -0) 📝 `packages/loot-core/src/server/aql/compiler.ts` (+12 -0) ➕ `upcoming-release-notes/7138.md` (+6 -0) </details> ### 📄 Description ## Description I was querying transactions by date range using the API: ```js q('transactions') .filter({ date: { $gte: '2025-03-01', $lt: '2025-04-01' } }) .select(['id', 'date', 'amount', 'category']) ``` Expected 76 transactions for March 2025, got 1398, everything from March onward. The `$gte` was applied but `$lt` was silently ignored. `compileOp` only reads the first key from the operator object via `const [op] = Object.keys(opExpr)`, so when a filter has multiple operators on one field, everything after the first is dropped. The array form `{ date: [{ $gte: ... }, { $lt: ... }] }` works fine because that path already maps each element to a separate `compileOp` call. This fix applies the same split-and-AND pattern to multi-key operator objects. ## Related issue(s) Fixes #7137 ## Testing - Added a test in `compiler.test.ts` for multi-operator object filters - Verified against a live Actual Budget instance that `runQuery` with `{ $gte, $lt }` now returns only transactions in the expected range ## Checklist - [ ] Release notes added (see link above) - [x] No obvious regressions in affected areas - [x] Self-review has been performed <!--- actual-bot-sections ---> <hr /> <!--- bundlestats-action-comment key:combined start ---> ### Bundle Stats Bundle | Files count | Total bundle size | % Changed ------ | ----------- | ----------------- | --------- desktop-client | 27 | 14.89 MB → 14.89 MB (-1.15 kB) | -0.01% loot-core | 1 | 5.82 MB → 5.82 MB (+299 B) | +0.00% api | 1 | 4.43 MB → 4.43 MB (+275 B) | +0.01% <details> <summary>View detailed bundle stats</summary> #### desktop-client **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 27 | 14.89 MB → 14.89 MB (-1.15 kB) | -0.01% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `locale/pl.json` | 📈 +985 B (+1.09%) | 88.37 kB → 89.33 kB `locale/en.json` | 📈 +88 B (+0.05%) | 170.33 kB → 170.42 kB `locale/ca.json` | 📉 -185 B (-0.10%) | 188.11 kB → 187.93 kB `locale/de.json` | 📉 -183 B (-0.10%) | 180.07 kB → 179.89 kB `locale/nb-NO.json` | 📉 -166 B (-0.10%) | 156.96 kB → 156.8 kB `locale/it.json` | 📉 -182 B (-0.10%) | 171.16 kB → 170.98 kB `locale/es.json` | 📉 -186 B (-0.10%) | 174.55 kB → 174.37 kB `locale/uk.json` | 📉 -232 B (-0.11%) | 214.88 kB → 214.65 kB `locale/fr.json` | 📉 -194 B (-0.11%) | 179.6 kB → 179.41 kB `locale/nl.json` | 📉 -156 B (-0.13%) | 113.21 kB ��� 113.06 kB `locale/da.json` | 📉 -158 B (-0.15%) | 106.35 kB → 106.2 kB `locale/th.json` | 📉 -303 B (-0.16%) | 181.87 kB → 181.58 kB `locale/pt-BR.json` | 📉 -307 B (-0.16%) | 183.19 kB → 182.89 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- static/js/pl.js | 88.37 kB → 89.33 kB (+985 B) | +1.09% static/js/en.js | 170.33 kB → 170.42 kB (+88 B) | +0.05% **Smaller** Asset | File Size | % Changed ----- | --------- | --------- static/js/pt-BR.js | 183.19 kB → 182.89 kB (-307 B) | -0.16% static/js/th.js | 181.87 kB → 181.58 kB (-303 B) | -0.16% static/js/uk.js | 214.88 kB → 214.65 kB (-232 B) | -0.11% static/js/fr.js | 179.6 kB → 179.41 kB (-194 B) | -0.11% static/js/es.js | 174.55 kB → 174.37 kB (-186 B) | -0.10% static/js/ca.js | 188.11 kB → 187.93 kB (-185 B) | -0.10% static/js/de.js | 180.07 kB → 179.89 kB (-183 B) | -0.10% static/js/it.js | 171.16 kB → 170.98 kB (-182 B) | -0.10% static/js/nb-NO.js | 156.96 kB → 156.8 kB (-166 B) | -0.10% static/js/da.js | 106.35 kB → 106.2 kB (-158 B) | -0.15% static/js/nl.js | 113.21 kB → 113.06 kB (-156 B) | -0.13% **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- static/js/index.js | 9.54 MB | 0% static/js/indexeddb-main-thread-worker-e59fee74.js | 12.94 kB | 0% static/js/workbox-window.prod.es5.js | 5.64 kB | 0% static/js/en-GB.js | 7.18 kB | 0% static/js/resize-observer.js | 18.37 kB | 0% static/js/BackgroundImage.js | 120.54 kB | 0% static/js/ReportRouter.js | 1.16 MB | 0% static/js/narrow.js | 638.11 kB | 0% static/js/TransactionList.js | 106.22 kB | 0% static/js/wide.js | 164.15 kB | 0% static/js/AppliedFilters.js | 9.71 kB | 0% static/js/usePayeeRuleCounts.js | 10.04 kB | 0% static/js/useTransactionBatchActions.js | 13.23 kB | 0% static/js/FormulaEditor.js | 1.04 MB | 0% </div> </details> --- #### loot-core **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 5.82 MB → 5.82 MB (+299 B) | +0.00% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts` | 📈 +299 B (+0.95%) | 30.87 kB → 31.16 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.DUK7Xc7n.js | 0 B → 5.82 MB (+5.82 MB) | - **Removed** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.MNtpiHkH.js | 5.82 MB → 0 B (-5.82 MB) | -100% **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> --- #### api **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 4.43 MB → 4.43 MB (+275 B) | +0.01% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `src/server/aql/compiler.ts` | 📈 +275 B (+0.98%) | 27.33 kB → 27.6 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- bundle.api.js | 4.43 MB → 4.43 MB (+275 B) | +0.01% **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> </details> <!--- bundlestats-action-comment key:combined end ---> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-14 22:01:23 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#21320