Skip to content

Commit

Permalink
Merge branch 'smart-dstu2' of https://github.com/smart-on-fhir/fhir.js
Browse files Browse the repository at this point in the history
…into smart-on-fhir-smart-dstu2
  • Loading branch information
niquola committed Mar 30, 2016
2 parents 11a19dc + ee28efc commit de70e76
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 27 deletions.
2 changes: 1 addition & 1 deletion node_tests/nodeAdapterSpec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ new_pt =

describe "nodejs adapter", ->

@timeout(10000);
@timeout(10000)

subject = fhir(baseUrl: 'http://localhost:8976/node_test', patient: '123', auth: {user: 'client', pass: 'secret'})

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
},
"scripts": {
"start": "webpack-dev-server --port $PORT --progress --colors",
"build": "rm -rf dist && `npm bin`/webpack --progress --colors && coffee --output lib --compile src",
"build": "rm -rf dist && `npm bin`/webpack --progress --colors && `npm bin`/coffee --output lib --compile src",
"spec": "node_modules/karma/bin/karma start --single-run",
"integrate": "node_modules/karma/bin/karma start karma-itegration.conf.js --single-run",
"node-test": "node_modules/.bin/jasmine-node --coffee node_tests",
"node-test": "node_modules/.bin/mocha --compilers mocha --compilers coffee:coffee-script/register node_tests",
"spec-node": " node_modules/.bin/mocha --compilers mocha --compilers coffee:coffee-script/register",
"spec-watch": "node_modules/karma/bin/karma start",
"all-tests": "npm run node-test && npm run spec && npm run spec-node && npm run integrate"
Expand Down
7 changes: 4 additions & 3 deletions src/adapters/jquery.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
(function() {
var mkFhir = require('../fhir');
var jquery = window['_jQuery'] || window['jQuery'];

var defer = function(){
pr = jQuery.Deferred();
pr = jquery.Deferred();
pr.promise = pr.promise();
return pr;
};
var adapter = {
defer: defer,
http: function(args) {
var ret = jQuery.Deferred();
var ret = jquery.Deferred();
var opts = {
type: args.method,
url: args.url,
Expand All @@ -18,7 +19,7 @@
contentType: "application/json",
data: args.data || args.params
};
jQuery.ajax(opts)
jquery.ajax(opts)
.done(function(data, status, xhr) {ret.resolve({data: data, status: status, headers: xhr.getResponseHeader, config: args});})
.fail(function(err) {ret.reject({error: err, data: err, config: args});});
return ret.promise();
Expand Down
123 changes: 123 additions & 0 deletions src/decorate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
(function() {
var fhirAPI;
var adapter;

function getNext (bundle, process) {
var i;
var d = bundle.data.entry || [];
var entries = [];
for (i = 0; i < d.length; i++) {
entries.push(d[i].resource);
}
process(entries);
var def = adapter.defer();
fhirAPI.nextPage({bundle:bundle.data}).then(function (r) {
getNext(r, process).then(function (t) {
def.resolve();
});
}, function(err) {def.resolve()});
return def.promise;
}

function drain (searchParams, process, done, fail) {
var ret = adapter.defer();

fhirAPI.search(searchParams).then(function(data){
getNext(data, process).then(function() {
done();
}, function(err) {
fail(err);
});
}, function(err) {
fail(err);
});
};

function fetchAll (searchParams){
var ret = adapter.defer();
var results = [];

drain(
searchParams,
function(entries) {
entries.forEach(function(entry) {
results.push(entry);
});
},
function () {
ret.resolve(results);
},
function (err) {
ret.reject(err);
}
);

return ret.promise;
};

function fetchAllWithReferences (searchParams, resolveParams) {
var ret = adapter.defer();

fhirAPI.search(searchParams) // TODO: THIS IS NOT CORRECT (need fetchAll, but it does not return a bundle yet)
.then(function(results){

var resolvedReferences = {};

var queue = [function() {ret.resolve(results, resolvedReferences);}];

function enqueue (bundle,resource,reference) {
queue.push(function() {resolveReference(bundle,resource,reference)});
}

function next() {
(queue.pop())();
}

function resolveReference (bundle,resource,reference) {
var referenceID = reference.reference;
fhirAPI.resolve({'bundle': bundle, 'resource': resource, 'reference':reference}).then(function(res){
var referencedObject = res.data || res.content;
resolvedReferences[referenceID] = referencedObject;
next();
});
}

var bundle = results.data;

bundle.entry && bundle.entry.forEach(function(element){
var resource = element.resource;
var type = resource.resourceType;
resolveParams && resolveParams.forEach(function(resolveParam){
var param = resolveParam.split('.');
var targetType = param[0];
var targetElement = param[1];
var reference = resource[targetElement];
if (type === targetType && reference) {
var referenceID = reference.reference;
if (!resolvedReferences[referenceID]) {
enqueue(bundle,resource,reference);
}
}
});
});

next();

}, function(){
ret.reject("Could not fetch search results");
});

return ret.promise;
};

function decorate (client, newAdapter) {
fhirAPI = client;
adapter = newAdapter;
client["drain"] = drain;
client["fetchAll"] = fetchAll;
client["fetchAllWithReferences"] = fetchAllWithReferences;
return client;
}

module.exports = decorate;
}).call(this);
9 changes: 5 additions & 4 deletions src/fhir.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
var pt = require('./middlewares/patient');
var refs = require('./middlewares/references');
var url = require('./middlewares/url');
var decorate = require('./decorate');

var cache = {};

Expand Down Expand Up @@ -51,25 +52,25 @@

var $Paging = Middleware(query.$Paging);

return {
return decorate({
conformance: GET.and(BaseUrl.slash("metadata")).end(http),
document: POST.and(BaseUrl.slash("Document")).end(http),
profile: GET.and(BaseUrl.slash("Profile").slash(":type")).end(http),
transaction: POST.and(BaseUrl).end(http),
history: GET.and(BaseUrl.slash("_history")).and($Paging).end(http),
typeHistory: GET.and(resourceTypeHxPath).and($Paging).end(http),
resourceHistory: GET.and(resourceHxPath).and($Paging).end(http),
read: GET.and(resourcePath).end(http),
read: GET.and(pt.$WithPatient).and(resourcePath).end(http),
vread: GET.and(vreadPath).end(http),
"delete": DELETE.and(resourcePath).and(ReturnHeader).end(http),
create: POST.and(resourceTypePath).and(ReturnHeader).end(http),
validate: POST.and(resourceTypePath.slash("_validate")).end(http),
search: GET.and(searchPath).and(pt.$WithPatient).and(query.$SearchParams).and($Paging).end(http),
search: GET.and(resourceTypePath).and(pt.$WithPatient).and(query.$SearchParams).and($Paging).end(http),
update: PUT.and(resourcePath).and(ReturnHeader).end(http),
nextPage: GET.and(bundle.$$BundleLinkUrl("next")).end(http),
prevPage: GET.and(bundle.$$BundleLinkUrl("prev")).end(http),
resolve: GET.and(refs.resolve).end(http)
};
}, adapter);

};
module.exports = fhir;
Expand Down
1 change: 1 addition & 0 deletions src/middlewares/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exports.$$BundleLinkUrl = function(rel){
var res = args.bundle && (args.bundle.link || []).filter(matched)[0];
if(res && res.url){
args.url = res.url;
args.data = null;
return h(args);
}
else{
Expand Down
73 changes: 61 additions & 12 deletions src/middlewares/patient.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,69 @@
(function() {
var mw = require('./core');

var keyFor = {
"Observation": "subject",
"MedicationPrescription": "patient"
};
// List of resources with 'patient' or 'subject' properties (as of FHIR DSTU2 1.0.0)
var targets = [
"Account",
"AllergyIntolerance",
"BodySite",
"CarePlan",
"Claim",
"ClinicalImpression",
"Communication",
"CommunicationRequest",
"Composition",
"Condition",
"Contract",
"DetectedIssue",
"Device",
"DeviceUseRequest",
"DeviceUseStatement",
"DiagnosticOrder",
"DiagnosticReport",
"DocumentManifest",
"DocumentReference",
"Encounter",
"EnrollmentRequest",
"EpisodeOfCare",
"FamilyMemberHistory",
"Flag",
"Goal",
"ImagingObjectSelection",
"ImagingStudy",
"Immunization",
"ImmunizationRecommendation",
"List",
"Media",
"MedicationAdministration",
"MedicationDispense",
"MedicationOrder",
"MedicationStatement",
"NutritionOrder",
"Observation",
"Order",
"Procedure",
"ProcedureRequest",
"QuestionnaireResponse",
"ReferralRequest",
"RelatedPerson",
"RiskAssessment",
"Specimen",
"SupplyDelivery",
"SupplyRequest",
"VisionPrescription"
];

exports.$WithPatient = mw.$$Simple(function(args){
var type = args.type;
var param = keyFor[type];
if (args.patient && param){
args.query = args.query || {};
args.query[param] = {
$type: "Patient",
_id: args.patient
};
var type = args.type;
if (args.patient) {
if (type === "Patient") {
args.query = args.query || {};
args.query["_id"] = args.patient;
args["id"] = args.patient;
} else if (targets.indexOf(type) >= 0){
args.query = args.query || {};
args.query["patient"] = args.patient;
}
}
return args;
});
Expand Down
1 change: 1 addition & 0 deletions src/middlewares/references.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
throw new Error("Contained resource not found");
}
args.url = utils.absoluteUrl(args.baseUrl, ref.reference);
args.data = null;
return h(args);
};
};
Expand Down
3 changes: 2 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@
exports.mergeLists = mergeLists;

var absoluteUrl = function(baseUrl, ref) {
if (ref.slice(ref, baseUrl.length + 1) !== baseUrl + "/") {
console.log(baseUrl, ref)
if (!ref.match(/https?:\/\/./)) {
return baseUrl + "/" + ref;
} else {
return ref;
Expand Down
6 changes: 3 additions & 3 deletions test/patientSpec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ describe "Search by patient:", ()->

it 'Add pt param', (done)->
http = (opt)->
assert.equal(opt.url, 'BASE/Observation?_id=5&subject:Patient._id=123')
assert.equal(opt.url, 'BASE/Observation?_id=5&patient=123')
done()

subject.search(type: 'Observation', query: {_id: 5}, http: http);

it 'Add pt param', (done)->
http = (opt)->
assert.equal(opt.url, 'BASE/MedicationPrescription?_id=5&patient:Patient._id=123')
assert.equal(opt.url, 'BASE/MedicationOrder?patient=123')
done()

subject.search(type: 'MedicationPrescription', query: {_id: 5}, http: http);
subject.search(type: 'MedicationOrder', http: http);

it 'Skip non relevant types', (done)->
http = (opt)->
Expand Down
4 changes: 3 additions & 1 deletion test/utilsSpec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ describe "utils", ->

it "url utils", ->
assert.deepEqual(utils.absoluteUrl("BASE", "Patient/123"), "BASE/Patient/123")
assert.deepEqual(utils.absoluteUrl("BASE", "Patient/123"), "BASE/Patient/123")
assert.deepEqual(utils.absoluteUrl("BASE", "http://test/Patient/123"), "http://test/Patient/123")

assert.deepEqual(utils.relativeUrl("BASE", "BASE/Patient/123"), "Patient/123")
assert.deepEqual(utils.absoluteUrl("BASE", "BASE/Patient/123"), "BASE/Patient/123")
assert.deepEqual(utils.relativeUrl("BASE", "Patient/123"), "Patient/123")

it "resourceIdToUrl", ->
Expand Down

0 comments on commit de70e76

Please sign in to comment.