diff --git a/.gitignore b/.gitignore
index a98205f8c3..e613dc3e0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+WebAPIConfig/
*application.properties
.idea/
.metadata/
diff --git a/pom.xml b/pom.xml
index 3f011889c9..4dc14d0b0c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -205,6 +205,8 @@
info
info
info
+ info
+ info
warn
10
@@ -949,6 +951,11 @@
2.0.1
test
+
+ log4j
+ log4j
+ 1.2.17
+
diff --git a/src/main/java/org/ohdsi/webapi/cohortsample/CleanupCohortSamplesTasklet.java b/src/main/java/org/ohdsi/webapi/cohortsample/CleanupCohortSamplesTasklet.java
new file mode 100644
index 0000000000..269230f39a
--- /dev/null
+++ b/src/main/java/org/ohdsi/webapi/cohortsample/CleanupCohortSamplesTasklet.java
@@ -0,0 +1,145 @@
+package org.ohdsi.webapi.cohortsample;
+
+import org.ohdsi.webapi.cohortdefinition.CleanupCohortTasklet;
+import org.ohdsi.webapi.job.JobExecutionResource;
+import org.ohdsi.webapi.job.JobTemplate;
+import org.ohdsi.webapi.source.Source;
+import org.ohdsi.webapi.source.SourceDaimon;
+import org.ohdsi.webapi.source.SourceRepository;
+import org.ohdsi.webapi.util.PreparedStatementRenderer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.batch.core.job.builder.SimpleJobBuilder;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.ohdsi.webapi.Constants.Params.COHORT_DEFINITION_ID;
+import static org.ohdsi.webapi.Constants.Params.JOB_NAME;
+import static org.ohdsi.webapi.Constants.Params.SOURCE_ID;
+
+public class CleanupCohortSamplesTasklet implements Tasklet {
+ private static final Logger log = LoggerFactory.getLogger(CleanupCohortTasklet.class);
+
+ private final TransactionTemplate transactionTemplate;
+ private final SourceRepository sourceRepository;
+ private final CohortSamplingService samplingService;
+ private final CohortSampleRepository sampleRepository;
+
+ public CleanupCohortSamplesTasklet(
+ final TransactionTemplate transactionTemplate,
+ final SourceRepository sourceRepository,
+ CohortSamplingService samplingService,
+ CohortSampleRepository sampleRepository
+ ) {
+ this.transactionTemplate = transactionTemplate;
+ this.sourceRepository = sourceRepository;
+ this.samplingService = samplingService;
+ this.sampleRepository = sampleRepository;
+ }
+
+ private Integer doTask(ChunkContext chunkContext) {
+ Map jobParams = chunkContext.getStepContext().getJobParameters();
+ int cohortDefinitionId = Integer.parseInt(jobParams.get(COHORT_DEFINITION_ID).toString());
+
+ if (jobParams.containsKey(SOURCE_ID)) {
+ int sourceId = Integer.parseInt(jobParams.get(SOURCE_ID).toString());
+ Source source = this.sourceRepository.findOne(sourceId);
+ if (source != null) {
+ return mapSource(source, cohortDefinitionId);
+ } else {
+ return 0;
+ }
+ } else {
+ return this.sourceRepository.findAll().stream()
+ .filter(source-> source.getDaimons()
+ .stream()
+ .anyMatch(daimon -> daimon.getDaimonType() == SourceDaimon.DaimonType.Results))
+ .mapToInt(source -> mapSource(source, cohortDefinitionId))
+ .sum();
+ }
+ }
+
+ private int mapSource(Source source, int cohortDefinitionId) {
+ try {
+ String resultSchema = source.getTableQualifier(SourceDaimon.DaimonType.Results);
+ return transactionTemplate.execute(transactionStatus -> {
+ List samples = sampleRepository.findByCohortDefinitionIdAndSourceId(cohortDefinitionId, source.getId());
+ if (samples.isEmpty()) {
+ return 0;
+ }
+
+ sampleRepository.delete(samples);
+
+ int[] cohortSampleIds = samples.stream()
+ .mapToInt(CohortSample::getId)
+ .toArray();
+
+ PreparedStatementRenderer renderer = new PreparedStatementRenderer(
+ source,
+ "/resources/cohortsample/sql/deleteSampleElementsById.sql",
+ "results_schema",
+ resultSchema,
+ "cohortSampleId",
+ cohortSampleIds);
+
+ samplingService.getSourceJdbcTemplate(source)
+ .update(renderer.getSql(), renderer.getOrderedParams());
+ return cohortSampleIds.length;
+ });
+ } catch (Exception e) {
+ log.error("Error deleting samples for cohort: {}, cause: {}", cohortDefinitionId, e.getMessage());
+ return 0;
+ }
+ }
+
+ @Override
+ public RepeatStatus execute(final StepContribution contribution, final ChunkContext chunkContext) throws Exception {
+ this.transactionTemplate.execute(status -> doTask(chunkContext));
+
+ return RepeatStatus.FINISHED;
+ }
+
+ public JobExecutionResource launch(JobBuilderFactory jobBuilders, StepBuilderFactory stepBuilders, JobTemplate jobTemplate, int cohortDefinitionId) {
+ JobParametersBuilder builder = new JobParametersBuilder();
+ builder.addString(JOB_NAME, String.format("Cleanup cohort samples of cohort definition %d.", cohortDefinitionId));
+ builder.addString(COHORT_DEFINITION_ID, String.valueOf(cohortDefinitionId));
+
+ log.info("Beginning cohort cleanup for cohort definition id: {}", cohortDefinitionId);
+ return launch(jobBuilders, stepBuilders, jobTemplate, builder.toJobParameters());
+ }
+
+ public JobExecutionResource launch(JobBuilderFactory jobBuilders, StepBuilderFactory stepBuilders, JobTemplate jobTemplate, int cohortDefinitionId, int sourceId) {
+ JobParametersBuilder builder = new JobParametersBuilder();
+ builder.addString(JOB_NAME, String.format("Cleanup cohort samples of cohort definition %d.", cohortDefinitionId));
+ builder.addString(COHORT_DEFINITION_ID, String.valueOf(cohortDefinitionId));
+ builder.addString(SOURCE_ID, String.valueOf(sourceId));
+
+ log.info("Beginning cohort cleanup for cohort definition id {} and source ID {}", cohortDefinitionId, sourceId);
+ return launch(jobBuilders, stepBuilders, jobTemplate, builder.toJobParameters());
+ }
+
+ private JobExecutionResource launch(JobBuilderFactory jobBuilders, StepBuilderFactory stepBuilders, JobTemplate jobTemplate, JobParameters jobParameters) {
+ Step cleanupStep = stepBuilders.get("cohortSample.cleanupSamples")
+ .tasklet(this)
+ .build();
+
+ SimpleJobBuilder cleanupJobBuilder = jobBuilders.get("cleanupSamples")
+ .start(cleanupStep);
+
+ Job cleanupCohortJob = cleanupJobBuilder.build();
+
+ return jobTemplate.launch(cleanupCohortJob, jobParameters);
+ }
+}
diff --git a/src/main/java/org/ohdsi/webapi/cohortsample/CohortSample.java b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSample.java
new file mode 100644
index 0000000000..4bacd82e4f
--- /dev/null
+++ b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSample.java
@@ -0,0 +1,139 @@
+package org.ohdsi.webapi.cohortsample;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
+import org.ohdsi.webapi.model.CommonEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import java.util.List;
+
+/**
+ * Cohort sample details.
+ */
+@Entity(name = "CohortSample")
+@Table(name = "cohort_sample")
+public class CohortSample extends CommonEntity {
+ @Id
+ @GenericGenerator(
+ name = "cohort_sample_generator",
+ strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
+ parameters = {
+ @Parameter(name = "sequence_name", value = "cohort_sample_sequence"),
+ @Parameter(name = "increment_size", value = "1")
+ }
+ )
+ @GeneratedValue(generator = "cohort_sample_generator")
+ private Integer id;
+
+ @Column
+ private String name;
+
+ @Column(name = "cohort_definition_id")
+ private int cohortDefinitionId;
+
+ @Column(name = "source_id")
+ private int sourceId;
+
+ @Column(name = "age_mode")
+ private String ageMode;
+
+ @Column(name = "age_min")
+ private Integer ageMin;
+
+ @Column(name = "age_max")
+ private Integer ageMax;
+
+ @Column(name = "gender_concept_ids")
+ private String genderConceptIds;
+
+ @Column
+ private int size;
+
+ @Transient
+ private List elements;
+
+ public Integer getId() {
+ return this.id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public int getCohortDefinitionId() {
+ return cohortDefinitionId;
+ }
+
+ public void setCohortDefinitionId(int cohortDefinitionId) {
+ this.cohortDefinitionId = cohortDefinitionId;
+ }
+
+ public List getElements() {
+ return elements;
+ }
+
+ public void setElements(List elements) {
+ this.elements = elements;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public Integer getAgeMin() {
+ return ageMin;
+ }
+
+ public void setAgeMin(Integer ageMin) {
+ this.ageMin = ageMin;
+ }
+
+ public Integer getAgeMax() {
+ return ageMax;
+ }
+
+ public void setAgeMax(Integer ageMax) {
+ this.ageMax = ageMax;
+ }
+
+ public String getGenderConceptIds() {
+ return genderConceptIds;
+ }
+
+ public void setGenderConceptIds(String genderConceptIds) {
+ this.genderConceptIds = genderConceptIds;
+ }
+
+ public int getSourceId() {
+ return sourceId;
+ }
+
+ public void setSourceId(int sourceId) {
+ this.sourceId = sourceId;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getAgeMode() {
+ return ageMode;
+ }
+
+ public void setAgeMode(String ageMode) {
+ this.ageMode = ageMode;
+ }
+}
diff --git a/src/main/java/org/ohdsi/webapi/cohortsample/CohortSampleRepository.java b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSampleRepository.java
new file mode 100644
index 0000000000..d04aa4d941
--- /dev/null
+++ b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSampleRepository.java
@@ -0,0 +1,26 @@
+package org.ohdsi.webapi.cohortsample;
+
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * Repository of samples. This does not fetch any sample elements.
+ */
+@Component
+public interface CohortSampleRepository extends CrudRepository {
+ @Query("SELECT c FROM CohortSample c LEFT JOIN FETCH c.createdBy WHERE c.id = :id")
+ CohortSample findById(@Param("id") int cohortSampleId);
+
+ @Query("SELECT c FROM CohortSample c LEFT JOIN FETCH c.createdBy WHERE c.cohortDefinitionId = :cohortDefinitionId AND c.sourceId = :sourceId")
+ List findByCohortDefinitionIdAndSourceId(@Param("cohortDefinitionId") int cohortDefinitionId, @Param("sourceId") int sourceId);
+
+ @Query("SELECT count(c.id) FROM CohortSample c WHERE c.cohortDefinitionId = :cohortDefinitionId")
+ int countSamples(@Param("cohortDefinitionId") int cohortDefinitionId);
+
+ @Query("SELECT count(c.id) FROM CohortSample c WHERE c.cohortDefinitionId = :cohortDefinitionId AND c.sourceId = :sourceId")
+ int countSamples(@Param("cohortDefinitionId") int cohortDefinitionId, @Param("sourceId") int sourceId);
+}
diff --git a/src/main/java/org/ohdsi/webapi/cohortsample/CohortSamplingService.java b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSamplingService.java
new file mode 100644
index 0000000000..eb47bd851e
--- /dev/null
+++ b/src/main/java/org/ohdsi/webapi/cohortsample/CohortSamplingService.java
@@ -0,0 +1,511 @@
+package org.ohdsi.webapi.cohortsample;
+
+import org.ohdsi.webapi.cohortsample.dto.CohortSampleDTO;
+import org.ohdsi.webapi.cohortsample.dto.SampleElementDTO;
+import org.ohdsi.webapi.cohortsample.dto.SampleParametersDTO;
+import org.ohdsi.webapi.job.JobTemplate;
+import org.ohdsi.webapi.service.AbstractDaoService;
+import org.ohdsi.webapi.shiro.Entities.UserEntity;
+import org.ohdsi.webapi.source.Source;
+import org.ohdsi.webapi.source.SourceDaimon;
+import org.ohdsi.webapi.user.dto.UserDTO;
+import org.ohdsi.webapi.util.PreparedStatementRenderer;
+import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.support.TransactionCallback;
+
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.NotFoundException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.ohdsi.sql.SqlTranslate;
+
+import static org.ohdsi.webapi.cohortsample.dto.SampleParametersDTO.GenderDTO.GENDER_FEMALE_CONCEPT_ID;
+import static org.ohdsi.webapi.cohortsample.dto.SampleParametersDTO.GenderDTO.GENDER_MALE_CONCEPT_ID;
+import org.ohdsi.webapi.util.SourceUtils;
+
+/**
+ * Service to do manage samples of a cohort definition.
+ */
+@Component
+public class CohortSamplingService extends AbstractDaoService {
+ private final CohortSampleRepository sampleRepository;
+ private final JobBuilderFactory jobBuilders;
+ private final StepBuilderFactory stepBuilders;
+ private final JobTemplate jobTemplate;
+
+ @Autowired
+ public CohortSamplingService(
+ CohortSampleRepository sampleRepository,
+ JobBuilderFactory jobBuilders,
+ StepBuilderFactory stepBuilders,
+ JobTemplate jobTemplate) {
+ this.sampleRepository = sampleRepository;
+ this.jobBuilders = jobBuilders;
+ this.stepBuilders = stepBuilders;
+ this.jobTemplate = jobTemplate;
+ }
+
+ public List listSamples(int cohortDefinitionId, int sourceId) {
+ return sampleRepository.findByCohortDefinitionIdAndSourceId(cohortDefinitionId, sourceId).stream()
+ .map(sample -> sampleToSampleDTO(sample, null, false))
+ .collect(Collectors.toList());
+ }
+
+ public CohortSampleDTO getSample(int sampleId, boolean withRecordCounts) {
+ CohortSample sample = sampleRepository.findById(sampleId);
+ if (sample == null) {
+ throw new NotFoundException("Cohort sample with ID " + sampleId + " not found");
+ }
+ Source source = getSourceRepository().findBySourceId(sample.getSourceId());
+ List sampleElements = findSampleElements(source, sample.getId(), withRecordCounts);
+ return sampleToSampleDTO(sample, sampleElements, true);
+ }
+
+ public int countSamples(int cohortDefinitionId) {
+ return sampleRepository.countSamples(cohortDefinitionId);
+ }
+
+ public int countSamples(int cohortDefinitionId, int sourceId) {
+ return sampleRepository.countSamples(cohortDefinitionId, sourceId);
+ }
+
+ /**
+ * Find all sample elements of a sample.
+ * @param source Source to use
+ * @param cohortSampleId sample ID of the elements.
+ * @param withRecordCounts whether to return record counts. This makes the query much slower.
+ * @return list of elements.
+ */
+ private List findSampleElements(Source source, int cohortSampleId, boolean withRecordCounts) {
+ JdbcTemplate jdbcTemplate = getSourceJdbcTemplate(source);
+ PreparedStatementRenderer renderer;
+ Collection optionalFields;
+
+ if (withRecordCounts) {
+ renderer = new PreparedStatementRenderer(source, "/resources/cohortsample/sql/findElementsByCohortSampleIdWithCounts.sql",
+ new String[]{"results_schema", "CDM_schema"},
+ new String[]{source.getTableQualifier(SourceDaimon.DaimonType.Results), source.getTableQualifier(SourceDaimon.DaimonType.CDM)},
+ "cohortSampleId", cohortSampleId);
+ optionalFields = Collections.singleton("record_count");
+ } else {
+ renderer = new PreparedStatementRenderer(source, "/resources/cohortsample/sql/findElementsByCohortSampleId.sql",
+ "results_schema",
+ source.getTableQualifier(SourceDaimon.DaimonType.Results),
+ "cohortSampleId", cohortSampleId);
+ optionalFields = Collections.emptySet();
+ }
+ return jdbcTemplate.query(renderer.getSql(), renderer.getOrderedParams(), new CohortSampleElementRowMapper(optionalFields));
+ }
+
+ /**
+ * Create a new sample in given source and cohort definition, using sample parameters.
+ * @param source Source to use
+ * @param cohortDefinitionId cohort definition ID to sample
+ * @param sampleParameters parameters to define the sample
+ * @return list of elements.
+ */
+ public CohortSampleDTO createSample(Source source, int cohortDefinitionId, SampleParametersDTO sampleParameters) {
+ JdbcTemplate jdbcTemplate = getSourceJdbcTemplate(source);
+
+ CohortSample sample = new CohortSample();
+ sample.setName(sampleParameters.getName());
+ sample.setCohortDefinitionId(cohortDefinitionId);
+ sample.setSourceId(source.getId());
+ sample.setSize(sampleParameters.getSize());
+
+ SampleParametersDTO.AgeDTO age = sampleParameters.getAge();
+ if (age != null) {
+ switch (age.getMode()) {
+ case LESS_THAN:
+ case LESS_THAN_OR_EQUAL:
+ sample.setAgeMax(age.getValue());
+ break;
+ case GREATER_THAN:
+ case GREATER_THAN_OR_EQUAL:
+ sample.setAgeMin(age.getValue());
+ break;
+ case EQUAL_TO:
+ sample.setAgeMin(age.getValue());
+ sample.setAgeMax(age.getValue());
+ break;
+ case BETWEEN:
+ case NOT_BETWEEN:
+ sample.setAgeMin(age.getMin());
+ sample.setAgeMax(age.getMax());
+ break;
+ }
+ sample.setAgeMode(age.getMode().getSerialName());
+ }
+
+ SampleParametersDTO.GenderDTO gender = sampleParameters.getGender();
+ if (gender != null) {
+ StringBuilder sb = new StringBuilder(12);
+ for (Integer conceptId : gender.getConceptIds()) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(conceptId);
+ }
+ if (gender.isOtherNonBinary()) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(-1);
+ }
+ sample.setGenderConceptIds(sb.toString());
+ }
+ sample.setCreatedBy(getCurrentUser());
+ sample.setCreatedDate(new Date());
+
+ log.info("Sampling {} elements for cohort {}", sampleParameters.getSize(), cohortDefinitionId);
+ final List elements = sampleElements(sampleParameters, sample, jdbcTemplate, source);
+
+ if (elements.size() < sample.getSize()) {
+ sample.setSize(elements.size());
+ }
+
+ getTransactionTemplate().execute((TransactionCallback) transactionStatus -> {
+ log.debug("Saving {} sample elements for cohort {}", sample.getSize(), cohortDefinitionId);
+ CohortSample updatedSample = sampleRepository.save(sample);
+ insertSampledElements(source, jdbcTemplate, updatedSample.getId(), elements);
+
+ return null;
+ });
+
+ return sampleToSampleDTO(sample, elements, true);
+ }
+
+ /**
+ * Create a new sample in given source and cohort definition, using sample parameters.
+ * @param sampleId The sample to refresh
+ */
+ public void refreshSample(Integer sampleId) {
+
+ CohortSample sample = sampleRepository.findById(sampleId);
+ if (sample == null) {
+ throw new NotFoundException("Cohort sample with ID " + sampleId + " not found");
+ }
+ Source source = getSourceRepository().findBySourceId(sample.getSourceId());
+
+ CohortSampleDTO sampleDto = sampleToSampleDTO(sample, null, true);
+ SampleParametersDTO sampleParamaters = new SampleParametersDTO();
+ sampleParamaters.setAge(sampleDto.getAge());
+ sampleParamaters.setGender(sampleDto.getGender());
+ sampleParamaters.setSize(sampleDto.getSize());
+ log.info("Sampling {} elements for cohort {}", sampleParamaters.getSize(), sample.getCohortDefinitionId());
+ JdbcTemplate jdbcTemplate = getSourceJdbcTemplate(source);
+ final List elements = sampleElements(sampleParamaters, sample, jdbcTemplate, source);
+
+ getTransactionTemplate().execute((TransactionCallback) transactionStatus -> {
+ String deleteSql = String.format(
+ "DELETE FROM %s.cohort_sample_element WHERE cohort_sample_id = %d;",
+ source.getTableQualifier(SourceDaimon.DaimonType.Results),
+ sample.getId());
+ String translatedDeleteSql = SqlTranslate.translateSql(deleteSql, source.getSourceDialect(), null, null);
+ jdbcTemplate.update(translatedDeleteSql);
+ insertSampledElements(source, jdbcTemplate, sample.getId(), elements);
+ return null;
+ });
+ }
+
+ /** Convert a given sample with given elements to a DTO. */
+ private CohortSampleDTO sampleToSampleDTO(CohortSample sample, List elements, boolean includeIds) {
+ CohortSampleDTO sampleDTO = new CohortSampleDTO();
+ sampleDTO.setId(sample.getId());
+ sampleDTO.setName(sample.getName());
+ sampleDTO.setSize(sample.getSize());
+ if (includeIds) {
+ sampleDTO.setCohortDefinitionId(sample.getCohortDefinitionId());
+ sampleDTO.setSourceId(sample.getSourceId());
+ }
+ sampleDTO.setCreatedDate(sample.getCreatedDate());
+ UserEntity createdBy = sample.getCreatedBy();
+ if (createdBy != null) {
+ UserDTO userDto = new UserDTO();
+ userDto.setId(createdBy.getId());
+ userDto.setLogin(createdBy.getLogin());
+ userDto.setName(createdBy.getName());
+ sampleDTO.setCreatedBy(userDto);
+ }
+
+ SampleParametersDTO.AgeMode ageMode = SampleParametersDTO.AgeMode.fromSerialName(sample.getAgeMode());
+ if (ageMode != null) {
+ SampleParametersDTO.AgeDTO age = new SampleParametersDTO.AgeDTO();
+ age.setMode(ageMode);
+ switch (ageMode) {
+ case LESS_THAN:
+ case LESS_THAN_OR_EQUAL:
+ case EQUAL_TO:
+ age.setValue(sample.getAgeMax());
+ break;
+ case GREATER_THAN:
+ case GREATER_THAN_OR_EQUAL:
+ age.setValue(sample.getAgeMin());
+ break;
+ case BETWEEN:
+ case NOT_BETWEEN:
+ age.setMin(sample.getAgeMin());
+ age.setMax(sample.getAgeMax());
+ break;
+ }
+ sampleDTO.setAge(age);
+ }
+ if (sample.getGenderConceptIds() != null && !sample.getGenderConceptIds().isEmpty()) {
+ List conceptIds = Arrays.stream(sample.getGenderConceptIds().split(","))
+ .map(Integer::valueOf)
+ .collect(Collectors.toList());
+
+ SampleParametersDTO.GenderDTO genderDto = new SampleParametersDTO.GenderDTO();
+
+ if (conceptIds.remove(Integer.valueOf(-1))) {
+ genderDto.setOtherNonBinary(true);
+ }
+
+ genderDto.setConceptIds(conceptIds);
+ sampleDTO.setGender(genderDto);
+ }
+
+ sampleDTO.setElements(sampleElementToDTO(elements));
+ return sampleDTO;
+ }
+
+ /** Convert given sample elements DTOs. */
+ private List sampleElementToDTO(List elements) {
+ if (elements == null) {
+ return null;
+ }
+
+ return elements.stream()
+ .map(el -> {
+ SampleElementDTO elementDTO = new SampleElementDTO();
+ elementDTO.setRank(el.getRank());
+ elementDTO.setPersonId(String.valueOf(el.getPersonId()));
+ elementDTO.setAge(el.getAge());
+ elementDTO.setGenderConceptId(el.getGenderConceptId());
+ elementDTO.setRecordCount(el.getRecordCount());
+ return elementDTO;
+ })
+ .collect(Collectors.toList());
+ }
+
+ /** Insert elements that have been sampled. */
+ private void insertSampledElements(Source source, JdbcTemplate jdbcTemplate, int sampleId, List elements) {
+ if (elements.isEmpty()) {
+ return;
+ }
+
+ String[] parameters = new String[] { "results_schema" };
+ String[] parameterValues = new String[] { source.getTableQualifier(SourceDaimon.DaimonType.Results) };
+ String[] sqlParameters = new String[] { "cohortSampleId", "rank", "personId", "age", "genderConceptId" };
+
+ String statement = null;
+ List