Fixes query for tag starting in $ (#7324)

* Fixes query for tag starting in $

* Update packages/loot-core/src/server/transactions/transaction-rules.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply coderabbitai suggestion

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
gust0717
2026-04-08 11:45:00 -03:00
committed by GitHub
parent 446fde6cd9
commit 2bbcbaee73
3 changed files with 46 additions and 6 deletions

View File

@@ -510,6 +510,36 @@ describe('Transaction rules', () => {
// todo: isapprox
});
test('transactions can be queried by hasTags when tag starts with dollar', async () => {
await loadRules();
const account = await db.insertAccount({ name: 'bank' });
const payeeId = await db.insertPayee({ name: 'payee' });
await db.insertTransaction({
id: '1',
date: '2020-10-01',
account,
payee: payeeId,
notes: 'Follow up #$Bug_Test issue',
amount: 123,
});
await db.insertTransaction({
id: '2',
date: '2020-10-01',
account,
payee: payeeId,
notes: 'Follow up #Tag_1 issue',
amount: 123,
});
const transactions = await getMatchingTransactions([
{ field: 'notes', op: 'hasTags', value: '#$Bug_Test' },
]);
expect(transactions.map(t => t.id)).toEqual(['1']);
});
test('and sub expression builds $and condition', async () => {
const conds = [{ field: 'category', op: 'is', value: null }];
const { filters } = conditionsToAQL(conds);

View File

@@ -599,22 +599,26 @@ export function conditionsToAQL(
}
return { $or: values.map(v => apply(field, '$eq', v)) };
case 'hasTags':
case 'hasTags': {
const tagValues = [];
const seenTags = new Set();
for (const [_, tag] of value.matchAll(/(?<!#)(#[^#\s]+)/g)) {
if (!tagValues.find(t => t.tag === tag)) {
if (!seenTags.has(tag)) {
seenTags.add(tag);
tagValues.push(tag);
}
}
return {
$and: tagValues.map(v => {
const regex = new RegExp(
`(?<!#)${v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([\\s#]|$)`,
);
return apply(field, '$regexp', regex.source);
const escapedTag = v
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace(/\\\$/g, '[$]'); // Use '[$]' instead of '\$' so AQL string unescaping doesn't turn it into a bare '$' end-of-string anchor
const pattern = `(?<!#)${escapedTag}([\\s#]|$)`;
return apply(field, '$regexp', pattern);
}),
};
}
case 'notOneOf':
const notValues = value;

View File

@@ -0,0 +1,6 @@
---
category: Bugfixes
authors: [gust0717]
---
Fixes transaction query by tag when tag starts with $