Skip to content

Commit

Permalink
Merge a33e81a into a1e9e72
Browse files Browse the repository at this point in the history
  • Loading branch information
sshah-asymmetrik committed Apr 16, 2019
2 parents a1e9e72 + a33e81a commit b40fb22
Show file tree
Hide file tree
Showing 6 changed files with 620 additions and 164 deletions.
68 changes: 43 additions & 25 deletions packages/fhir-qb-mongo/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
let supportedSearchTransformations = {
_count: function(value) {
return { $limit: value };
},
};

/**
* Takes in a list of queries and wraps them in an $and block
*/
Expand Down Expand Up @@ -113,47 +119,58 @@ let buildEndsWithQuery = function({ field, value, caseSensitive = false }) {
*
* Returns a mongo aggregate query.
*/
let assembleSearchQuery = function({ joinsToPerform, matchesToPerform }) {
let assembleSearchQuery = function({
joinsToPerform,
matchesToPerform,
searchResultTransformations,
}) {
let aggregatePipeline = [];
if (joinsToPerform.length === 0 && matchesToPerform.length === 0) {
return aggregatePipeline;
}
let toSuppress = {};

// Construct the necessary joins and add them to the aggregate pipeline. Also follow each $lookup with an $unwind
// for ease of use.
for (let join of joinsToPerform) {
let { from, localKey, foreignKey } = join;
aggregatePipeline.push({
$lookup: {
from: from,
localField: localKey,
foreignField: foreignKey,
as: from,
},
});
aggregatePipeline.push({ $unwind: `$${from}` });
toSuppress[from] = 0;
if (joinsToPerform.length > 0) {
for (let join of joinsToPerform) {
let { from, localKey, foreignKey } = join;
aggregatePipeline.push({
$lookup: {
from: from,
localField: localKey,
foreignField: foreignKey,
as: from,
},
});
aggregatePipeline.push({ $unwind: `$${from}` });
toSuppress[from] = 0;
}
}

// Construct the necessary queries for each match and add them the pipeline.
let listOfOrs = [];
for (let match of matchesToPerform) {
if (match.length === 0) {
match.push({});
if (matchesToPerform.length > 0) {
let listOfOrs = [];
for (let match of matchesToPerform) {
if (match.length === 0) {
match.push({});
}
listOfOrs.push(buildOrQuery({ queries: match }));
}
listOfOrs.push(buildOrQuery({ queries: match }));
aggregatePipeline.push({ $match: buildAndQuery({ queries: listOfOrs }) });
}
if (listOfOrs.length === 0) {
listOfOrs.push({});
}
aggregatePipeline.push({ $match: buildAndQuery({ queries: listOfOrs }) });

// Suppress the tables that were joined from being displayed in the returned query. TODO might not want to do this.
if (Object.keys(toSuppress).length > 0) {
aggregatePipeline.push({ $project: toSuppress });
}

// TODO - WORK IN PROGRESS - handling search result transformations
// Handle search result parameters
Object.keys(searchResultTransformations).forEach(transformation => {
aggregatePipeline.push(
supportedSearchTransformations[transformation](
searchResultTransformations[transformation],
),
);
});
return aggregatePipeline;
};

Expand All @@ -168,4 +185,5 @@ module.exports = {
buildOrQuery,
buildInRangeQuery,
buildStartsWithQuery,
supportedSearchTransformations,
};
59 changes: 58 additions & 1 deletion packages/fhir-qb-mongo/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,46 @@ describe('Mongo Query Builder Tests', () => {
expect(observedResult).toEqual(expectedResult);
});
});
describe('buildExistsQuery Tests', () => {
test('Should return a range query', () => {
const expectedResult = { foo: { $exists: true } };
let observedResult = mongoQB.buildExistsQuery({
field: 'foo',
exists: true,
});
expect(observedResult).toEqual(expectedResult);
});
});
describe('buildInRangeQuery Tests', () => {
test('Should return a range query', () => {
const expectedResult = { foo: { $gte: 1, $lte: 10 } };
let observedResult = mongoQB.buildInRangeQuery({
field: 'foo',
lowerBound: 1,
upperBound: 10,
});
expect(observedResult).toEqual(expectedResult);
});
test('Should return an exclusive range query if given an invert flag', () => {
const expectedResult = {
$or: [{ foo: { $lt: 1 } }, { foo: { $gt: 10 } }],
};
let observedResult = mongoQB.buildInRangeQuery({
field: 'foo',
lowerBound: 1,
upperBound: 10,
invert: true,
});
expect(observedResult).toEqual(expectedResult);
});
});
describe('assembleSearchQuery Tests', () => {
test('Should return empty pipeline if no matches or joins to perform', () => {
const expectedResult = [];
let observedResult = mongoQB.assembleSearchQuery({
joinsToPerform: [],
matchesToPerform: [],
searchResultTransformations: {},
});
expect(observedResult).toEqual(expectedResult);
});
Expand All @@ -179,12 +213,12 @@ describe('Mongo Query Builder Tests', () => {
},
},
{ $unwind: '$foo' },
{ $match: { $and: [{}] } },
{ $project: { foo: 0 } },
];
let observedResult = mongoQB.assembleSearchQuery({
joinsToPerform: [{ from: 'foo', localKey: 'bar', foreignKey: 'baz' }],
matchesToPerform: [],
searchResultTransformations: {},
});
expect(observedResult).toEqual(expectedResult);
});
Expand All @@ -193,6 +227,29 @@ describe('Mongo Query Builder Tests', () => {
let observedResult = mongoQB.assembleSearchQuery({
joinsToPerform: [],
matchesToPerform: [[]],
searchResultTransformations: {},
});
expect(observedResult).toEqual(expectedResult);
});
test('Should handle matches appropriately', () => {
const expectedResult = [
{ $match: { $and: [{ $or: [{ foo: { $gte: 1, $lte: 10 } }] }] } },
];
let observedResult = mongoQB.assembleSearchQuery({
joinsToPerform: [],
matchesToPerform: [[{ foo: { $gte: 1, $lte: 10 } }]],
searchResultTransformations: {},
});
expect(observedResult).toEqual(expectedResult);
});
});
describe('Search Result Transformation Tests', () => {
test('Should add $limit to the end of the pipeline when given _count parameter', () => {
const expectedResult = [{ $limit: 3 }];
let observedResult = mongoQB.assembleSearchQuery({
joinsToPerform: [],
matchesToPerform: [],
searchResultTransformations: { _count: 3 },
});
expect(observedResult).toEqual(expectedResult);
});
Expand Down
Loading

0 comments on commit b40fb22

Please sign in to comment.