Skip to content

Commit

Permalink
Merge pull request #81 from marmelab/smarter-q
Browse files Browse the repository at this point in the history
Fix q filter fails to search multiple words
  • Loading branch information
djhi authored Jul 23, 2024
2 parents d8bee97 + c9cf359 commit 394cf1b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
23 changes: 19 additions & 4 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ import {
ShowGuesser,
required,
AutocompleteInput,
ReferenceInput,
SimpleForm,
TextInput,
Datagrid,
List,
TextField,
SearchInput,
} from 'react-admin';
import authProvider from './authProvider';
import { QueryClient } from 'react-query';

const queryClient = new QueryClient({
Expand All @@ -36,7 +44,7 @@ export const App = ({ dataProvider }: { dataProvider: DataProvider }) => {
/>
<Resource
name="authors"
list={ListGuesser}
list={AuthorList}
edit={EditGuesser}
show={ShowGuesser}
recordRepresentation={(record) =>
Expand All @@ -47,11 +55,18 @@ export const App = ({ dataProvider }: { dataProvider: DataProvider }) => {
);
};

import { ReferenceInput, SimpleForm, TextInput } from 'react-admin';
import authProvider from './authProvider';
const AuthorList = () => (
<List filters={[<SearchInput source="q" alwaysOn key="q" />]}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="first_name" />
<TextField source="last_name" />
</Datagrid>
</List>
);

// The default value for the title field should cause a server validation error as it's not unique
export const BookCreate = () => (
const BookCreate = () => (
<Create>
<SimpleForm>
<ReferenceInput source="author_id" reference="authors">
Expand Down
8 changes: 8 additions & 0 deletions src/Collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,14 @@ describe('Collection', () => {
{ id: 2, a: 'foo', b: 'bar' },
{ id: 3, a: { b: 'bar' } },
]);
expect(
collection.getAll({ filter: { q: 'hello bar' } }),
).toEqual([
{ id: 0, a: 'Hello', b: 'world' },
{ id: 1, a: 'helloworld', b: 'bunny' },
{ id: 2, a: 'foo', b: 'bar' },
{ id: 3, a: { b: 'bar' } },
]);
});

it('should filter by range using _gte, _gt, _lte, and _lt', () => {
Expand Down
21 changes: 20 additions & 1 deletion src/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ function filterItems<T extends CollectionItem = CollectionItem>(
// turn filter properties to functions
const filterFunctions = Object.keys(filter).map((key) => {
if (key === 'q' && typeof filter.q === 'string') {
const regex = new RegExp(filter.q, 'i');
const regex = buildRegexSearch(filter.q);

const filterWithQuery = <
T2 extends CollectionItem = CollectionItem,
Expand Down Expand Up @@ -556,3 +556,22 @@ function rangeItems<T extends CollectionItem = CollectionItem>(
}
throw new Error('Unsupported range type');
}

function buildRegexSearch(input: string) {
// Trim the input to remove leading and trailing whitespace
const trimmedInput = input.trim();

// Escape special characters in the input to prevent regex injection
const escapedInput = trimmedInput.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

// Split the input into words
const words = escapedInput.split(' ');

// Create a regex pattern to match any of the words
const pattern = words.map((word) => `(${word})`).join('|');

// Create a new RegExp object with the pattern, case insensitive
const regex = new RegExp(pattern, 'i');

return regex;
}

0 comments on commit 394cf1b

Please sign in to comment.