Skip to content

Commit

Permalink
Merge pull request #100 from jaysalvat/master
Browse files Browse the repository at this point in the history
Make populate param multilevel
  • Loading branch information
loris authored Jul 28, 2019
2 parents a744807 + 5f28d3f commit 0297de5
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 18 deletions.
62 changes: 48 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,39 @@ const getProjection = projection => {
return fields;
};

const getPopulation = population =>
population.split(',').map(path => {
return { path };
const getPopulation = population => {
const cache = {};

function iterateLevels(levels, prevLevels = []) {
let populate;
let path;
const topLevel = levels.shift();
prevLevels.push(topLevel);

const cacheKey = prevLevels.join('.');
if (cache[cacheKey]) {
path = cache[cacheKey];
} else {
path = { path: topLevel };
}
cache[cacheKey] = path;

if (levels.length) {
populate = iterateLevels(levels, prevLevels);
if (populate) {
path.populate = populate;
}
}
return path;
}

const populations = population.split(',').map(path => {
return iterateLevels(path.split('.'));
});

return [...new Set(populations)]; // Deduplicate array
};

const getSort = sort => parseUnaries(sort);

const getSkip = skip => Number(skip);
Expand Down Expand Up @@ -213,24 +241,30 @@ const getFilter = (filter, params, options) => {
};

const mergeProjectionAndPopulation = result => {
if (result.projection && result.population) {
// Loop the population rows
result.population.forEach(row => {
const prefix = `${row.path}.`;
function iteratePopulation(population, prevPrefix = '') {
population.forEach(row => {
const prefix = `${prevPrefix}${row.path}.`;
Object.keys(result.projection).forEach(key => {
// If field start with the name of the path, we add it to the `select` property
if (key.startsWith(prefix)) {
const unprefixedKey = key.replace(prefix, '');
row.select = {
...row.select,
[unprefixedKey]: result.projection[key],
};
// Remove field with . from the projection
delete result.projection[key];
if (unprefixedKey.indexOf('.') === -1) {
row.select = {
...row.select,
[unprefixedKey]: result.projection[key],
};
delete result.projection[key];
}
}
});
if (row.populate) {
iteratePopulation([row.populate], prefix);
}
});
}

if (result.projection && result.population) {
iteratePopulation(result.population);
}
};

const operators = [
Expand Down
64 changes: 60 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,21 +349,77 @@ test('populate', t => {
t.deepEqual(res.population, [{ path: 'a' }, { path: 'b' }, { path: 'c' }]);
});

test('populate and projection', t => {
const res = aqp('populate=a,b,c&fields=j,k,l,a.x,a.y,a.z,b.x,b.y,foo.bar');
test('populate (nested)', t => {
const res = aqp('populate=a,b.b1,c.c1.c2');
t.truthy(res);
t.deepEqual(res.projection, { j: 1, k: 1, l: 1, 'foo.bar': 1 });
t.deepEqual(res.population, [
{
path: 'a',
select: { x: 1, y: 1, z: 1 },
},
{
path: 'b',
populate: {
path: 'b1',
},
},
{
path: 'c',
populate: {
path: 'c1',
populate: {
path: 'c2',
},
},
},
]);
});

test('populate (nested, no duplicated)', t => {
const res = aqp('populate=a,a.a1,a.a1.a2');
t.truthy(res);
t.deepEqual(res.population, [
{
path: 'a',
populate: {
path: 'a1',
populate: {
path: 'a2',
},
},
},
]);
});

test('populate (nested) and projection', t => {
const res = aqp(
'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'
);
t.truthy(res);
t.deepEqual(res.projection, { j: 1, k: 1, 'foo.bar': 1 });
t.deepEqual(res.population, [
{
path: 'a',
select: { x: 1 },
},
{
path: 'b',
select: { x: 1, y: 1 },
populate: {
path: 'b1',
select: { x: 1 },
},
},
{
path: 'c',
select: { x: 1 },
populate: {
path: 'c1',
select: { x: 1 },
populate: {
path: 'c2',
select: { x: 1, y: 1 },
},
},
},
]);
});
Expand Down

0 comments on commit 0297de5

Please sign in to comment.