support not in options for transaction type, transaction category and account filters

This commit is contained in:
MaysWind
2026-04-11 16:49:11 +08:00
parent a604737c7c
commit 448fc760c0
21 changed files with 123 additions and 33 deletions
+102 -33
View File
@@ -301,16 +301,16 @@ export class TransactionExplorerQuery {
switch (field) {
case TransactionExplorerConditionField.TransactionType:
condition = new TransactionExplorerTransactionTypeCondition([ TransactionType.Expense, TransactionType.Income, TransactionType.Transfer ]);
condition = new TransactionExplorerTransactionTypeCondition(TransactionExplorerConditionOperatorType.In, [ TransactionType.Expense, TransactionType.Income, TransactionType.Transfer ]);
break;
case TransactionExplorerConditionField.TransactionCategory:
condition = new TransactionExplorerTransactionCategoryCondition([]);
condition = new TransactionExplorerTransactionCategoryCondition(TransactionExplorerConditionOperatorType.In, []);
break;
case TransactionExplorerConditionField.SourceAccount:
condition = new TransactionExplorerSourceAccountCondition([]);
condition = new TransactionExplorerSourceAccountCondition(TransactionExplorerConditionOperatorType.In, []);
break;
case TransactionExplorerConditionField.DestinationAccount:
condition = new TransactionExplorerDestinationAccountCondition([]);
condition = new TransactionExplorerDestinationAccountCondition(TransactionExplorerConditionOperatorType.In, []);
break;
case TransactionExplorerConditionField.SourceAmount:
condition = new TransactionExplorerSourceAmountCondition(TransactionExplorerConditionOperatorType.Between, [0, 0]);
@@ -331,7 +331,7 @@ export class TransactionExplorerQuery {
condition = new TransactionExplorerDescriptionCondition(TransactionExplorerConditionOperatorType.Contains, '');
break;
default:
condition = new TransactionExplorerTransactionTypeCondition([ TransactionType.Expense, TransactionType.Income, TransactionType.Transfer ]);
condition = new TransactionExplorerTransactionTypeCondition(TransactionExplorerConditionOperatorType.In, [ TransactionType.Expense, TransactionType.Income, TransactionType.Transfer ]);
break;
}
@@ -737,23 +737,23 @@ export class TransactionExplorerConditionWithRelation {
switch (conditionField) {
case TransactionExplorerConditionField.TransactionType.value:
if (conditionOperator === TransactionExplorerConditionOperatorType.In && Array.isArray(conditionValue)) {
condition = new TransactionExplorerTransactionTypeCondition(conditionValue as number[]);
if (TransactionExplorerTransactionTypeCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
condition = new TransactionExplorerTransactionTypeCondition(conditionOperator as TransactionTypeConditionOperator, conditionValue as number[]);
}
break;
case TransactionExplorerConditionField.TransactionCategory.value:
if (conditionOperator === TransactionExplorerConditionOperatorType.In && Array.isArray(conditionValue)) {
condition = new TransactionExplorerTransactionCategoryCondition(conditionValue as string[]);
if (TransactionExplorerTransactionCategoryCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
condition = new TransactionExplorerTransactionCategoryCondition(conditionOperator as TransactionCategoryConditionOperator, conditionValue as string[]);
}
break;
case TransactionExplorerConditionField.SourceAccount.value:
if (conditionOperator === TransactionExplorerConditionOperatorType.In && Array.isArray(conditionValue)) {
condition = new TransactionExplorerSourceAccountCondition(conditionValue as string[]);
if (TransactionExplorerSourceAccountCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
condition = new TransactionExplorerSourceAccountCondition(conditionOperator as AccountConditionOperator, conditionValue as string[]);
}
break;
case TransactionExplorerConditionField.DestinationAccount.value:
if (conditionOperator === TransactionExplorerConditionOperatorType.In && Array.isArray(conditionValue)) {
condition = new TransactionExplorerDestinationAccountCondition(conditionValue as string[]);
if (TransactionExplorerDestinationAccountCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
condition = new TransactionExplorerDestinationAccountCondition(conditionOperator as AccountConditionOperator, conditionValue as string[]);
}
break;
case TransactionExplorerConditionField.SourceAmount.value:
@@ -831,15 +831,20 @@ export class TransactionExplorerUndefinedCondition implements TransactionExplore
}
}
type TransactionTypeConditionOperator = TransactionExplorerConditionOperatorType.In |
TransactionExplorerConditionOperatorType.NotIn;
export class TransactionExplorerTransactionTypeCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionType, number[]> {
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
[TransactionExplorerConditionOperatorType.In]: true
[TransactionExplorerConditionOperatorType.In]: true,
[TransactionExplorerConditionOperatorType.NotIn]: true
};
public readonly field = TransactionExplorerConditionFieldType.TransactionType;
public readonly operator: TransactionExplorerConditionOperatorType.In = TransactionExplorerConditionOperatorType.In;
public readonly operator: TransactionTypeConditionOperator = TransactionExplorerConditionOperatorType.In;
public value: number[];
constructor(value: number[]) {
constructor(operator: TransactionTypeConditionOperator, value: number[]) {
this.operator = operator;
this.value = value;
}
@@ -848,7 +853,13 @@ export class TransactionExplorerTransactionTypeCondition implements TransactionE
}
public match(transaction: TransactionInsightDataItem): boolean {
return this.value.includes(transaction.type);
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return this.value.includes(transaction.type);
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return !this.value.includes(transaction.type);
}
return false;
}
public toExpression(): string {
@@ -863,19 +874,31 @@ export class TransactionExplorerTransactionTypeCondition implements TransactionE
return type.toString();
}
}).join(', ');
return `type IN (${textualTypes})`;
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return `type IN (${textualTypes})`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return `type NOT IN (${textualTypes})`;
} else {
return '';
}
}
}
type TransactionCategoryConditionOperator = TransactionExplorerConditionOperatorType.In |
TransactionExplorerConditionOperatorType.NotIn;
export class TransactionExplorerTransactionCategoryCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionCategory, string[]> {
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
[TransactionExplorerConditionOperatorType.In]: true
[TransactionExplorerConditionOperatorType.In]: true,
[TransactionExplorerConditionOperatorType.NotIn]: true
};
public readonly field = TransactionExplorerConditionFieldType.TransactionCategory;
public readonly operator: TransactionExplorerConditionOperatorType.In = TransactionExplorerConditionOperatorType.In;
public readonly operator: TransactionCategoryConditionOperator = TransactionExplorerConditionOperatorType.In;
public value: string[];
constructor(value: string[]) {
constructor(operator: TransactionCategoryConditionOperator, value: string[]) {
this.operator = operator
this.value = value;
}
@@ -884,7 +907,13 @@ export class TransactionExplorerTransactionCategoryCondition implements Transact
}
public match(transaction: TransactionInsightDataItem): boolean {
return this.value.includes(transaction.primaryCategory?.id ?? '') || this.value.includes(transaction.secondaryCategory?.id ?? transaction.categoryId);
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return this.value.includes(transaction.primaryCategory?.id ?? '') || this.value.includes(transaction.secondaryCategory?.id ?? transaction.categoryId);
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return !this.value.includes(transaction.primaryCategory?.id ?? '') && !this.value.includes(transaction.secondaryCategory?.id ?? transaction.categoryId);
}
return false;
}
public toExpression(allCategoriesMap: Record<string, TransactionCategory>): string {
@@ -901,19 +930,31 @@ export class TransactionExplorerTransactionCategoryCondition implements Transact
return `'${id}'`;
}
}).filter(item => !!item).join(', ');
return `category IN (${textualCategories})`;
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return `category IN (${textualCategories})`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return `category NOT IN (${textualCategories})`;
} else {
return '';
}
}
}
type AccountConditionOperator = TransactionExplorerConditionOperatorType.In |
TransactionExplorerConditionOperatorType.NotIn;
export class TransactionExplorerSourceAccountCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.SourceAccount, string[]> {
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
[TransactionExplorerConditionOperatorType.In]: true
[TransactionExplorerConditionOperatorType.In]: true,
[TransactionExplorerConditionOperatorType.NotIn]: true
};
public readonly field = TransactionExplorerConditionFieldType.SourceAccount;
public readonly operator: TransactionExplorerConditionOperatorType.In = TransactionExplorerConditionOperatorType.In;
public readonly operator: AccountConditionOperator = TransactionExplorerConditionOperatorType.In;
public value: string[];
constructor(value: string[]) {
constructor(operator: AccountConditionOperator, value: string[]) {
this.operator = operator;
this.value = value;
}
@@ -922,7 +963,13 @@ export class TransactionExplorerSourceAccountCondition implements TransactionExp
}
public match(transaction: TransactionInsightDataItem): boolean {
return this.value.includes(transaction.sourceAccountId);
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return this.value.includes(transaction.sourceAccountId);
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return !this.value.includes(transaction.sourceAccountId);
}
return false;
}
public toExpression(allCategoriesMap: Record<string, TransactionCategory>, allAccountsMap: Record<string, Account>): string {
@@ -939,19 +986,28 @@ export class TransactionExplorerSourceAccountCondition implements TransactionExp
return `'${id}'`;
}
}).filter(item => !!item).join(', ');
return `source_account IN (${textualAccounts})`;
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return `source_account IN (${textualAccounts})`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return `source_account NOT IN (${textualAccounts})`;
} else {
return '';
}
}
}
export class TransactionExplorerDestinationAccountCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.DestinationAccount, string[]> {
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
[TransactionExplorerConditionOperatorType.In]: true
[TransactionExplorerConditionOperatorType.In]: true,
[TransactionExplorerConditionOperatorType.NotIn]: true
};
public readonly field = TransactionExplorerConditionFieldType.DestinationAccount;
public readonly operator: TransactionExplorerConditionOperatorType.In = TransactionExplorerConditionOperatorType.In;
public readonly operator: AccountConditionOperator = TransactionExplorerConditionOperatorType.In;
public value: string[];
constructor(value: string[]) {
constructor(operator: AccountConditionOperator, value: string[]) {
this.operator = operator;
this.value = value;
}
@@ -960,7 +1016,13 @@ export class TransactionExplorerDestinationAccountCondition implements Transacti
}
public match(transaction: TransactionInsightDataItem): boolean {
return this.value.includes(transaction.destinationAccountId);
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return this.value.includes(transaction.destinationAccountId);
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return !this.value.includes(transaction.destinationAccountId);
}
return false;
}
public toExpression(allCategoriesMap: Record<string, TransactionCategory>, allAccountsMap: Record<string, Account>): string {
@@ -977,7 +1039,14 @@ export class TransactionExplorerDestinationAccountCondition implements Transacti
return `'${id}'`;
}
}).filter(item => !!item).join(', ');
return `destination_account IN (${textualAccounts})`;
if (this.operator === TransactionExplorerConditionOperatorType.In) {
return `destination_account IN (${textualAccounts})`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
return `destination_account NOT IN (${textualAccounts})`;
} else {
return '';
}
}
}