func (s *ServiceSuite) TestBundleToEventStreamUnsupportedEvent(c *C) {
	data, err := ioutil.ReadFile("fixtures/brad_bradworth_event_source_bundle.json")
	util.CheckErr(err)

	bundle := new(models.Bundle)
	json.Unmarshal(data, bundle)

	bundle.Entry = append(bundle.Entry, models.BundleEntryComponent{
		Resource: &models.Encounter{},
		Search: &models.BundleEntrySearchComponent{
			Mode: "include",
		},
	})

	_, err = BundleToEventStream(bundle)
	c.Assert(err, NotNil)
	c.Assert(err.Error(), Equals, "Unsupported: Converting Encounter to Event")
}
func (dal *mongoDataAccessLayer) Search(baseURL url.URL, searchQuery search.Query) (*models.Bundle, error) {
	searcher := search.NewMongoSearcher(dal.Database)

	var result interface{}
	var err error
	usesIncludes := len(searchQuery.Options().Include) > 0
	usesRevIncludes := len(searchQuery.Options().RevInclude) > 0
	// Only use (slower) pipeline if it is needed
	if usesIncludes || usesRevIncludes {
		result = models.NewSlicePlusForResourceName(searchQuery.Resource, 0, 0)
		err = searcher.CreatePipeline(searchQuery).All(result)
	} else {
		result = models.NewSliceForResourceName(searchQuery.Resource, 0, 0)
		err = searcher.CreateQuery(searchQuery).All(result)
	}
	if err != nil {
		return nil, convertMongoErr(err)
	}

	includesMap := make(map[string]interface{})
	var entryList []models.BundleEntryComponent
	resultVal := reflect.ValueOf(result).Elem()
	for i := 0; i < resultVal.Len(); i++ {
		var entry models.BundleEntryComponent
		entry.Resource = resultVal.Index(i).Addr().Interface()
		entry.Search = &models.BundleEntrySearchComponent{Mode: "match"}
		entryList = append(entryList, entry)

		if usesIncludes || usesRevIncludes {
			rpi, ok := entry.Resource.(ResourcePlusRelatedResources)
			if ok {
				for k, v := range rpi.GetIncludedAndRevIncludedResources() {
					includesMap[k] = v
				}
			}
		}
	}

	for _, v := range includesMap {
		var entry models.BundleEntryComponent
		entry.Resource = v
		entry.Search = &models.BundleEntrySearchComponent{Mode: "include"}
		entryList = append(entryList, entry)
	}

	var bundle models.Bundle
	bundle.Id = bson.NewObjectId().Hex()
	bundle.Type = "searchset"
	bundle.Entry = entryList

	options := searchQuery.Options()

	// Need to get the true total (not just how many were returned in this response)
	var total uint32
	if resultVal.Len() == options.Count || resultVal.Len() == 0 {
		// Need to get total count from the server, since there may be more or the offset was too high
		intTotal, err := searcher.CreateQueryWithoutOptions(searchQuery).Count()
		if err != nil {
			return nil, convertMongoErr(err)
		}
		total = uint32(intTotal)
	} else {
		// We can figure out the total by adding the offset and # results returned
		total = uint32(options.Offset + resultVal.Len())
	}
	bundle.Total = &total

	// Add links for paging
	bundle.Link = generatePagingLinks(baseURL, searchQuery, total)

	return &bundle, nil
}
func (s *ServiceSuite) TestEndToEndCalculationsWithNACHADS(c *C) {
	// Get the test data for Chad Chadworth (for the CHADS test -- get it?)
	data, err := os.Open("fixtures/chad_chadworth_bundle.json")
	util.CheckErr(err)
	defer data.Close()

	// Remove the AFib entry (index 5) so he is Not Applicable
	bundle := new(models.Bundle)
	decoder := json.NewDecoder(data)
	err = decoder.Decode(bundle)
	util.CheckErr(err)
	bundle.Entry = append(bundle.Entry[:5], bundle.Entry[6:]...)
	b, err := json.Marshal(bundle)
	util.CheckErr(err)

	// Store Chad Chadworth's modified information to Mongo
	res, err := http.Post(s.Server.URL+"/", "application/json", bytes.NewBuffer(b))
	util.CheckErr(err)
	defer res.Body.Close()

	// Get the response so we can pull out the patient ID
	decoder = json.NewDecoder(res.Body)
	responseBundle := new(models.Bundle)
	err = decoder.Decode(responseBundle)
	util.CheckErr(err)
	patientID := responseBundle.Entry[0].Resource.(*models.Patient).Id

	// Confirm there are no risk assessments or pies
	raCollection := s.Database.C("riskassessments")
	count, err := raCollection.Count()
	util.CheckErr(err)
	c.Assert(count, Equals, 0)
	piesCollection := s.Database.C("pies")
	count, err = piesCollection.Count()
	util.CheckErr(err)
	c.Assert(count, Equals, 0)

	// Now register the plugins and request the calculation!
	s.Service.RegisterPlugin(assessments.NewCHA2DS2VAScPlugin())
	s.Service.RegisterPlugin(assessments.NewSimplePlugin())

	err = s.Service.Calculate(patientID, s.Server.URL, s.Server.URL+"/pies")
	util.CheckErr(err)

	count, err = raCollection.Find(bson.M{"method.coding.code": "CHADS"}).Count()
	util.CheckErr(err)
	c.Assert(count, Equals, 1)
	count, err = raCollection.Find(bson.M{"method.coding.code": "Simple"}).Count()
	util.CheckErr(err)
	c.Assert(count, Equals, 4)
	count, err = piesCollection.Count()
	util.CheckErr(err)
	c.Assert(count, Equals, 4)

	var ras []models.RiskAssessment
	err = raCollection.Find(bson.M{"method.coding.code": "CHADS"}).All(&ras)
	util.CheckErr(err)

	// Check that the CHADS is not applicable
	c.Assert(ras, HasLen, 1)
	ra := ras[0]
	c.Assert(ra.Subject.Reference, Equals, "Patient/"+patientID)
	c.Assert(ra.Method.MatchesCode("http://interventionengine.org/risk-assessments", "CHADS"), Equals, true)
	c.Assert(time.Now().Sub(ra.Date.Time) < time.Minute, Equals, true)
	c.Assert(ra.Prediction, HasLen, 1)
	c.Assert(ra.Prediction[0].Outcome.Text, Equals, "Stroke")
	c.Assert(ra.Prediction[0].ProbabilityCodeableConcept.Coding, HasLen, 1)
	c.Assert(ra.Prediction[0].ProbabilityCodeableConcept.Coding[0].System, Equals, "http://snomed.info/sct")
	c.Assert(ra.Prediction[0].ProbabilityCodeableConcept.Coding[0].Code, Equals, "385432009")
	c.Assert(ra.Prediction[0].ProbabilityCodeableConcept.Text, Equals, "Not applicable")
	c.Assert(ra.Basis, HasLen, 0)
	c.Assert(ra.Meta.Tag, HasLen, 1)
	c.Assert(ra.Meta.Tag[0], DeepEquals, models.Coding{System: "http://interventionengine.org/tags/", Code: "MOST_RECENT"})

	// Simple should still be good
	ras = nil
	err = raCollection.Find(bson.M{"method.coding.code": "Simple"}).Sort("date.time").All(&ras)
	util.CheckErr(err)

	loc := time.FixedZone("-0500", -5*60*60)
	s.checkSimpleRiskAssessment(c, &ras[0], patientID, time.Date(2012, time.September, 20, 8, 0, 0, 0, loc), 1, false)
	s.checkSimplePie(c, &ras[0], patientID, 1, 0)
	s.checkSimpleRiskAssessment(c, &ras[1], patientID, time.Date(2013, time.September, 2, 10, 0, 0, 0, loc), 3, false)
	s.checkSimplePie(c, &ras[1], patientID, 2, 1)
	s.checkSimpleRiskAssessment(c, &ras[2], patientID, time.Date(2014, time.January, 17, 20, 35, 0, 0, loc), 4, false)
	s.checkSimplePie(c, &ras[2], patientID, 3, 1)
	s.checkSimpleRiskAssessment(c, &ras[3], patientID, time.Date(2014, time.January, 17, 20, 40, 0, 0, loc), 3, true)
	s.checkSimplePie(c, &ras[3], patientID, 2, 1)
}
예제 #4
0
func (rc *ResourceController) IndexHandler(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer func() {
		if r := recover(); r != nil {
			rw.Header().Set("Content-Type", "application/json; charset=utf-8")
			switch x := r.(type) {
			case search.Error:
				rw.WriteHeader(x.HTTPStatus)
				json.NewEncoder(rw).Encode(x.OperationOutcome)
				return
			default:
				outcome := &models.OperationOutcome{
					Issue: []models.OperationOutcomeIssueComponent{
						models.OperationOutcomeIssueComponent{
							Severity: "fatal",
							Code:     "exception",
						},
					},
				}
				rw.WriteHeader(http.StatusInternalServerError)
				json.NewEncoder(rw).Encode(outcome)
			}
		}
	}()

	result := models.NewSliceForResourceName(rc.Name, 0, 0)

	// Create and execute the Mongo query based on the http query params
	searcher := search.NewMongoSearcher(Database)
	searchQuery := search.Query{Resource: rc.Name, Query: r.URL.RawQuery}
	mgoQuery := searcher.CreateQuery(searchQuery)

	// Horrible, horrible hack (for now) to ensure patients are sorted by name.  This is needed by
	// the frontend, else paging won't work correctly.  This should be removed when the general
	// sorting feature is implemented.
	if rc.Name == "Patient" {
		// To add insult to injury, mongo will not let us sort by family *and* given name:
		// Executor error: BadValue cannot sort with keys that are parallel arrays
		mgoQuery = mgoQuery.Sort("name.0.family.0" /*", name.0.given.0"*/, "_id")
	}

	err := mgoQuery.All(result)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}

	var entryList []models.BundleEntryComponent
	resultVal := reflect.ValueOf(result).Elem()
	for i := 0; i < resultVal.Len(); i++ {
		var entry models.BundleEntryComponent
		entry.Resource = resultVal.Index(i).Addr().Interface()
		entryList = append(entryList, entry)
	}

	var bundle models.Bundle
	bundle.Id = bson.NewObjectId().Hex()
	bundle.Type = "searchset"
	bundle.Entry = entryList

	options := searchQuery.Options()

	// Need to get the true total (not just how many were returned in this response)
	var total uint32
	if resultVal.Len() == options.Count || resultVal.Len() == 0 {
		// Need to get total count from the server, since there may be more or the offset was too high
		intTotal, err := searcher.CreateQueryWithoutOptions(searchQuery).Count()
		if err != nil {
			http.Error(rw, err.Error(), http.StatusInternalServerError)
		}
		total = uint32(intTotal)
	} else {
		// We can figure out the total by adding the offset and # results returned
		total = uint32(options.Offset + resultVal.Len())
	}
	bundle.Total = &total

	// Add links for paging
	bundle.Link = generatePagingLinks(r, searchQuery, total)

	context.Set(r, rc.Name, reflect.ValueOf(result).Elem().Interface())
	context.Set(r, "Resource", rc.Name)
	context.Set(r, "Action", "search")

	rw.Header().Set("Content-Type", "application/json; charset=utf-8")
	rw.Header().Set("Access-Control-Allow-Origin", "*")
	json.NewEncoder(rw).Encode(&bundle)
}