Skip to content

Commit dbbf677

Browse files
authored
Merge pull request #561 from psteinroe/fix/nested-arrays
fix(postgrest-core): handle nested arrays properly
2 parents 1d579f8 + 2cef149 commit dbbf677

File tree

3 files changed

+66
-23
lines changed

3 files changed

+66
-23
lines changed

.changeset/tiny-bottles-wave.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@supabase-cache-helpers/postgrest-core": patch
3+
---
4+
5+
fix: hasPath now handles nested arrays properly

packages/postgrest-core/src/postgrest-filter.ts

+23-23
Original file line numberDiff line numberDiff line change
@@ -112,33 +112,33 @@ export class PostgrestFilter<Result extends Record<string, unknown>> {
112112
return this._selectFn(obj);
113113
}
114114

115-
private hasPathRecursive(
116-
obj: unknown,
117-
basePath: string,
118-
objectPath?: string,
119-
): boolean {
120-
const v = get(obj, basePath);
115+
private hasPathRecursive(obj: unknown, path: string): boolean {
116+
// normalise json operators "->" and "->>" to "."
117+
const pathElements = path.replace(/->>|->/g, '.').split('.');
121118

122-
// Return early if we are not searching for a nested value and the path is valid
123-
if (!objectPath && typeof v !== 'undefined') return true;
119+
// we are at the deepest level
120+
if (pathElements.length === 1) {
121+
// obj is valid if v is null, because the foreign key relation can be null
122+
if (obj === null) return true;
124123

125-
// If we are looking for a nested value and we found an array, validate that all array elements have a value for the required path
126-
if (objectPath && Array.isArray(v)) {
127-
return v.every((i) => typeof get(i, objectPath) !== 'undefined');
124+
// else check if the path exists
125+
return typeof get(obj, pathElements[0]) !== 'undefined';
128126
}
129127

130-
const pathElements = basePath.replace(/->>|->/g, '.').split('.');
131-
const currentPathElement = pathElements.pop();
132-
133-
// Return if arrived at root level
134-
// obj is valid if v is null, because the foreign key relation can be null
135-
if (pathElements.length === 0) return v === null;
136-
// If there are levels to go up to, add current path element to object path and go up
137-
return this.hasPathRecursive(
138-
obj,
139-
pathElements.join('.'),
140-
[currentPathElement, objectPath].filter(Boolean).join('.'),
141-
);
128+
// go deeper
129+
const currentPathElement = pathElements.shift();
130+
const v = get(obj, currentPathElement!);
131+
132+
// undefined means the path does not exist
133+
if (typeof v === 'undefined') return false;
134+
135+
// if we have an array, check if all elements have the path
136+
if (Array.isArray(v)) {
137+
return v.every((i) => this.hasPathRecursive(i, pathElements.join('.')));
138+
}
139+
140+
// if we dont have an array, continue recursively
141+
return this.hasPathRecursive(v, pathElements.join('.'));
142142
}
143143

144144
private applyFilterFn(

packages/postgrest-core/tests/postgrest-filter.spec.ts

+38
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ const MOCK = {
1010
array: ['element-1', 'element-2'],
1111
empty_array: [],
1212
null_value: null,
13+
array_within_array: [
14+
{
15+
val: 'hello',
16+
inner_array: [
17+
{
18+
val: 'world',
19+
},
20+
],
21+
},
22+
],
1323
array_of_objects: [
1424
{ some: { value: 'value' } },
1525
{ some: { value: 'value' } },
@@ -535,6 +545,20 @@ describe('PostgrestFilter', () => {
535545
).toEqual(true);
536546
});
537547

548+
it('with simple array', () => {
549+
expect(
550+
new PostgrestFilter({
551+
filters: [],
552+
paths: [
553+
{
554+
path: 'array',
555+
declaration: 'array',
556+
},
557+
],
558+
}).hasPaths(MOCK),
559+
).toEqual(true);
560+
});
561+
538562
it('with valid array of objects', () => {
539563
expect(
540564
new PostgrestFilter({
@@ -562,6 +586,20 @@ describe('PostgrestFilter', () => {
562586
}).hasPaths(MOCK),
563587
).toEqual(false);
564588
});
589+
590+
it('with nested arrays', () => {
591+
expect(
592+
new PostgrestFilter({
593+
filters: [],
594+
paths: [
595+
{
596+
path: 'array_within_array.inner_array.val',
597+
declaration: 'array_within_array.inner_array.val',
598+
},
599+
],
600+
}).hasPaths(MOCK),
601+
).toEqual(true);
602+
});
565603
});
566604

567605
describe('.hasFiltersOnPaths', () => {

0 commit comments

Comments
 (0)