def insert_codes(self): self.code_dao.insert(self.CODE_1) self.code_dao.insert(self.CODE_2) self.code_dao.insert(self.CODE_3) self.code_dao.insert(self.CODE_4) self.code_dao.insert(self.CODE_5) self.code_dao.insert(self.CODE_6) self.code_dao.insert(self.MODULE_CODE_7) self.code_dao.insert(self.skip_code) self.consent_code_id = self.code_dao.insert(consent_code()).codeId self.first_name_code_id = self.code_dao.insert( first_name_code()).codeId self.last_name_code_id = self.code_dao.insert(last_name_code()).codeId self.email_code_id = self.code_dao.insert(email_code()).codeId self.login_phone_number_code_id = self.code_dao.insert( login_phone_number_code()).codeId self.FN_QUESTION = QuestionnaireQuestion( linkId='fn', codeId=self.first_name_code_id, repeats=False) self.LN_QUESTION = QuestionnaireQuestion(linkId='ln', codeId=self.last_name_code_id, repeats=False) self.EMAIL_QUESTION = QuestionnaireQuestion(linkId='email', codeId=self.email_code_id, repeats=False) self.LOGIN_PHONE_NUMBER_QUESTION = QuestionnaireQuestion( linkId='lpn', codeId=self.login_phone_number_code_id, repeats=False) self.first_name = self.fake.first_name() self.last_name = self.fake.last_name() self.email = self.fake.email() self.login_phone_number = self.fake.phone_number() self.FN_ANSWER = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=3, questionnaireResponseId=1, questionId=3, valueString=self.first_name) self.LN_ANSWER = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=4, questionnaireResponseId=1, questionId=4, valueString=self.last_name) self.EMAIL_ANSWER = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=5, questionnaireResponseId=1, questionId=5, valueString=self.email) self.LOGIN_PHONE_NUMBER_ANSWER = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=6, questionnaireResponseId=1, questionId=6, valueString=self.login_phone_number)
def _populate_codes_and_answers(cls, group, code_map, answers, link_id_to_question, questionnaire_id): """Populates code_map with (system, code) -> (display, code type, question code id) and answers with (QuestionnaireResponseAnswer, (system, code)) pairs.""" if group.question: for question in group.question: if question.linkId and question.answer: qq = link_id_to_question.get(question.linkId) if qq: for answer in question.answer: qr_answer = QuestionnaireResponseAnswer(questionId=qq.questionnaireQuestionId) system_and_code = None ignore_answer = False if answer.valueCoding: if not answer.valueCoding.system: raise BadRequest("No system provided for valueCoding: %s" % question.linkId) if not answer.valueCoding.code: raise BadRequest("No code provided for valueCoding: %s" % question.linkId) if answer.valueCoding.system == PPI_EXTRA_SYSTEM: # Ignore answers from the ppi-extra system, as they aren't used for analysis. ignore_answer = True else: system_and_code = (answer.valueCoding.system, answer.valueCoding.code) if not system_and_code in code_map: code_map[system_and_code] = (answer.valueCoding.display, CodeType.ANSWER, qq.codeId) if not ignore_answer: if answer.valueDecimal is not None: qr_answer.valueDecimal = answer.valueDecimal if answer.valueInteger is not None: qr_answer.valueInteger = answer.valueInteger if answer.valueString: answer_length = len(answer.valueString) max_length = QuestionnaireResponseAnswer.VALUE_STRING_MAXLEN if answer_length > max_length: err_msg = 'String value too long (len=%d); must be less than %d' raise BadRequest(err_msg % (answer_length, max_length)) qr_answer.valueString = answer.valueString if answer.valueDate is not None: qr_answer.valueDate = answer.valueDate.date if answer.valueDateTime is not None: qr_answer.valueDateTime = answer.valueDateTime.date if answer.valueBoolean is not None: qr_answer.valueBoolean = answer.valueBoolean if answer.valueUri is not None: qr_answer.valueUri = answer.valueUri answers.append((qr_answer, system_and_code)) if answer.group: for sub_group in answer.group: cls._populate_codes_and_answers(sub_group, code_map, answers, link_id_to_question, questionnaire_id) if group.group: for sub_group in group.group: cls._populate_codes_and_answers(sub_group, code_map, answers, link_id_to_question, questionnaire_id)
def test_insert_duplicate(self): self.insert_codes() p = Participant(participantId=1, biobankId=2) self.participant_dao.insert(p) self._setup_questionnaire() qr = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE) qr.answers.extend(self._names_and_email_answers()) self.questionnaire_response_dao.insert(qr) qr2 = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE_2) qr2.answers.append( QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2, questionnaireResponseId=1, questionId=2, valueSystem='c', valueCodeId=4)) with self.assertRaises(IntegrityError): self.questionnaire_response_dao.insert(qr2)
def test_insert_not_name_answers(self): self.insert_codes() p = Participant(participantId=1, biobankId=2) self.participant_dao.insert(p) self._setup_questionnaire() qr = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE) qr.answers.append( QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2, questionnaireResponseId=1, questionId=2, valueSystem='c', valueCodeId=4)) # Both first and last name are required. with self.assertRaises(BadRequest): self.questionnaire_response_dao.insert(qr)
def test_schema(self): session = self.database.make_session() hpo = HPO(hpoId=1, name='UNSET', displayName='No organization set', organizationType=OrganizationType.UNSET) code_book = CodeBook(codeBookId=1, created=datetime.datetime.now(), latest=True, name="pmi", system="http://foo/bar", version="v0.1.1") session.add(hpo) session.add(code_book) session.commit() organization = Organization(organizationId=1, externalId='org', displayName='Organization', hpoId=1) session.add(organization) session.commit() site = Site(siteId=1, siteName='site', googleGroup='*****@*****.**', mayolinkClientNumber=12345, organizationId=1) code1 = Code(codeId=1, codeBookId=1, system="a", value="b", shortValue="q", display=u"c", topic=u"d", codeType=CodeType.MODULE, mapped=True, created=datetime.datetime.now()) codeHistory1 = CodeHistory(codeId=1, codeBookId=1, system="a", value="b", shortValue="q", display=u"c", topic=u"d", codeType=CodeType.MODULE, mapped=True, created=datetime.datetime.now()) session.add(site) session.add(code1) session.add(codeHistory1) session.commit() code2 = Code(codeId=2, codeBookId=1, parentId=1, system="a", value="c", display=u"X", topic=u"d", codeType=CodeType.QUESTION, mapped=True, created=datetime.datetime.now()) codeHistory2 = CodeHistory(codeId=2, codeBookId=1, parentId=1, system="a", value="c", display=u"X", topic=u"d", codeType=CodeType.QUESTION, mapped=True, created=datetime.datetime.now()) session.add(code2) session.add(codeHistory2) session.commit() code3 = Code(codeId=3, codeBookId=1, parentId=2, system="a", value="d", display=u"Y", topic=u"d", codeType=CodeType.ANSWER, mapped=False, created=datetime.datetime.now()) codeHistory3 = CodeHistory(codeId=3, codeBookId=1, parentId=2, system="a", value="d", display=u"Y", topic=u"d", codeType=CodeType.ANSWER, mapped=False, created=datetime.datetime.now()) session.add(code3) session.add(codeHistory3) session.commit() session.commit() p = self._participant_with_defaults( participantId=1, version=1, biobankId=2, clientId='*****@*****.**', hpoId=hpo.hpoId, signUpTime=datetime.datetime.now(), lastModified=datetime.datetime.now()) ps = self._participant_summary_with_defaults( participantId=1, biobankId=2, lastModified=datetime.datetime.now(), hpoId=hpo.hpoId, firstName=self.fake.first_name(), middleName=self.fake.first_name(), lastName=self.fake.last_name(), email=self.fake.email(), zipCode='78751', dateOfBirth=datetime.date.today(), genderIdentityId=1, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForStudyEnrollmentTime=datetime.datetime.now(), numBaselineSamplesArrived=2) p.participantSummary = ps session.add(p) ph = self._participant_history_with_defaults( participantId=1, biobankId=2, clientId='*****@*****.**', hpoId=hpo.hpoId, signUpTime=datetime.datetime.now(), lastModified=datetime.datetime.now()) session.add(ph) session.commit() session.add( BiobankStoredSample(biobankStoredSampleId='WEB1234542', biobankId=p.biobankId, biobankOrderIdentifier='KIT', test='1UR10', confirmed=datetime.datetime.utcnow())) session.add( BiobankStoredSample( biobankStoredSampleId='WEB99999', # Sample ID must be unique. biobankId=p. biobankId, # Participant ID and test may be duplicated. biobankOrderIdentifier='KIT', test='1UR10', confirmed=datetime.datetime.utcnow())) pm = PhysicalMeasurements(physicalMeasurementsId=1, participantId=1, created=datetime.datetime.now(), resource='blah', final=False, logPosition=LogPosition()) pm2 = PhysicalMeasurements(physicalMeasurementsId=2, participantId=1, created=datetime.datetime.now(), resource='blah', final=True, amendedMeasurementsId=1, logPosition=LogPosition()) session.add(pm) session.add(pm2) session.commit() q1 = Measurement(measurementId=3, physicalMeasurementsId=pm.physicalMeasurementsId, codeSystem='codeSystem', codeValue='codeValue', measurementTime=datetime.datetime.now(), valueCodeSystem='valueCodeSystem', valueCodeValue='value3') session.add(q1) session.commit() m1 = Measurement(measurementId=1, physicalMeasurementsId=pm.physicalMeasurementsId, codeSystem='codeSystem', codeValue='codeValue', measurementTime=datetime.datetime.now(), bodySiteCodeSystem='bodySiteCodeSystem', bodySiteCodeValue='bodySiteCodeValue', valueString='a', valueDecimal=1.2, valueUnit='cm', valueCodeSystem='valueCodeSystem', valueCodeValue='value', valueDateTime=datetime.datetime.now(), qualifierId=q1.measurementId) session.add(m1) session.commit() m2 = Measurement(measurementId=2, physicalMeasurementsId=pm.physicalMeasurementsId, codeSystem='codeSystem', codeValue='codeValue', measurementTime=datetime.datetime.now(), valueCodeSystem='valueCodeSystem', valueCodeValue='value2', parentId=m1.measurementId, qualifierId=q1.measurementId) session.add(m2) session.commit() q = Questionnaire(questionnaireId=1, version=1, created=datetime.datetime.now(), lastModified=datetime.datetime.now(), resource='what?') qh = QuestionnaireHistory(questionnaireId=1, version=1, created=datetime.datetime.now(), lastModified=datetime.datetime.now(), resource='what?') qh.questions.append( QuestionnaireQuestion(questionnaireQuestionId=1, questionnaireId=1, questionnaireVersion=1, linkId="1.2.3", codeId=2, repeats=True)) qh.concepts.append( QuestionnaireConcept(questionnaireConceptId=1, questionnaireId=1, questionnaireVersion=1, codeId=1)) session.add(q) session.add(qh) session.commit() qr = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, created=datetime.datetime.now(), resource='blah') qr.answers.append( QuestionnaireResponseAnswer(questionnaireResponseAnswerId=1, questionnaireResponseId=1, questionId=1, endTime=datetime.datetime.now(), valueSystem='a', valueCodeId=3, valueDecimal=123, valueString=self.fake.first_name(), valueDate=datetime.date.today())) session.add(qr) session.commit() mv = MetricsVersion(metricsVersionId=1, inProgress=False, complete=True, date=datetime.datetime.utcnow(), dataVersion=1) session.add(mv) session.commit() mb = MetricsBucket(metricsVersionId=1, date=datetime.date.today(), hpoId='PITT', metrics='blah') session.add(mb) session.commit()
def test_insert_qr_three_times(self): """Adds three questionnaire responses for the same participant. The latter two responses are for the same questionnaire, answering a question that has the same concept code and system as a question found on the first (different) questionnaire. Verifies that new answers set endTime on answers for questions with the same concept for the same participant, whether on the same questionnaire or a different questionnaire, without affecting other answers. """ self.insert_codes() p = Participant(participantId=1, biobankId=2) with FakeClock(TIME): self.participant_dao.insert(p) self._setup_questionnaire() q2 = Questionnaire(resource=QUESTIONNAIRE_RESOURCE_2) # The question on the second questionnaire has the same concept as the first question on the # first questionnaire; answers to it will thus set endTime for answers to the first question. q2.questions.append(self.CODE_1_QUESTION_2) self.questionnaire_dao.insert(q2) qr = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE) answer_1 = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=1, questionnaireResponseId=1, questionId=1, valueSystem='a', valueCodeId=3, valueDecimal=123, valueString=self.fake.first_name(), valueDate=datetime.date.today()) answer_2 = QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2, questionnaireResponseId=1, questionId=2, valueSystem='c', valueCodeId=4) qr.answers.append(answer_1) qr.answers.append(answer_2) qr.answers.extend(self._names_and_email_answers()) with FakeClock(TIME_2): self.questionnaire_response_dao.insert(qr) expected_ps = self._participant_summary_with_defaults( participantId=1, biobankId=2, genderIdentityId=3, signUpTime=TIME, numCompletedBaselinePPIModules=1, numCompletedPPIModules=1, questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED, questionnaireOnTheBasicsTime=TIME_2, questionnaireOnTheBasicsAuthored=TIME_2, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForStudyEnrollmentTime=TIME_2, consentForStudyEnrollmentAuthored=TIME_2, lastModified=TIME_2, firstName=self.first_name, lastName=self.last_name, email=self.email) self.assertEquals(expected_ps.asdict(), self.participant_summary_dao.get(1).asdict()) qr2 = QuestionnaireResponse(questionnaireResponseId=2, questionnaireId=2, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE_2) answer_3 = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=6, questionnaireResponseId=2, questionId=7, valueSystem='x', valueCodeId=5, valueDecimal=123, valueString=self.fake.last_name(), valueDate=datetime.date.today()) qr2.answers.append(answer_3) with FakeClock(TIME_3): qr2.authored = TIME_3 self.questionnaire_response_dao.insert(qr2) expected_qr = QuestionnaireResponse( questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1), created=TIME_2, authored=TIME_2) # Answer one on the original response should be marked as ended, since a question with # the same concept was answered. Answer two should be left alone. answer_1.endTime = TIME_3 expected_qr.answers.append(answer_1) expected_qr.answers.append(answer_2) expected_qr.answers.extend(self._names_and_email_answers()) self.check_response(expected_qr) # The new questionnaire response should be there, too. expected_qr2 = QuestionnaireResponse( questionnaireResponseId=2, questionnaireId=2, questionnaireVersion=1, participantId=1, resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE_2, 2), created=TIME_3, authored=TIME_3) expected_qr2.answers.append(answer_3) self.check_response(expected_qr2) expected_ps2 = self._participant_summary_with_defaults( participantId=1, biobankId=2, genderIdentityId=5, signUpTime=TIME, numCompletedBaselinePPIModules=1, numCompletedPPIModules=1, questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED, questionnaireOnTheBasicsTime=TIME_2, questionnaireOnTheBasicsAuthored=TIME_2, lastModified=TIME_3, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForStudyEnrollmentTime=TIME_2, consentForStudyEnrollmentAuthored=TIME_2, firstName=self.first_name, lastName=self.last_name, email=self.email) # The participant summary should be updated with the new gender identity, but nothing else # changes. self.assertEquals(expected_ps2.asdict(), self.participant_summary_dao.get(1).asdict()) qr3 = QuestionnaireResponse(questionnaireResponseId=3, questionnaireId=2, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE_3) answer_4 = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=7, questionnaireResponseId=3, questionId=7, valueSystem='z', valueCodeId=6, valueDecimal=456, valueString=self.fake.last_name(), valueDate=datetime.date.today()) qr3.answers.append(answer_4) with FakeClock(TIME_4): qr3.authored = TIME_4 self.questionnaire_response_dao.insert(qr3) # The first questionnaire response hasn't changed. self.check_response(expected_qr) # The second questionnaire response's answer should have had an endTime set. answer_3.endTime = TIME_4 self.check_response(expected_qr2) # The third questionnaire response should be there. expected_qr3 = QuestionnaireResponse( questionnaireResponseId=3, questionnaireId=2, questionnaireVersion=1, participantId=1, resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE_3, 3), created=TIME_4, authored=TIME_4) expected_qr3.answers.append(answer_4) self.check_response(expected_qr3) expected_ps3 = self._participant_summary_with_defaults( participantId=1, biobankId=2, genderIdentityId=6, signUpTime=TIME, numCompletedBaselinePPIModules=1, numCompletedPPIModules=1, questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED, questionnaireOnTheBasicsTime=TIME_2, questionnaireOnTheBasicsAuthored=TIME_2, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForStudyEnrollmentTime=TIME_2, consentForStudyEnrollmentAuthored=TIME_2, lastModified=TIME_4, firstName=self.first_name, lastName=self.last_name, email=self.email) # The participant summary should be updated with the new gender identity, but nothing else # changes. self.assertEquals(expected_ps3.asdict(), self.participant_summary_dao.get(1).asdict())
def test_insert_with_answers(self): self.insert_codes() p = Participant(participantId=1, biobankId=2) with FakeClock(TIME): self.participant_dao.insert(p) self._setup_questionnaire() qr = QuestionnaireResponse(questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=QUESTIONNAIRE_RESPONSE_RESOURCE) answer_1 = QuestionnaireResponseAnswer( questionnaireResponseAnswerId=1, questionnaireResponseId=1, questionId=1, valueSystem='a', valueCodeId=3, valueDecimal=123, valueString=self.fake.first_name(), valueDate=datetime.date.today()) answer_2 = QuestionnaireResponseAnswer(questionnaireResponseAnswerId=2, questionnaireResponseId=1, questionId=2, valueSystem='c', valueCodeId=4) qr.answers.append(answer_1) qr.answers.append(answer_2) names_and_email_answers = self._names_and_email_answers() qr.answers.extend(names_and_email_answers) with FakeClock(TIME_2): self.questionnaire_response_dao.insert(qr) expected_qr = QuestionnaireResponse( questionnaireResponseId=1, questionnaireId=1, questionnaireVersion=1, participantId=1, resource=with_id(QUESTIONNAIRE_RESPONSE_RESOURCE, 1), created=TIME_2, authored=TIME_2) qr2 = self.questionnaire_response_dao.get(1) self.assertEquals(expected_qr.asdict(), qr2.asdict()) expected_qr.answers.append(answer_1) expected_qr.answers.append(answer_2) expected_qr.answers.extend(names_and_email_answers) self.check_response(expected_qr) expected_ps = self._participant_summary_with_defaults( participantId=1, biobankId=2, genderIdentityId=3, signUpTime=TIME, numCompletedBaselinePPIModules=1, numCompletedPPIModules=1, questionnaireOnTheBasics=QuestionnaireStatus.SUBMITTED, questionnaireOnTheBasicsTime=TIME_2, questionnaireOnTheBasicsAuthored=TIME_2, consentForStudyEnrollment=QuestionnaireStatus.SUBMITTED, consentForStudyEnrollmentTime=TIME_2, consentForStudyEnrollmentAuthored=TIME_2, lastModified=TIME_2, firstName=self.first_name, lastName=self.last_name, email=self.email) self.assertEquals(expected_ps.asdict(), self.participant_summary_dao.get(1).asdict())