Skip to content

Commit 6df517f

Browse files
committed
Make populate params multilevel
1 parent a744807 commit 6df517f

File tree

2 files changed

+128
-18
lines changed

2 files changed

+128
-18
lines changed

src/index.js

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,39 @@ const getProjection = projection => {
146146
return fields;
147147
};
148148

149-
const getPopulation = population =>
150-
population.split(',').map(path => {
151-
return { path };
149+
const getPopulation = population => {
150+
const cache = {};
151+
152+
function iterateLevels(levels, prevLevels = []) {
153+
let populate;
154+
let path;
155+
const topLevel = levels.shift();
156+
prevLevels.push(topLevel);
157+
158+
const cacheKey = prevLevels.join('.');
159+
if (cache[cacheKey]) {
160+
path = cache[cacheKey];
161+
} else {
162+
path = { path: topLevel };
163+
}
164+
cache[cacheKey] = path;
165+
166+
if (levels.length) {
167+
populate = iterateLevels(levels, prevLevels);
168+
if (populate) {
169+
path.populate = populate;
170+
}
171+
}
172+
return path;
173+
}
174+
175+
const populations = population.split(',').map(path => {
176+
return iterateLevels(path.split('.'));
152177
});
153178

179+
return [...new Set(populations)]; // Deduplicate array
180+
};
181+
154182
const getSort = sort => parseUnaries(sort);
155183

156184
const getSkip = skip => Number(skip);
@@ -213,24 +241,30 @@ const getFilter = (filter, params, options) => {
213241
};
214242

215243
const mergeProjectionAndPopulation = result => {
216-
if (result.projection && result.population) {
217-
// Loop the population rows
218-
result.population.forEach(row => {
219-
const prefix = `${row.path}.`;
244+
function iteratePopulation(population, prevPrefix = '') {
245+
population.forEach(row => {
246+
const prefix = `${prevPrefix}${row.path}.`;
220247
Object.keys(result.projection).forEach(key => {
221-
// If field start with the name of the path, we add it to the `select` property
222248
if (key.startsWith(prefix)) {
223249
const unprefixedKey = key.replace(prefix, '');
224-
row.select = {
225-
...row.select,
226-
[unprefixedKey]: result.projection[key],
227-
};
228-
// Remove field with . from the projection
229-
delete result.projection[key];
250+
if (unprefixedKey.indexOf('.') === -1) {
251+
row.select = {
252+
...row.select,
253+
[unprefixedKey]: result.projection[key],
254+
};
255+
delete result.projection[key];
256+
}
230257
}
231258
});
259+
if (row.populate) {
260+
iteratePopulation([row.populate], prefix);
261+
}
232262
});
233263
}
264+
265+
if (result.projection && result.population) {
266+
iteratePopulation(result.population);
267+
}
234268
};
235269

236270
const operators = [

test/index.js

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,21 +349,97 @@ test('populate', t => {
349349
t.deepEqual(res.population, [{ path: 'a' }, { path: 'b' }, { path: 'c' }]);
350350
});
351351

352-
test('populate and projection', t => {
353-
const res = aqp('populate=a,b,c&fields=j,k,l,a.x,a.y,a.z,b.x,b.y,foo.bar');
352+
// test('populate and projection', t => {
353+
// const res = aqp('populate=a,b,c&fields=j,k,l,a.x,a.y,a.z,b.x,b.y,foo.bar');
354+
// t.truthy(res);
355+
// t.deepEqual(res.projection, { j: 1, k: 1, l: 1, 'foo.bar': 1 });
356+
// t.deepEqual(res.population, [
357+
// {
358+
// path: 'a',
359+
// select: { x: 1, y: 1, z: 1 },
360+
// },
361+
// {
362+
// path: 'b',
363+
// select: { x: 1, y: 1 },
364+
// },
365+
// {
366+
// path: 'c',
367+
// },
368+
// ]);
369+
// });
370+
371+
test('populate (nested)', t => {
372+
const res = aqp('populate=a,b.b1,c.c1.c2');
354373
t.truthy(res);
355-
t.deepEqual(res.projection, { j: 1, k: 1, l: 1, 'foo.bar': 1 });
356374
t.deepEqual(res.population, [
357375
{
358376
path: 'a',
359-
select: { x: 1, y: 1, z: 1 },
377+
},
378+
{
379+
path: 'b',
380+
populate: {
381+
path: 'b1',
382+
},
383+
},
384+
{
385+
path: 'c',
386+
populate: {
387+
path: 'c1',
388+
populate: {
389+
path: 'c2',
390+
},
391+
},
392+
},
393+
]);
394+
});
395+
396+
test('populate (nested, no duplicated)', t => {
397+
const res = aqp('populate=a,a.a1,a.a1.a2');
398+
t.truthy(res);
399+
console.log(res.population);
400+
t.deepEqual(res.population, [
401+
{
402+
path: 'a',
403+
populate: {
404+
path: 'a1',
405+
populate: {
406+
path: 'a2',
407+
},
408+
},
409+
},
410+
]);
411+
});
412+
413+
test('populate (nested) and projection', t => {
414+
const res = aqp(
415+
'populate=a,b.b1,c.c1.c2&fields=j,k,foo.bar,a.x,b.x,b.y,b.b1.x,c.x,c.c1.x,c.c1.c2.x,c.c1.c2.y'
416+
);
417+
t.truthy(res);
418+
t.deepEqual(res.projection, { j: 1, k: 1, 'foo.bar': 1 });
419+
t.deepEqual(res.population, [
420+
{
421+
path: 'a',
422+
select: { x: 1 },
360423
},
361424
{
362425
path: 'b',
363426
select: { x: 1, y: 1 },
427+
populate: {
428+
path: 'b1',
429+
select: { x: 1 },
430+
},
364431
},
365432
{
366433
path: 'c',
434+
select: { x: 1 },
435+
populate: {
436+
path: 'c1',
437+
select: { x: 1 },
438+
populate: {
439+
path: 'c2',
440+
select: { x: 1, y: 1 },
441+
},
442+
},
367443
},
368444
]);
369445
});

0 commit comments

Comments
 (0)