diff --git a/src/core/explorer.ts b/src/core/explorer.ts index a3ff1211..6519e10a 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -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); diff --git a/src/locales/de.json b/src/locales/de.json index a6a4e851..4634e3a7 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -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", diff --git a/src/locales/en.json b/src/locales/en.json index 36c94eff..f14321f0 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -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", diff --git a/src/locales/es.json b/src/locales/es.json index 4ff3c2e4..deb3f5cb 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -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", diff --git a/src/locales/fr.json b/src/locales/fr.json index e63b86fd..f6ff450a 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -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", diff --git a/src/locales/it.json b/src/locales/it.json index d9cf41fc..408da31e 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -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", diff --git a/src/locales/ja.json b/src/locales/ja.json index 469cfc99..d43c98d9 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -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", diff --git a/src/locales/kn.json b/src/locales/kn.json index 5159dc2c..64df56e6 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -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", diff --git a/src/locales/ko.json b/src/locales/ko.json index f6802ebe..686ef21d 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -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", diff --git a/src/locales/nl.json b/src/locales/nl.json index 1284ed55..f55dad3d 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -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", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 4190accc..9ff8856b 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -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", diff --git a/src/locales/ru.json b/src/locales/ru.json index dc8a3d41..72477a04 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -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", diff --git a/src/locales/sl.json b/src/locales/sl.json index c9342152..b922ac47 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -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", diff --git a/src/locales/ta.json b/src/locales/ta.json index d66d3272..1755ed55 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -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", diff --git a/src/locales/th.json b/src/locales/th.json index b7b68505..dc8cdf6d 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -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", diff --git a/src/locales/tr.json b/src/locales/tr.json index 21c14597..e648ac59 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -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", diff --git a/src/locales/uk.json b/src/locales/uk.json index fb205901..4da1933f 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -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", diff --git a/src/locales/vi.json b/src/locales/vi.json index 8c2d651a..02d62201 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -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", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 5fc149e3..a03d1917 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -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": "经度介于", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index c4461999..a3349a8c 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -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": "經度介於", diff --git a/src/models/explorer.ts b/src/models/explorer.ts index af2a867d..1317a1fa 100644 --- a/src/models/explorer.ts +++ b/src/models/explorer.ts @@ -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 { public static readonly supportedOperators: PartialRecord = { @@ -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; + } }