Skip to content

Commit 4d4535d

Browse files
authored
Merge pull request #50 from oxdev03/feat/allow-to-filter-array-values
Add filtering for array fields and enhance iterate function
2 parents 5436533 + cb7e972 commit 4d4535d

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ sentence:word
234234
# Search for 'word' in the object properties starting with 's' and any nested property, e.g., [{s: {a: 'word'}}]
235235
s*:word
236236

237+
# Search for 'word' in array e.g. [{ s: ['word','number'] }]
238+
s:word
239+
237240
# Search for 'word' in the object by nested key 's.a'
238241
s.a:word
239242

src/tests/filter/filter.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,64 @@ describe(`filter`, () => {
122122
expect(result).toEqual(data.filter((d) => d._id == 13));
123123
});
124124
});
125+
126+
describe('filter array fields', () => {
127+
const data = [
128+
{ id: 1, tags: ['javascript', 'typescript'] },
129+
{ id: 2, tags: ['python', 'typescript'] },
130+
{ id: 3, tags: ['java'] },
131+
{ id: 4, tags: [] },
132+
{ id: 5 },
133+
];
134+
135+
it('should filter by array value', () => {
136+
const result = filter(new QueryParser('tags:typescript'), data);
137+
expect(result).toEqual([
138+
{ id: 1, tags: ['javascript', 'typescript'] },
139+
{ id: 2, tags: ['python', 'typescript'] },
140+
]);
141+
});
142+
143+
it('should handle nested array fields', () => {
144+
const nestedData = [
145+
{
146+
id: 1,
147+
nested: {
148+
tags: ['javascript', 'typescript'],
149+
},
150+
},
151+
{
152+
id: 2,
153+
nested: {
154+
tags: ['python'],
155+
},
156+
},
157+
{
158+
id: 3,
159+
nested: {
160+
other: ['something'],
161+
},
162+
},
163+
];
164+
165+
const queries = [
166+
'nested.tags:typescript', // explicit field path
167+
'*.tags:typescript', // wildcard prefix
168+
'nested.tags*:typescript', // wildcard suffix
169+
'*.tags*:typescript', // wildcard on both sides
170+
];
171+
172+
for (const query of queries) {
173+
const result = filter(new QueryParser(query), nestedData);
174+
expect(result).toEqual([
175+
{
176+
id: 1,
177+
nested: {
178+
tags: ['javascript', 'typescript'],
179+
},
180+
},
181+
]);
182+
}
183+
});
184+
});
125185
});

src/tests/utils/iterate.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,25 @@ describe('iterate', () => {
372372
`);
373373
});
374374

375+
it('should handle object with plain array', () => {
376+
const someObj = {
377+
tags: ['tagA', 'tagB'],
378+
};
379+
const result = [...iterate(someObj, 'tags')];
380+
expect(result).toMatchInlineSnapshot(`
381+
[
382+
[
383+
"tags.0",
384+
"tagA",
385+
],
386+
[
387+
"tags.1",
388+
"tagB",
389+
],
390+
]
391+
`);
392+
});
393+
375394
describe('iterate private fields feature', () => {
376395
const objWithPrivateFields = {
377396
private: {

src/utils/iterate.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ export default function* iterate(
4141

4242
// Check if the object is iterable and not in the NOT_ITERABLE list
4343
if (typeof obj === 'object' && obj !== null && !NOT_ITERABLE.some((cls) => obj instanceof cls)) {
44+
// Handle plain arrays directly if we're at the target field and not using a wildcard
45+
if (Array.isArray(obj) && currentPath.length === splittedFields.length && !isTrailingWildcard && field) {
46+
for (const [i, element] of obj.entries()) {
47+
yield [[...currentPath, i].join('.'), element];
48+
}
49+
return;
50+
}
51+
4452
// Check if the object is an array with elements having the current field as a key
4553
const arrayWithInnerKey = Array.isArray(obj) && obj.some((o) => objectHasField(o, currentField, checkPrivate));
4654
const objWithCurrentField = objectHasField(obj, currentField, checkPrivate);

0 commit comments

Comments
 (0)