Skip to content

Commit

Permalink
Package/fhir qb (#12)
Browse files Browse the repository at this point in the history
* feat: add fhir-qb and fhir-qb-mongo

* feat: update fhir-sanitize-params and phx-tools tests

* chore: cleaning out old info from readmes

* Removed lockfiles for repos not updated

* Added lockfiles for new packages

* feat: added lockfiles for each package

* Publish

 - @asymmetrik/fhir-gql-schema-utils@1.1.0
 - @asymmetrik/fhir-qb-mongo@0.10.0
 - @asymmetrik/fhir-qb@0.10.0
 - @asymmetrik/fhir-sanitize-param@1.1.0
 - @asymmetrik/sof-graphql-invariant@1.1.0
 - @asymmetrik/sof-strategy@1.1.0

* fix: add fhir-qb-mongo and fhir-sanitize-param as dependencies
  • Loading branch information
sshah-asymmetrik authored and Robert-W committed Mar 22, 2019
1 parent 17b31ef commit f5a52c7
Show file tree
Hide file tree
Showing 28 changed files with 15,471 additions and 1,177 deletions.
12 changes: 12 additions & 0 deletions packages/fhir-gql-schema-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [1.1.0](https://github.com/Asymmetrik/phx-tools/compare/@asymmetrik/fhir-gql-schema-utils@1.0.2...@asymmetrik/fhir-gql-schema-utils@1.1.0) (2019-03-20)


### Features

* add fhir-qb and fhir-qb-mongo ([fefce17](https://github.com/Asymmetrik/phx-tools/commit/fefce17))
* added lockfiles for each package ([f8d9a31](https://github.com/Asymmetrik/phx-tools/commit/f8d9a31))





## [1.0.2](https://github.com/Asymmetrik/phx-tools/compare/@asymmetrik/fhir-gql-schema-utils@1.0.1...@asymmetrik/fhir-gql-schema-utils@1.0.2) (2019-02-13)


Expand Down
2 changes: 1 addition & 1 deletion packages/fhir-gql-schema-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@asymmetrik/fhir-gql-schema-utils",
"version": "1.0.2",
"version": "1.1.0",
"description": "Suite of FHIR related utilities for GraphQL schemas.",
"main": "index.js",
"homepage": "https://github.com/Asymmetrik/phx-tools",
Expand Down
15 changes: 15 additions & 0 deletions packages/fhir-gql-schema-utils/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


graphql@^14.0.2:
version "14.1.1"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.1.1.tgz#d5d77df4b19ef41538d7215d1e7a28834619fac0"
integrity sha512-C5zDzLqvfPAgTtP8AUPIt9keDabrdRAqSWjj2OPRKrKxI9Fb65I36s1uCs1UUBFnSWTdO7hyHi7z1ZbwKMKF6Q==
dependencies:
iterall "^1.2.2"

iterall@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
12 changes: 12 additions & 0 deletions packages/fhir-qb-mongo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 0.10.0 (2019-03-20)


### Features

* add fhir-qb and fhir-qb-mongo ([fefce17](https://github.com/Asymmetrik/phx-tools/commit/fefce17))
* update fhir-sanitize-params and phx-tools tests ([3466c1b](https://github.com/Asymmetrik/phx-tools/commit/3466c1b))
24 changes: 24 additions & 0 deletions packages/fhir-qb-mongo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# FHIR-Query-Builder-Mongo
> Utility for building Mongo DB queries based on incoming requests.
## Install
```shell
yarn add @asymmetrik/fhir-qb-mongo
```

## Usage
This module is meant to be imported and used by the fhir-qb. Included are implementations of the following methods:
```
assembleSearchQuery,
buildAndQuery,
buildComparatorQuery,
buildContainsQuery,
buildEndsWithQuery,
buildEqualToQuery,
buildExistsQuery,
buildOrQuery,
buildInRangeQuery,
buildStartsWithQuery,
```
These are used by the fhir-qb to build a query that will work in the mongo
aggregation pipeline.
171 changes: 171 additions & 0 deletions packages/fhir-qb-mongo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* Takes in a list of queries and wraps them in an $and block
*/
let buildAndQuery = function({ queries }) {
return { $and: queries };
};

/**
* Takes in a list of queries and wraps them in an $or block
*/
let buildOrQuery = function({ queries, invert }) {
return { [invert ? '$nor' : '$or']: queries };
};

/**
* Builds query to get records where the value of the field equal to the value.
* Setting invert to true will get records that are NOT equal instead.
*/
let buildEqualToQuery = function({ field, value, invert = false }) {
return { [field]: invert ? { $ne: value } : value };
};

/**
* Builds query to get records where the value of the field is [<,<=,>,>=,!=] to the value.
*/
let buildComparatorQuery = function({ field, value, comparator }) {
const mongoComparators = {
gt: '$gt',
ge: '$gte',
lt: '$lt',
le: '$lte',
ne: '$ne',
sa: '$gt',
eb: '$lt',
};
return { [field]: { [mongoComparators[comparator]]: value } };
};

/**
* Builds query to get records where the value of the field is in the specified range
* Setting invert to true will get records that are NOT in the specified range.
*/
let buildInRangeQuery = function({
field,
lowerBound,
upperBound,
invert = false,
}) {
if (invert) {
return buildOrQuery({
queries: [
buildComparatorQuery({ field, value: lowerBound, comparator: 'lt' }),
buildComparatorQuery({ field, value: upperBound, comparator: 'gt' }),
],
});
}
return { [field]: { $gte: lowerBound, $lte: upperBound } };
};

/**
* Builds query to retrieve records where the field exists (or not).
*/
let buildExistsQuery = function({ field, exists }) {
return { [field]: { $exists: exists } };
};

/**
* Builds a query to get records where the value of the field key matches the given pattern and options.
*/
let buildRegexQuery = function({ field, pattern, options }) {
return { [field]: { $regex: pattern, $options: options } };
};

/**
* Builds query to get records where the value of the field contains the value.
* Setting caseSensitive to true will cause the regex to be case insensitive
*/
let buildContainsQuery = function({ field, value, caseSensitive = false }) {
return buildRegexQuery({
field,
pattern: value,
options: caseSensitive ? '' : 'i',
});
};

/**
* Builds query to get records where the value of the field starts with the value.
* Setting caseSensitive to true will cause the regex to be case insensitive
*/
let buildStartsWithQuery = function({ field, value, caseSensitive = false }) {
return buildRegexQuery({
field,
pattern: `^${value}`,
options: caseSensitive ? '' : 'i',
});
};

/**
* Builds query to get records where the value of the field ends with the value.
* Setting caseSensitive to true will cause the regex to be case insensitive
*/
let buildEndsWithQuery = function({ field, value, caseSensitive = false }) {
return buildRegexQuery({
field,
pattern: `${value}$`,
options: caseSensitive ? '' : 'i',
});
};

/**
* Takes in 2 lists, joinsToPerform and matchesToPerform. Constructs a mongo aggregation query that first performs
* any necessary joins as dictated by joinsToPerform, and then filters the results them down using matchesToPerform.
*
* Returns a mongo aggregate query.
*/
let assembleSearchQuery = function({ joinsToPerform, matchesToPerform }) {
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;
}

// 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({});
}
listOfOrs.push(buildOrQuery({ queries: match }));
}
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 });
}

return aggregatePipeline;
};

module.exports = {
assembleSearchQuery,
buildAndQuery,
buildComparatorQuery,
buildContainsQuery,
buildEndsWithQuery,
buildEqualToQuery,
buildExistsQuery,
buildOrQuery,
buildInRangeQuery,
buildStartsWithQuery,
};
Loading

0 comments on commit f5a52c7

Please sign in to comment.