mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support filtering transaction description using regular expressions in insights explorer
This commit is contained in:
@@ -93,6 +93,8 @@ export enum TransactionExplorerConditionOperatorType {
|
||||
NotStartsWith = 'notStartsWith',
|
||||
EndsWith = 'endsWith',
|
||||
NotEndsWith = 'notEndsWith',
|
||||
RegexMatch = 'regexMatch',
|
||||
NotRegexMatch = 'notRegexMatch',
|
||||
LatitudeBetween = 'latitudeBetween',
|
||||
LatitudeNotBetween = 'latitudeNotBetween',
|
||||
LongitudeBetween = 'longitudeBetween',
|
||||
@@ -123,6 +125,8 @@ export class TransactionExplorerConditionOperator implements NameValue {
|
||||
public static readonly NotStartsWith = new TransactionExplorerConditionOperator('Does not start with', TransactionExplorerConditionOperatorType.NotStartsWith);
|
||||
public static readonly EndsWith = new TransactionExplorerConditionOperator('Ends with', TransactionExplorerConditionOperatorType.EndsWith);
|
||||
public static readonly NotEndsWith = new TransactionExplorerConditionOperator('Does not end with', TransactionExplorerConditionOperatorType.NotEndsWith);
|
||||
public static readonly RegexMatch = new TransactionExplorerConditionOperator('Matches regex', TransactionExplorerConditionOperatorType.RegexMatch);
|
||||
public static readonly NotRegexMatch = new TransactionExplorerConditionOperator('Does not match regex', TransactionExplorerConditionOperatorType.NotRegexMatch);
|
||||
public static readonly LatitudeBetween = new TransactionExplorerConditionOperator('Latitude is between', TransactionExplorerConditionOperatorType.LatitudeBetween);
|
||||
public static readonly LatitudeNotBetween = new TransactionExplorerConditionOperator('Latitude is not between', TransactionExplorerConditionOperatorType.LatitudeNotBetween);
|
||||
public static readonly LongitudeBetween = new TransactionExplorerConditionOperator('Longitude is between', TransactionExplorerConditionOperatorType.LongitudeBetween);
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Beginnt nicht mit",
|
||||
"Ends with": "Endet mit",
|
||||
"Does not end with": "Endet nicht mit",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Breitengrad zwischen",
|
||||
"Latitude is not between": "Breitengrad nicht zwischen",
|
||||
"Longitude is between": "Längengrad zwischen",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "No empieza por",
|
||||
"Ends with": "Termina en",
|
||||
"Does not end with": "No termina en",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Não começa com",
|
||||
"Ends with": "Termina com",
|
||||
"Does not end with": "Não termina com",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude entre",
|
||||
"Latitude is not between": "Latitude não entre",
|
||||
"Longitude is between": "Longitude entre",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Не начинается с",
|
||||
"Ends with": "Заканчивается с",
|
||||
"Does not end with": "Не заканчивается с",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Se ne začne z",
|
||||
"Ends with": "Se konča z",
|
||||
"Does not end with": "Se ne konča z",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "தொடங்கவில்லை",
|
||||
"Ends with": "முடிகிறது",
|
||||
"Does not end with": "முடியவில்லை",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "Does not start with",
|
||||
"Ends with": "Ends with",
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "开头不是",
|
||||
"Ends with": "结尾是",
|
||||
"Does not end with": "结尾不是",
|
||||
"Matches regex": "正则匹配",
|
||||
"Does not match regex": "不匹配正则",
|
||||
"Latitude is between": "纬度介于",
|
||||
"Latitude is not between": "纬度不介于",
|
||||
"Longitude is between": "经度介于",
|
||||
|
||||
@@ -1571,6 +1571,8 @@
|
||||
"Does not start with": "開頭不是",
|
||||
"Ends with": "結尾是",
|
||||
"Does not end with": "結尾不是",
|
||||
"Matches regex": "正則匹配",
|
||||
"Does not match regex": "不匹配正則",
|
||||
"Latitude is between": "緯度介於",
|
||||
"Latitude is not between": "緯度不介於",
|
||||
"Longitude is between": "經度介於",
|
||||
|
||||
+45
-10
@@ -1499,7 +1499,9 @@ type DescriptionConditionOperator = TransactionExplorerConditionOperatorType.IsE
|
||||
TransactionExplorerConditionOperatorType.StartsWith |
|
||||
TransactionExplorerConditionOperatorType.NotStartsWith |
|
||||
TransactionExplorerConditionOperatorType.EndsWith |
|
||||
TransactionExplorerConditionOperatorType.NotEndsWith;
|
||||
TransactionExplorerConditionOperatorType.NotEndsWith |
|
||||
TransactionExplorerConditionOperatorType.RegexMatch |
|
||||
TransactionExplorerConditionOperatorType.NotRegexMatch;
|
||||
|
||||
export class TransactionExplorerDescriptionCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.Description, string> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
@@ -1512,8 +1514,13 @@ export class TransactionExplorerDescriptionCondition implements TransactionExplo
|
||||
[TransactionExplorerConditionOperatorType.StartsWith]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotStartsWith]: true,
|
||||
[TransactionExplorerConditionOperatorType.EndsWith]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotEndsWith]: true
|
||||
[TransactionExplorerConditionOperatorType.NotEndsWith]: true,
|
||||
[TransactionExplorerConditionOperatorType.RegexMatch]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotRegexMatch]: true
|
||||
};
|
||||
private static cachedRegex: RegExp | undefined = undefined;
|
||||
private static cachedRegexPattern: string | undefined = undefined;
|
||||
|
||||
public readonly field = TransactionExplorerConditionFieldType.Description;
|
||||
public readonly operator: DescriptionConditionOperator = TransactionExplorerConditionOperatorType.Contains;
|
||||
public value: string;
|
||||
@@ -1554,34 +1561,62 @@ export class TransactionExplorerDescriptionCondition implements TransactionExplo
|
||||
return description.endsWith(this.value);
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEndsWith) {
|
||||
return !description.endsWith(this.value);
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.RegexMatch) {
|
||||
return this.getCachedRegex()?.test(description) ?? false;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotRegexMatch) {
|
||||
return !(this.getCachedRegex()?.test(description) ?? false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
const escapedValue = this.value.replace(/'/g, "''");
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.IsEmpty) {
|
||||
return `description IS EMPTY`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.IsNotEmpty) {
|
||||
return `description IS NOT EMPTY`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.Equals) {
|
||||
return `description = '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description = '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEquals) {
|
||||
return `description <> '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description <> '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.Contains) {
|
||||
return `description CONTAINS '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description CONTAINS '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotContains) {
|
||||
return `description NOT CONTAINS '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description NOT CONTAINS '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.StartsWith) {
|
||||
return `description STARTS WITH '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description STARTS WITH '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotStartsWith) {
|
||||
return `description NOT STARTS WITH '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description NOT STARTS WITH '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.EndsWith) {
|
||||
return `description ENDS WITH '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description ENDS WITH '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEndsWith) {
|
||||
return `description NOT ENDS WITH '${this.value.replace(/'/g, "''")}'`;
|
||||
return `description NOT ENDS WITH '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.RegexMatch) {
|
||||
return `description REGEXP LIKE '${escapedValue}'`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotRegexMatch) {
|
||||
return `description NOT REGEXP LIKE '${escapedValue}'`;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private getCachedRegex(): RegExp | undefined {
|
||||
if (this.operator !== TransactionExplorerConditionOperatorType.RegexMatch && this.operator !== TransactionExplorerConditionOperatorType.NotRegexMatch) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (TransactionExplorerDescriptionCondition.cachedRegexPattern !== this.value) {
|
||||
try {
|
||||
TransactionExplorerDescriptionCondition.cachedRegex = new RegExp(this.value);
|
||||
TransactionExplorerDescriptionCondition.cachedRegexPattern = this.value;
|
||||
} catch {
|
||||
TransactionExplorerDescriptionCondition.cachedRegex = undefined;
|
||||
TransactionExplorerDescriptionCondition.cachedRegexPattern = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return TransactionExplorerDescriptionCondition.cachedRegex;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user