feat: escape special characters in filter values#147
Draft
Conversation
MoneyERP filter DSL uses #, |, ~ as structural operators (AND, OR,
operator delimiter). When field values contain these characters
(e.g. street address "CRA 80A # 17-85"), the filter string becomes
ambiguous and the server misparses it.
Add EscapeFilterValue() to FilterFor<T> that replaces operator
characters with configurable escape sequences. Currently uses
backslash escaping (\#, \|, \~) but this does NOT work with the
MoneyERP server - they appear to use a naive Split('#') approach
with no escape support. The escape rules are configurable via the
EscapeRules array for when/if a working scheme is found.
Also adds:
- Unit tests for all operator characters in filter values
- Integration test (MoneyErpCompanyFilterTests) that creates a
company with '#' in the street address and verifies the filter
round-trip, exposing the server-side parsing limitation.
URL encoding (%23, %7C) was also tested and does not work.
This is likely a MoneyERP server limitation requiring their fix.
Refactor MoneyErpCompanyFilterTests to extract shared logic into a parameterized helper. Add two new test methods covering tilde and pipe characters in company street address filter values, alongside the existing hash test.
ce6e085 to
8432131
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MoneyERP's filter DSL uses
#,|, and~as structural operators (AND, OR, and operator delimiter respectively). When a field value contains any of these characters — e.g. a Colombian street addressCRA 80A # 17-85— the filter string becomes ambiguous and the server misparses it.Real-world example (anonymized):
The
#inside the street address is indistinguishable from the AND operator, causing the server to parse 5 clauses instead of 4.What was tried
%23,%7C)%23as literal text\#,|,\~)Split('#')Conclusion: The MoneyERP server has no escape mechanism for operator characters in filter values. This is a server-side limitation that requires a fix from Solitea (MoneyERP vendor).
Changes
FilterFor.cs— Configurable value escaping infrastructureEscapeFilterValue()method that scans values for operator characters and replaces them using configurableEscapeRules(char Character, string Replacement)tuples — easy to swap the escaping scheme when a working one is foundGetFilterClausenow callsEscapeFilterValuebefore interpolating the valueFilterForTests.ValueContainingOperatorCharacters.cs— Unit testsAndWithValueContainingHashIsEscaped— Full reproduction of the real failing request (anonymized 8-clause AND filter with#in street address)EqualWithValueContainingHash/Tilde/Pipe/Backslash— Isolated tests per operator characterEqualWithValueContainingMultipleSpecialCharacters— All operators in one valueEqualWithValueWithoutSpecialCharactersIsUnchanged— Fast path verificationEscapeFilterValue*— Direct unit tests of the escape methodMoneyErpCompanyFilterTests.cs— Integration test#in the street address via GraphQL mutation#value#returns nothing but filter-without-#finds the company →Assert.Failproving the escaping bugExplicit = true(requiresMONEYERP_CLIENT_ID,MONEYERP_CLIENT_SECRET,MONEYERP_ENDPOINTenv vars)Status
EscapeRulesarray and the test assertions.References