Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ALS-7694] Add DashboardDrawer feature with controller, service, and repository #55

Merged
merged 7 commits into from
Nov 20, 2024

Conversation

TDeSain
Copy link

@TDeSain TDeSain commented Nov 18, 2024

Introduce DashboardDrawerController, DashboardDrawerService, and DashboardDrawerRepository classes for dashboard drawer functionality. Include methods to fetch drawer data for datasets using materialized views.

@TDeSain TDeSain self-assigned this Nov 18, 2024
@TDeSain TDeSain added the enhancement New feature or request label Nov 18, 2024
@JamesPeck JamesPeck changed the title Add DashboardDrawer feature with controller, service, and repository [ALS-7694] Add DashboardDrawer feature with controller, service, and repository Nov 19, 2024
- 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
- Added `dashboard.enable.bdc_hack` property
- Added `dashboard.layout.type` property
- Moved `filtering.unfilterable_concepts` property
- Ensured newline at end of file
- Added `dashboard.enable.bdc_hack` property
- Added `dashboard.layout.type` property
- Moved `filtering.unfilterable_concepts` property
- Ensured newline at end of file
@@ -52,6 +52,7 @@ public List<Map<String, String>> getHackyBDCRows() {
String sql =
"""
SELECT
dataset.dataset_id as dataset_id,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use the dataset table's primary key the return object to make downstream processes more efficient

}

public List<DashboardDrawer> getDashboardDrawerRows() {
String materializedViewSql = """
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Materialized views are pretty powerful tools. I am not in love with how Postgres handles them as you have to build logic to use them unlike Oracles Query Rewrite abilities.

https://docs.oracle.com/cd/B10501_01/server.920/a96520/qr.htm

This query is not expensive so I am not worried about needing this unless we scale number of studies and retrieved metadata. Can remove materialized view logic if needed.

Would make the query much more dynamic / possibly stored procedure. Aggregation gets expensive.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's talk about this in OH. I clearly don't use views often enough and I want to learn more about them from you.

}
}

public List<DashboardDrawer> getDashboardDrawerRows(Integer datasetId) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as other query but this will find a specific record based on the datasetId

import java.util.List;

public class DashboardDrawerRowMapper implements RowMapper<DashboardDrawer> {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would at least make an abstract class for this that I could extend to fulfill multiple Dashboard Layouts.

Should probably do this for other Classes such as Dashboard.

} else {
Object[] arrayContents = (Object[]) sqlArray.getArray();
// Check if the array contains a single empty value
if (arrayContents.length == 1 && "".equals(arrayContents[0])) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit hacky but sqlArray returns an single empty value for empty values in the db. Which makes sense as empty values can have meaning. For this component they do not.

src/main/resources/application-bdc.properties Show resolved Hide resolved
@@ -0,0 +1,24 @@
package edu.harvard.dbmi.avillach.dictionary.dashboarddrawer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between edu.harvard.dbmi.avillach.dictionary.dashboarddrawer and edu.harvard.dbmi.avillach.dictionary.dashboard as far as business purpose goes? Are these legitimately different domains, or is this a BDC specific implementation of the same domain?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I was in the same boat at the beginning and was trying to fit it into to the Dashboard thus why it was basically a replication of it until changed the class names.

I think I should follow up on this ticket with Cleaning up some of the dashboard method and looking at how this integrates with the dashboard more closely.

From more of a backend mindset I think it should relate to a dataset endpoint and not a feature endpoint.


@GetMapping("/{id}")
public ResponseEntity<DashboardDrawer> findByDatasetId(@PathVariable Integer id) {
return ResponseEntity.ok(dashboardDrawerService.findByDatasetId(id));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should 404 if the dataset DNE. You can do this cleanly by expressing the nullable DashboardDrawer as an Optional<DashboardDrawer> and then mapping that to a response entity here.


import java.util.List;

public record DashboardDrawerList(List<DashboardDrawer> dashboardDrawerList) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made yourself a note to get rid of this record and just return a list. I agree with that note.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a comment that DashboardDrawerRecord was redundant as it's already a record.

DashboardDrawerList should be a list of DashboardDrawer as that is the collection type of this record class.

DashboardDrawer is just a record.

}

public List<DashboardDrawer> getDashboardDrawerRows() {
String materializedViewSql = """
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's talk about this in OH. I clearly don't use views often enough and I want to learn more about them from you.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we make it so this view always exists?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://www.postgresql.org/docs/current/rules-materializedviews.html

Materialized views are a bit different then views. As in they are stored on disk ( in memory on some DBMS ). They are basically a point in time view of a table. But they need to be managed and refreshed.

Have not use Postgres in my checkered past but they were a Saint when it came to Oracle. Oracle has query rewrite which makes it much easier to manage. From what I see so far in Postgres we will need to write logic blocks like this or queries will fail if Materialized view is being rewritten.

Query rewrite would fall back on the select statement used to create the materialized view if the view doesn't exist or is being refreshed.

}
}

public List<DashboardDrawer> getDashboardDrawerRows(Integer datasetId) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is selecting a specific dataset ID. Why return a list when it's always either 1 or 0 elements?

}
}

return new DashboardDrawer(-1, "", "", new ArrayList<>(), "", new ArrayList<>(), "", "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this zero value, and I want to understand more about the API requirements justify this.

src/main/resources/application-bdc.properties Show resolved Hide resolved
- 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 `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
@TDeSain TDeSain merged commit 60d3904 into release Nov 20, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants