|
14 | 14 | # KIND, either express or implied. See the License for the |
15 | 15 | # specific language governing permissions and limitations |
16 | 16 | # under the License. |
| 17 | +import re |
17 | 18 | from decimal import Decimal |
18 | 19 |
|
19 | 20 | from pyparsing import ( |
|
51 | 52 | NotIn, |
52 | 53 | NotNaN, |
53 | 54 | NotNull, |
54 | | - NotStartsWith, |
55 | 55 | Or, |
56 | 56 | Reference, |
57 | 57 | StartsWith, |
|
78 | 78 | identifier = Word(alphas, alphanums + "_$").set_results_name("identifier") |
79 | 79 | column = DelimitedList(identifier, delim=".", combine=False).set_results_name("column") |
80 | 80 |
|
| 81 | +like_regex = r'(?P<valid_wildcard>(?<!\\)%$)|(?P<invalid_wildcard>(?<!\\)%)' |
| 82 | + |
81 | 83 |
|
82 | 84 | @column.set_parse_action |
83 | 85 | def _(result: ParseResults) -> Reference: |
@@ -217,12 +219,25 @@ def _(result: ParseResults) -> BooleanExpression: |
217 | 219 |
|
218 | 220 | @starts_with.set_parse_action |
219 | 221 | def _(result: ParseResults) -> BooleanExpression: |
220 | | - return StartsWith(result.column, result.raw_quoted_string) |
| 222 | + return _evaluate_like_statement(result) |
221 | 223 |
|
222 | 224 |
|
223 | 225 | @not_starts_with.set_parse_action |
224 | 226 | def _(result: ParseResults) -> BooleanExpression: |
225 | | - return NotStartsWith(result.column, result.raw_quoted_string) |
| 227 | + return ~_evaluate_like_statement(result) |
| 228 | + |
| 229 | + |
| 230 | +def _evaluate_like_statement(result: ParseResults) -> BooleanExpression: |
| 231 | + literal_like: StringLiteral = result.raw_quoted_string |
| 232 | + |
| 233 | + match = re.search(like_regex, literal_like.value) |
| 234 | + |
| 235 | + if match and match.groupdict()['invalid_wildcard']: |
| 236 | + raise ValueError("LIKE expressions only supports wildcard, '%', at the end of a string") |
| 237 | + elif match and match.groupdict()['valid_wildcard']: |
| 238 | + return StartsWith(result.column, StringLiteral(literal_like.value[:-1].replace('\\%', '%'))) |
| 239 | + else: |
| 240 | + return EqualTo(result.column, StringLiteral(literal_like.value.replace('\\%', '%'))) |
226 | 241 |
|
227 | 242 |
|
228 | 243 | predicate = (comparison | in_check | null_check | nan_check | starts_check | boolean).set_results_name("predicate") |
|
0 commit comments