Skip to content

Commit

Permalink
[ALS-7694] Add DashboardDrawer feature with controller, service, and …
Browse files Browse the repository at this point in the history
…repository (#55)

* Add Dashboard Drawer feature

- Introduce DashboardDrawerController for drawer-related endpoints
- Implement DashboardDrawerService to handle drawer logic
- Create DashboardDrawerRepository for database interactions
- Define DashboardDrawer and DashboardDrawerList records
- Add DashboardDrawerRowMapper for result set mapping
- Update DashboardRepository SQL to include dataset_id
- Modify application properties to include dashboard layout configuration

* Update application-bdc.properties with dashboard and filtering configs

- Added `dashboard.enable.bdc_hack` property
- Added `dashboard.layout.type` property
- Moved `filtering.unfilterable_concepts` property
- Ensured newline at end of file

* Add 'program_name' column to Dashboard repository

- Updated SQL query to include 'program_name' field.
- Joined 'dataset_meta' table for 'program_name' metadata.
- Added 'program_name' to the column list in DashboardService.

* Refactor service and controller to handle Optional returns

- Refactor `DashboardDrawerService` methods to return `Optional`
- Update controller methods to handle `Optional` results with appropriate HTTP responses
- Modify repository methods to return `Optional` for single item queries
- Ensure consistency and error handling improvements across the service and controller layers
  • Loading branch information
TDeSain authored Nov 20, 2024
1 parent 5487a7b commit 60d3904
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public List<Map<String, String>> getHackyBDCRows() {
String sql =
"""
SELECT
dataset.dataset_id as dataset_id,
dataset.abbreviation AS abbreviation,
dataset.full_name AS name,
CASE
Expand All @@ -70,10 +71,11 @@ public List<Map<String, String>> getHackyBDCRows() {
END
AS samples,
CASE
WHEN (consent.consent_code IS NOT NULL AND consent.consent_code != '') THEN concat(study_accession_meta.value, '.', consent.consent_code)
WHEN (consent.consent_code IS NOT NULL AND consent.consent_code != '') THEN concat(study_accession_meta.value, '.', consent.consent_code)
ELSE study_accession_meta.value
END
AS accession,
program_name.value as program_name,
study_focus_meta.value AS study_focus,
additional_info_meta.value AS additional_info_link
FROM
Expand All @@ -82,6 +84,7 @@ public List<Map<String, String>> getHackyBDCRows() {
LEFT JOIN dataset_meta AS study_focus_meta ON study_focus_meta.dataset_id = dataset.dataset_id AND study_focus_meta.KEY = 'study_focus'
LEFT JOIN dataset_meta AS study_accession_meta ON study_accession_meta.dataset_id = dataset.dataset_id AND study_accession_meta.KEY = 'study_accession'
LEFT JOIN dataset_meta AS additional_info_meta ON additional_info_meta.dataset_id = dataset.dataset_id AND additional_info_meta.KEY = 'study_link'
LEFT JOIN dataset_meta AS program_name ON program_name.dataset_id = dataset.dataset_id AND program_name.KEY = 'program_name'
WHERE dataset.dataset_id NOT IN (select dataset_id from dataset_meta where KEY = 'show_dashboad' and VALUE = 'false')
ORDER BY name ASC, abbreviation ASC
""";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public Dashboard getDashboard() {

private static final List<DashboardColumn> hackyBDCColumns = List.of(
new DashboardColumn("abbreviation", "Abbreviation"), new DashboardColumn("name", "Name"),
new DashboardColumn("study_focus", "Study Focus"), new DashboardColumn("clinvars", "Clinical Variables"),
new DashboardColumn("participants", "Participants"), new DashboardColumn("samples", "Samples Sequenced"),
new DashboardColumn("accession", "Accession"), new DashboardColumn("additional_info_link", "Study Link")
new DashboardColumn("study_focus", "Study Focus"), new DashboardColumn("program_name", "Program"),
new DashboardColumn("participants", "Participants"), new DashboardColumn("clinvars", "Clinical Variables"),
new DashboardColumn("samples", "Samples Sequenced"), new DashboardColumn("accession", "Accession"),
new DashboardColumn("additional_info_link", "Study Link")
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import java.util.List;

public record DashboardDrawer(
int datasetId, String studyFullname, String studyAbbreviation, List<String> consentGroups, String studySummary, List<String> studyFocus,
String studyDesign, String sponsor
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/dashboard-drawer")
public class DashboardDrawerController {

@Autowired
private DashboardDrawerService dashboardDrawerService;

@GetMapping
public ResponseEntity<DashboardDrawerList> findAll() {
return dashboardDrawerService.findAll().map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}

@GetMapping("/{id}")
public ResponseEntity<DashboardDrawer> findByDatasetId(@PathVariable Integer id) {
return dashboardDrawerService.findByDatasetId(id).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import java.util.List;

public record DashboardDrawerList(List<DashboardDrawer> dashboardDrawerList) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class DashboardDrawerRepository {

private final NamedParameterJdbcTemplate template;

private static final Logger log = LoggerFactory.getLogger(DashboardDrawerRepository.class);

@Autowired
public DashboardDrawerRepository(NamedParameterJdbcTemplate template) {
this.template = template;
}

public List<DashboardDrawer> getDashboardDrawerRows() {
String materializedViewSql = """
select * from dictionary_db.dict.dataset_meta_materialized_view dmmv;
""";

String fallbackSql = """
SELECT d.dataset_id,
MAX(d.full_name) study_fullname,
MAX(d.abbreviation) study_abbreviation,
ARRAY_AGG(DISTINCT c.description) consent_groups,
MAX(d.description) study_summary,
ARRAY_AGG(DISTINCT dm.value) FILTER (where dm.key IN ('study_focus')) study_focus,
MAX(DISTINCT dm.value) FILTER (where dm.key IN ('study_design')) study_design,
MAX(DISTINCT dm.value) FILTER (where dm.key IN ('sponsor')) sponsor
FROM dataset d
JOIN dataset_meta dm ON d.dataset_id = dm.dataset_id
JOIN consent c ON d.dataset_id = c.dataset_id
GROUP BY d.dataset_id
""";

try {
return template.query(materializedViewSql, new DashboardDrawerRowMapper());
} catch (Exception e) {
log.debug("Materialized view not available, using fallback query. Error: {}", e.getMessage());
return template.query(fallbackSql, new DashboardDrawerRowMapper());
}
}

public Optional<DashboardDrawer> getDashboardDrawerRows(Integer datasetId) {
String materializedViewSql = """
select * from dictionary_db.dict.dataset_meta_materialized_view dmmv where dmmv.dataset_id = :datasetId;
""";

String fallbackSql = """
SELECT d.dataset_id dataset_id,
MAX(d.full_name) study_fullname,
MAX(d.abbreviation) study_abbreviation,
ARRAY_AGG(DISTINCT c.description) consent_groups,
MAX(d.description) study_summary,
ARRAY_AGG(DISTINCT dm.value) FILTER (where dm.key IN ('study_focus')) study_focus,
MAX(DISTINCT dm.value) FILTER (where dm.key IN ('study_design')) study_design,
MAX(DISTINCT dm.value) FILTER (where dm.key IN ('sponsor')) sponsor
FROM dataset d
JOIN dataset_meta dm ON d.dataset_id = dm.dataset_id
JOIN consent c ON d.dataset_id = c.dataset_id
where d.dataset_id = :datasetId
GROUP BY d.dataset_id
""";
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("datasetId", datasetId);

try {
return template.query(materializedViewSql, params, new DashboardDrawerRowMapper()).stream().findFirst();
} catch (Exception e) {
log.debug("Materialized view not available, using fallback query. Error: {}", e.getMessage());
return template.query(fallbackSql, params, new DashboardDrawerRowMapper()).stream().findFirst();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Array; // For handling SQL Array
import java.util.Arrays;
import java.util.List;

public class DashboardDrawerRowMapper implements RowMapper<DashboardDrawer> {

@Override
public DashboardDrawer mapRow(ResultSet rs, int rowNum) throws SQLException {
return new DashboardDrawer(
rs.getInt("dataset_id"), rs.getString("study_fullname"), rs.getString("study_abbreviation"),
convertSqlArrayToList(rs.getArray("consent_groups")), rs.getString("study_summary"),
convertSqlArrayToList(rs.getArray("study_focus")), rs.getString("study_design"), rs.getString("sponsor")
);
}

private List<String> convertSqlArrayToList(Array sqlArray) throws SQLException {
if (sqlArray == null) {
return List.of();
} else {
Object[] arrayContents = (Object[]) sqlArray.getArray();
// Check if the array contains a single empty value
if (arrayContents.length == 1 && "".equals(arrayContents[0])) {
return List.of();
} else {
return Arrays.asList((String[]) sqlArray.getArray());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class DashboardDrawerService {

private final DashboardDrawerRepository repository;
private final String dashboardLayout;

@Autowired
public DashboardDrawerService(DashboardDrawerRepository repository, @Value("${dashboard.layout.type}") String dashboardLayout) {
this.repository = repository;
this.dashboardLayout = dashboardLayout;
}

/**
* Retrieves the Dashboard Drawer for all datasets.
*
* @return All Dashboard Instances and their metadata.
*/
public Optional<DashboardDrawerList> findAll() {
if (dashboardLayout.equalsIgnoreCase("bdc")) {
List<DashboardDrawer> records = repository.getDashboardDrawerRows();
return Optional.of(new DashboardDrawerList(records));
}

return Optional.of(new DashboardDrawerList(new ArrayList<>()));
}

/**
* Retrieves the Dashboard Drawer for a specific dataset.
*
*
* @param datasetId the ID of the dataset to fetch.
* @return a single Dashboard instance with drawer-specific metadata.
*/
public Optional<DashboardDrawer> findByDatasetId(Integer datasetId) {
if ("bdc".equalsIgnoreCase(dashboardLayout)) {
return repository.getDashboardDrawerRows(datasetId);
}
return Optional.empty();
}
}
5 changes: 4 additions & 1 deletion src/main/resources/application-bdc.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ spring.datasource.username=${DATASOURCE_USERNAME}
server.port=80

dashboard.enable.extra_details=true
dashboard.enable.bdc_hack=true
dashboard.layout.type=bdc

filtering.unfilterable_concepts=stigmatized

filtering.unfilterable_concepts=stigmatized
4 changes: 3 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST}:5432/${POSTGRES_DB}?cur
spring.datasource.username=${POSTGRES_USER}
spring.datasource.password=${POSTGRES_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver

server.port=80

dashboard.columns={abbreviation:'Abbreviation',name:'Name',clinvars:'Clinical Variables'}
dashboard.column-order=abbreviation,name,clinvars
dashboard.nonmeta-columns=abbreviation,name
dashboard.enable.extra_details=true
dashboard.enable.bdc_hack=true
dashboard.enable.bdc_hack=false
dashboard.layout.type=default

filtering.unfilterable_concepts=stigmatized
2 changes: 1 addition & 1 deletion src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ spring.datasource.driver-class-name=org.postgresql.Driver
dashboard.columns={abbreviation:'Abbreviation',melast:'This one goes last',name:'Name',clinvars:'Clinical Variables',participants:'Participants'}
dashboard.column-order=abbreviation,name,clinvars
dashboard.nonmeta-columns=abbreviation,name

dashboard.enable.extra_details=true
dashboard.enable.bdc_hack=false
dashboard.layout.type=default

filtering.unfilterable_concepts=stigmatized

0 comments on commit 60d3904

Please sign in to comment.