Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Add support for question mark (?) wildcards #25

Merged
merged 4 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ name:/foo/o

# search using wildcard
name:foo*bar
name:foo?bar

# boolean search
member:true
Expand Down Expand Up @@ -202,6 +203,12 @@ Search for `name` field values matching `f*o` wildcard pattern.
name:f*o
```

Search for `name` field values matching `f?o` wildcard pattern.

```rb
name:f?o
```

Search for phrase "foo bar" in the `name` field (case sensitive).

```rb
Expand Down Expand Up @@ -250,12 +257,24 @@ Search for any word that starts with "foo" in the `name` field.
name:foo*
```

Search for any word that starts with "foo" and ends with bar in the `name` field.
Search for any word that starts with "foo" and ends with "bar" in the `name` field.

```rb
name:foo*bar
```

Search for any word that starts with "foo" in the `name` field, followed by a single arbitrary character.

```rb
name:foo?
```

Search for any word that starts with "foo", followed by a single arbitrary character and immediately ends with "bar" in the `name` field.

```rb
name:foo?bar
```

### Boolean operators

Search for phrase "foo bar" in the `name` field AND the phrase "quick fox" in the `bio` field.
Expand Down
6 changes: 4 additions & 2 deletions src/convertWildcardToRegex.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const WILDCARD_RULE = /\*+/g;
const WILDCARD_RULE = /(\*+)|(\?)/g;

export const convertWildcardToRegex = (pattern: string): RegExp => {
return new RegExp(
pattern
.replace(WILDCARD_RULE, '(.+?)'),
.replace(WILDCARD_RULE, (_match, p1) => {
return p1 ? '(.+?)' : '(.)';
}),
);
};
4 changes: 2 additions & 2 deletions src/createStringTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export const createStringTest = (regexCache: RegExpCache, ast: LiqeQuery) => {

const value = String(expression.value);

if (value.includes('*') && expression.quoted === false) {
return createRegexTest(regexCache, String(convertWildcardToRegex(value)) + (expression.quoted ? 'u' : 'ui'));
if ((value.includes('*') || value.includes('?')) && expression.quoted === false) {
return createRegexTest(regexCache, String(convertWildcardToRegex(value)) + 'ui');
} else {
return createRegexTest(regexCache, '/(' + escapeRegexString(value) + ')/' + (expression.quoted ? 'u' : 'ui'));
}
Expand Down
2 changes: 1 addition & 1 deletion src/grammar.ne
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,4 @@ regex_flags ->
[gmiyusd]:+ {% d => d[0].join('') %}

unquoted_value ->
[a-zA-Z_*@#$] [a-zA-Z\.\-_*@#$]:* {% d => d[0] + d[1].join('') %}
[a-zA-Z_*?@#$] [a-zA-Z\.\-_*?@#$]:* {% d => d[0] + d[1].join('') %}
4 changes: 2 additions & 2 deletions src/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@ const grammar: Grammar = {
{"name": "regex_flags$ebnf$1", "symbols": ["regex_flags$ebnf$1", /[gmiyusd]/], "postprocess": (d) => d[0].concat([d[1]])},
{"name": "regex_flags", "symbols": ["regex_flags$ebnf$1"], "postprocess": d => d[0].join('')},
{"name": "unquoted_value$ebnf$1", "symbols": []},
{"name": "unquoted_value$ebnf$1", "symbols": ["unquoted_value$ebnf$1", /[a-zA-Z\.\-_*@#$]/], "postprocess": (d) => d[0].concat([d[1]])},
{"name": "unquoted_value", "symbols": [/[a-zA-Z_*@#$]/, "unquoted_value$ebnf$1"], "postprocess": d => d[0] + d[1].join('')}
{"name": "unquoted_value$ebnf$1", "symbols": ["unquoted_value$ebnf$1", /[a-zA-Z\.\-_*?@#$]/], "postprocess": (d) => d[0].concat([d[1]])},
{"name": "unquoted_value", "symbols": [/[a-zA-Z_*?@#$]/, "unquoted_value$ebnf$1"], "postprocess": d => d[0] + d[1].join('')}
],
ParserStart: "main",
};
Expand Down
12 changes: 10 additions & 2 deletions test/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
filter,
} from '../src/Liqe';

const randomInRange = (min, max) => {
const randomInRange = (min: number, max: number) => {
return Math.floor(
Math.random() * (Math.ceil(max) - Math.floor(min) + 1) + min,
);
Expand Down Expand Up @@ -71,14 +71,22 @@ void suite(
};
}),

add('filters list by the "name" field using wildcard check', () => {
add('filters list by the "name" field using star (*) wildcard check', () => {
const query = parse('name:Ga*');

return () => {
filter(query, persons);
};
}),

add('filters list by the "name" field using question mark (?) wildcard check', () => {
const query = parse('name:Gaju?');

return () => {
filter(query, persons);
};
}),

add('filters list by any field using loose inclusion check', () => {
const query = parse('Gajus');

Expand Down
4 changes: 4 additions & 0 deletions test/liqe/convertWildcardToRegex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ const testRule = test.macro((t, regex: RegExp) => {
});

test('*', testRule, /(.+?)/);
test('?', testRule, /(.)/);
test('foo*bar', testRule, /foo(.+?)bar/);
test('foo***bar', testRule, /foo(.+?)bar/);
test('foo*bar*', testRule, /foo(.+?)bar(.+?)/);
test('foo?bar', testRule, /foo(.)bar/);
test('foo???bar', testRule, /foo(.)(.)(.)bar/);
19 changes: 17 additions & 2 deletions test/liqe/highlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ test(
);

test(
'matches wildcard',
'matches star (*) wildcard',
testQuery,
'name:f*o',
{
Expand All @@ -118,7 +118,7 @@ test(
);

test(
'matches wildcard (lazy)',
'matches star (*) wildcard (lazy)',
testQuery,
'name:f*o',
{
Expand All @@ -132,6 +132,21 @@ test(
],
);

test(
'matches question mark (?) wildcard',
testQuery,
'name:f?o',
{
name: 'foo bar baz',
},
[
{
path: 'name',
query: /(foo)/,
},
],
);

test(
'matches regex',
testQuery,
Expand Down
Loading