Skip to content

Fix: slow consultation pages#66

Open
LiamStanziani wants to merge 14 commits intoMagentaHealth:release/2026-01-19from
openo-beta:bug/slow-consult-pages
Open

Fix: slow consultation pages#66
LiamStanziani wants to merge 14 commits intoMagentaHealth:release/2026-01-19from
openo-beta:bug/slow-consult-pages

Conversation

@LiamStanziani
Copy link
Copy Markdown
Collaborator

@LiamStanziani LiamStanziani commented Jan 26, 2026

Please run these indexes as well:

  • CREATE INDEX IF NOT EXISTS idx_consult_status_referaldate ON consultationRequests (status, referalDate);
  • CREATE INDEX IF NOT EXISTS idx_consult_sendto_status_referaldate ON consultationRequests (sendTo, status, referalDate);
  • CREATE INDEX IF NOT EXISTS idx_consult_providerno_status_referaldate ON consultationRequests (providerNo, status, referalDate);
  • CREATE INDEX IF NOT EXISTS idx_consult_status_appointmentdate ON consultationRequests (status, appointmentDate);
  • CREATE INDEX IF NOT EXISTS idx_consult_demographicno ON consultationRequests (demographicNo);
  • CREATE INDEX IF NOT EXISTS idx_consult_serviceid ON consultationRequests (serviceId);
  • CREATE INDEX IF NOT EXISTS idx_consult_specid ON consultationRequests (specId);
  • CREATE INDEX IF NOT EXISTS idx_consult_lastupdatedate ON consultationRequests (lastUpdateDate);

In this PR, I have fixed:

  • Slow consultation pages
    • Fixed using DTO projection, and leveraging smaller datasets when applicable (avoid pulling all data into DB calls to reduce DB hits overall), as well as adding a migration script for indexing to the DB, and adding batch fetching to related entity classes
  • Additional upgrades
    • catching exceptions, nulls, etc, handling them
    • Encoding sanitation and more explanatory logging

I have tested these by:

  • Displaying, creating constulations, using the multitude of consultation pages for verification, matching with the hotfix branch behaviour

Summary by Sourcery

Optimize consultation request listing and form loading for performance and robustness by introducing DTO-based queries, batch-loading related data and extensions, and adding targeted database indexes.

Enhancements:

  • Replace N+1 consultation listing logic with JPQL constructor projections (ConsultationListDTO) and batch-loaded extensions for team and demographic views.
  • Refine consultation request DAO queries to use parameterized JPQL with centralized sorting logic and efficient joins to demographics, providers, services, and specialists.
  • Add lightweight service description and active-service summary retrieval methods to avoid loading full ConsultationServices entities and their collections.
  • Batch-load fax jobs and normalize specialist fax handling when building fax logs, reducing per-row lookups and null-handling issues.
  • Improve handling of specialist contact details and letterhead metadata in consultation form utilities, including safer numeric parsing and extension loading.
  • Annotate ConsultationRequest relationships with fetch and batch-size hints to reduce excessive eager loading.
  • Refactor HRM document attachment retrieval to load only attached documents directly instead of filtering a full HRM list.

Build:

  • Add a migration script that creates targeted indexes on consultationRequests to speed up common filters on status, team, provider, dates, demographic, service, specialist, and update time.

Documentation:

  • Introduce JavaDoc and inline documentation for new DTOs, DAO methods, and utilities describing performance rationale and query behavior.

@LiamStanziani LiamStanziani self-assigned this Jan 26, 2026
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Jan 26, 2026

Reviewer's Guide

Refactors consultation request listing and form utilities to use DTO-based JPQL projections, batched loading of extensions, and new DAO methods while adding targeted database indexes and query hints to significantly improve consultation page performance and robustness.

Sequence diagram for consultation list loading with DTO and batched extensions

sequenceDiagram
    actor User
    participant JSP as ConsultationListJSP
    participant Util as EctViewConsultationRequestsUtil
    participant CRDao as ConsultationRequestDao
    participant CRDaoImpl as ConsultationRequestDaoImpl
    participant DB as Database

    User->>JSP: Request consultation list page
    JSP->>Util: estConsultationVecByTeam(loggedInInfo, team,...)
    Util->>CRDao: getConsultationDTOs(team, showCompleted, startDate, endDate, orderby, desc, searchDate, offset, limit)
    activate CRDao
    CRDao->>CRDaoImpl: getConsultationDTOs(...)
    activate CRDaoImpl

    note over CRDaoImpl: Build JPQL DTO_SELECT + DTO_FROM + filters
    CRDaoImpl->>DB: JPQL query
        Note right of DB: Single constructor projection
        Note right of DB: LEFT JOIN Demographic, Provider, ConsultationServices, ProfessionalSpecialist
    DB-->>CRDaoImpl: List<ConsultationListDTO>

    note over CRDaoImpl: loadExtensionsForDTOs(dtos)
    CRDaoImpl->>DB: SELECT e FROM ConsultationRequestExt e WHERE e.requestId IN (:ids)
    DB-->>CRDaoImpl: List<ConsultationRequestExt>
    note over CRDaoImpl: Group by requestId and dto.applyExtensions(extMap)

    CRDaoImpl-->>CRDao: List<ConsultationListDTO>
    deactivate CRDaoImpl
    CRDao-->>Util: List<ConsultationListDTO>
    deactivate CRDao

    note over Util: initLists()
    note over Util: For each dto, populate parallel lists
    Util-->>JSP: Populated lists (ids, status, patient, ...)
    JSP-->>User: Rendered consultation list page
Loading

ER diagram for consultationRequests and new performance indexes

erDiagram
    consultationRequests {
        int id PK
        varchar status
        int demographicNo FK
        varchar providerNo FK
        varchar sendTo
        int serviceId FK
        int specId FK
        date referalDate
        date appointmentDate
        date followUpDate
        datetime lastUpdateDate
        %% Indexed columns
        %% idx_consult_status_referaldate (status, referalDate)
        %% idx_consult_sendto_status_referaldate (sendTo, status, referalDate)
        %% idx_consult_providerno_status_referaldate (providerNo, status, referalDate)
        %% idx_consult_status_appointmentdate (status, appointmentDate)
        %% idx_consult_demographicno (demographicNo)
        %% idx_consult_serviceid (serviceId)
        %% idx_consult_specid (specId)
        %% idx_consult_lastupdatedate (lastUpdateDate)
    }

    Demographic {
        int DemographicNo PK
        varchar LastName
        varchar FirstName
        varchar ProviderNo FK
    }

    Provider {
        varchar ProviderNo PK
        varchar LastName
        varchar FirstName
    }

    ConsultationServices {
        int serviceId PK
        varchar serviceDesc
    }

    ProfessionalSpecialist {
        int specId PK
        varchar firstName
        varchar lastName
    }

    ConsultationRequestExt {
        int id PK
        int requestId FK
        varchar key
        varchar value
    }

    %% Relationships used by DTO and optimized queries
    consultationRequests ||--o{ ConsultationRequestExt : has
    consultationRequests }o--|| Demographic : demographicNo
    consultationRequests }o--|| Provider : providerNo
    Demographic }o--|| Provider : mrpProvider
    consultationRequests }o--|| ConsultationServices : serviceId
    consultationRequests }o--|| ProfessionalSpecialist : specId
Loading

Updated class diagram for consultation request DTOs, DAOs, and utilities

classDiagram
    class EctViewConsultationRequestsUtil {
        List~String~ ids
        List~String~ status
        List~String~ patient
        List~String~ provider
        List~String~ teams
        List~String~ service
        List~String~ vSpecialist
        List~String~ date
        List~String~ demographicNo
        List~String~ apptDate
        List~String~ patientWillBook
        List~String~ urgency
        List~String~ followUpDate
        List~String~ providerNo
        List~String~ siteName
        List~Provider~ consultProvider
        List~Boolean~ eReferral
        +boolean estConsultationVecByTeam(loggedInInfo, team)
        +boolean estConsultationVecByTeam(loggedInInfo, team, showCompleted)
        +boolean estConsultationVecByTeam(loggedInInfo, team, showCompleted, startDate, endDate)
        +boolean estConsultationVecByTeam(loggedInInfo, team, showCompleted, startDate, endDate, orderby)
        +boolean estConsultationVecByTeam(loggedInInfo, team, showCompleted, startDate, endDate, orderby, desc)
        +boolean estConsultationVecByTeam(loggedInInfo, team, showCompleted, startDate, endDate, orderby, desc, searchDate, offset, limit)
        +boolean estConsultationVecByDemographic(loggedInInfo, demoNo)
        -Provider buildConsultProvider(dto)
        -boolean isBlank(value)
        -void initLists()
    }

    class ConsultationRequestDao {
        +List~ConsultationRequest~ getConsults(team, showCompleted, startDate, endDate, orderby, desc, searchDate, offset, limit)
        +List~ConsultationRequest~ getConsults(demoNo)
        +List~ConsultationListDTO~ getConsultationDTOs(team, showCompleted, startDate, endDate, orderby, desc, searchDate, offset, limit)
        +List~ConsultationListDTO~ getConsultationDTOsByDemographic(demoNo)
    }

    class ConsultationRequestDaoImpl {
        -static String DTO_SELECT
        -static String DTO_FROM
        +List~ConsultationListDTO~ getConsultationDTOs(team, showCompleted, startDate, endDate, orderby, desc, searchDate, offset, limit)
        +List~ConsultationListDTO~ getConsultationDTOsByDemographic(demoNo)
        -String buildConsultationDTOQuery(paramList, team, showCompleted, startDate, endDate, orderby, desc, searchDate)
        -void loadExtensionsForDTOs(dtos)
    }

    class ConsultationListDTO {
        -static long serialVersionUID
        -static String NOT_APPLICABLE
        -Integer id
        -String status
        -String urgency
        -Integer demographicNo
        -String demographicLastName
        -String demographicFirstName
        -String demographicProviderNo
        -String mrpLastName
        -String mrpFirstName
        -String consultProviderNo
        -String consultProviderLastName
        -String consultProviderFirstName
        -Integer serviceId
        -String serviceDescription
        -String specialistLastName
        -String specialistFirstName
        -Date referralDate
        -Date appointmentDate
        -Date appointmentTime
        -boolean patientWillBook
        -Date followUpDate
        -String sendTo
        -String siteName
        -boolean eReferral
        -String ereferralService
        -String ereferralDoctor
        +ConsultationListDTO()
        +ConsultationListDTO(id, status, urgency, demographicNo, demographicLastName, demographicFirstName, demographicProviderNo, mrpLastName, mrpFirstName, consultProviderNo, consultProviderLastName, consultProviderFirstName, serviceId, serviceDescription, specialistLastName, specialistFirstName, referralDate, appointmentDate, appointmentTime, patientWillBook, followUpDate, sendTo, siteName)
        +String getPatientFormattedName()
        +String getMrpFormattedName()
        +String getConsultProviderFormattedName()
        +String getSpecialistFormattedName()
        +String getEffectiveServiceDescription()
        +String getReferralDateFormatted()
        +String getAppointmentDateFormatted()
        +String getFollowUpDateFormatted()
        +void applyExtensions(extMap)
        +Integer getId()
        +String getStatus()
        +String getUrgency()
        +Integer getDemographicNo()
        +String getDemographicProviderNo()
        +String getConsultProviderNo()
        +String getConsultProviderLastName()
        +String getConsultProviderFirstName()
        +Integer getServiceId()
        +String getServiceDescription()
        +Date getReferralDate()
        +Date getAppointmentDate()
        +Date getAppointmentTime()
        +boolean isPatientWillBook()
        +Date getFollowUpDate()
        +String getSendTo()
        +String getSiteName()
        +boolean isEReferral()
    }

    class ConsultationRequest {
        +Integer id
        +String status
        +Integer demographicId
        +Integer serviceId
        +Integer specId
        +String providerNo
        +Date referralDate
        +Date appointmentDate
        +Date appointmentTime
        +Date followUpDate
        +String sendTo
        +String siteName
        +boolean patientWillBook
        +Date lastUpdateDate
        +ProfessionalSpecialist professionalSpecialist
        +DemographicContact demographicContact
        +LookupListItem lookupListItem
    }

    class ProfessionalSpecialist {
        +Integer specId
        +String firstName
        +String lastName
        +String phoneNumber
        +String faxNumber
        +String streetAddress
        +String emailAddress
    }

    class DemographicContact {
        +Integer id
    }

    class LookupListItem {
        +String value
    }

    class ConsultationServiceDao {
        +ConsultationServices find(serviceId)
        +ConsultationServices findByDescription(description)
        +ConsultationServices findReferringDoctorService(activeOnly)
        +String getServiceDescription(serviceId)
        +List~ConsultationServiceDto~ findActiveServiceSummaries()
    }

    class ConsultationServiceDaoImpl {
        +List~ConsultationServiceDto~ findActiveServiceSummaries()
        +String getServiceDescription(serviceId)
    }

    class ConsultationServiceDto {
        +Integer serviceId
        +String serviceDesc
    }

    class FaxJobDao {
        +List~FaxJob~ getFaxStatusByDateDemographicProviderStatusTeam(demographicNo, providerNo, status, team, startDate, endDate)
        +List~FaxJob~ getInprogressFaxesByJobId()
        +List~FaxJob~ findByIds(ids)
    }

    class FaxJobDaoImpl {
        +List~FaxJob~ findByIds(ids)
    }

    class FaxJob {
        +Integer id
    }

    class EctConsultationFormRequestUtil {
        -ProfessionalSpecialist professionalSpecialist
        -String specPhone
        -String specFax
        -String specAddr
        -String specEmail
        -boolean isEReferral
        +boolean estPatient(loggedInInfo, demographicNo)
        +boolean estRequestFromId(loggedInInfo, id)
        -void getFaxLogs(requestId)
        +String getServiceName(id)
    }

    class ConsultationRequestExt {
        +Integer id
        +Integer requestId
        +String key
        +String value
    }

    %% Relationships
    ConsultationRequestDaoImpl ..|> ConsultationRequestDao
    ConsultationRequestDaoImpl --> ConsultationListDTO
    ConsultationRequestDaoImpl --> ConsultationRequestExt
    ConsultationRequestDaoImpl --> ConsultationRequest

    EctViewConsultationRequestsUtil --> ConsultationRequestDao
    EctViewConsultationRequestsUtil --> ConsultationListDTO
    EctViewConsultationRequestsUtil --> Provider

    ConsultationRequest --> ProfessionalSpecialist
    ConsultationRequest --> DemographicContact
    ConsultationRequest --> LookupListItem

    ConsultationServiceDaoImpl ..|> ConsultationServiceDao
    ConsultationServiceDaoImpl --> ConsultationServices
    ConsultationServiceDaoImpl --> ConsultationServiceDto

    FaxJobDaoImpl ..|> FaxJobDao
    EctConsultationFormRequestUtil --> ConsultationRequestDao
    EctConsultationFormRequestUtil --> ConsultationRequestExt
    EctConsultationFormRequestUtil --> FaxJobDao
    EctConsultationFormRequestUtil --> FaxJob
    EctConsultationFormRequestUtil --> ProfessionalSpecialist
Loading

File-Level Changes

Change Details Files
Replace N+1 consultation listing logic with DTO-based DAO queries and centralized list initialization.
  • EctViewConsultationRequestsUtil now delegates list loading to ConsultationRequestDao#getConsultationDTOs and #getConsultationDTOsByDemographic, iterating over ConsultationListDTOs instead of entities plus multiple DAOs
  • Introduces helper methods to initialize all parallel JSP backing lists, build Provider objects from DTO consulting provider data, and handle blank provider numbers
  • Improves Javadoc and overload chaining for estConsultationVecByTeam and estConsultationVecByDemographic, and standardizes error logging on invalid input or DAO failures
src/main/java/ca/openosp/openo/encounter/oscarConsultationRequest/pageUtil/EctViewConsultationRequestsUtil.java
Add ConsultationListDTO projection and new DAO methods to fetch consultations and extensions efficiently.
  • Adds ConsultationListDTO class with constructor-compatible fields, formatting helpers, and applyExtensions to incorporate ConsultationRequestExt data
  • Extends ConsultationRequestDao with getConsultationDTOs and getConsultationDTOsByDemographic signatures returning ConsultationListDTOs
  • Implements DTO_SELECT/DTO_FROM JPQL fragments and buildConsultationDTOQuery in ConsultationRequestDaoImpl to build parameterized JPQL queries with LEFT JOINs, sorting, and pagination, replacing string-concatenated SQL
  • Adds loadExtensionsForDTOs to batch-load ConsultationRequestExt rows via IN(:ids), group them, and apply to DTOs
src/main/java/ca/openosp/openo/consultation/dto/ConsultationListDTO.java
src/main/java/ca/openosp/openo/commn/dao/ConsultationRequestDao.java
src/main/java/ca/openosp/openo/commn/dao/ConsultationRequestDaoImpl.java
Optimize consultation form utilities for robustness and fewer database round-trips.
  • EctConsultationFormRequestUtil.estPatient and estRequestFromId now validate numeric parameters and log on NumberFormatException instead of throwing
  • In estRequestFromId, caches all ConsultationRequestExt rows for a request into a map and reuses it for letterheadTitle and eReferral detection, and fully initializes specialist contact fields with null-safe defaults
  • Reworks getFaxLogs to batch-load FaxJobs via new FaxJobDao.findByIds, normalize specialist fax once, and reuse it when constructing FaxRecipient logs
  • Simplifies getServiceName to use ConsultationServiceDao.getServiceDescription and handle invalid IDs gracefully
src/main/java/ca/openosp/openo/encounter/oscarConsultationRequest/pageUtil/EctConsultationFormRequestUtil.java
Extend service and fax DAOs with lightweight read APIs used by the UI utilities.
  • ConsultationServiceDao gains getServiceDescription and findActiveServiceSummaries, with ConsultationServiceDaoImpl implementing them via JPQL projections avoiding loading full entities and collections
  • ConsultationLookup2Action.getServices now calls consultationServiceDao.findActiveServiceSummaries directly instead of materializing ConsultationServices then mapping to DTOs
  • FaxJobDao gains findByIds, implemented in FaxJobDaoImpl as a single IN(:ids) query with empty-input guard
src/main/java/ca/openosp/openo/commn/dao/ConsultationServiceDao.java
src/main/java/ca/openosp/openo/commn/dao/ConsultationServiceDaoImpl.java
src/main/java/ca/openosp/openo/encounter/oscarConsultationRequest/config/pageUtil/ConsultationLookup2Action.java
src/main/java/ca/openosp/openo/commn/dao/FaxJobDao.java
src/main/java/ca/openosp/openo/commn/dao/FaxJobDaoImpl.java
Tune ORM mappings on ConsultationRequest to reduce join/graph loading overhead.
  • Adds Hibernate @fetch(FetchMode.SELECT) and @batchsize(size = 25) to professionalSpecialist, demographicContact, and lookupListItem associations to favor batched SELECTs over large join graphs
  • Leaves existing EAGER fetch type but improves performance when many ConsultationRequest rows are loaded
src/main/java/ca/openosp/openo/commn/model/ConsultationRequest.java
Improve HRM document attachment lookup to avoid full-list scans.
  • ConsultationManagerImpl.getAttachedHRMDocuments now calls HRMUtil.getHRMDocumentById per attached ConsultDocs entry and maps to a minimal id/name structure, with warning logs on failures, instead of loading and filtering the entire HRM document list
src/main/java/ca/openosp/openo/managers/ConsultationManagerImpl.java
Add database indexes to accelerate common consultationRequests query patterns.
  • Introduces migration script creating composite indexes for (status, referalDate), (sendTo, status, referalDate), (providerNo, status, referalDate), and (status, appointmentDate) to align with listing filters and sort orders
  • Adds single-column indexes on demographicNo, serviceId, specId, and lastUpdateDate to speed up demographic lookups, FK joins, and update-time-based queries
  • Aligns with PR description requesting these indexes to be applied in production
database/mysql/updates/update-2026-01-26-consultation-indexes.sql

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@LiamStanziani LiamStanziani marked this pull request as ready for review January 26, 2026 21:38
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The new @Fetch(FetchMode.SELECT) annotations on eagerly loaded associations may still cause N+1 query patterns; consider switching these relationships to LAZY where possible and explicitly fetching them in the queries that need them.
  • The migration script uses CREATE INDEX IF NOT EXISTS, which is only supported in newer MySQL versions; verify that all supported environments run a compatible version or adjust the script to be backward compatible.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `@Fetch(FetchMode.SELECT)` annotations on eagerly loaded associations may still cause N+1 query patterns; consider switching these relationships to `LAZY` where possible and explicitly fetching them in the queries that need them.
- The migration script uses `CREATE INDEX IF NOT EXISTS`, which is only supported in newer MySQL versions; verify that all supported environments run a compatible version or adjust the script to be backward compatible.

## Individual Comments

### Comment 1
<location> `database/mysql/updates/update-2026-01-26-consultation-indexes.sql:5` </location>
<code_context>
+-- Addresses slow consultation page load times by optimizing common query patterns
+
+-- Index for status + referral date filtering (common filter pattern)
+CREATE INDEX IF NOT EXISTS idx_consult_status_referaldate ON consultationRequests (status, referalDate);
+
+-- Index for team-based queries with status and date filtering (main team listing query)
</code_context>

<issue_to_address>
**issue (bug_risk):** MySQL does not support `CREATE INDEX IF NOT EXISTS`, which will cause this migration to fail.

These statements will raise a syntax error on MySQL. If this migration must support MySQL, remove `IF NOT EXISTS` and either rely on the migration framework’s one-time execution guarantees or add a separate, framework-compatible existence check (e.g., via `information_schema`) before creating the index.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

LiamStanziani commented Jan 27, 2026

Depending on if the tickler issue is still happening on prod, I might need to change the solution, and create a new solution for the tickler updates, will set to draft until further investigation is conducted on the state of that in prod

@LiamStanziani LiamStanziani marked this pull request as draft January 27, 2026 18:02
@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

LiamStanziani commented Feb 2, 2026

I am going to revisit this after I fix up the meds disappearing issue, I think the main problem is probably:

  • No batch fetching (added in this branch)
  • N+1 query problem (fixed in ticklers in a recent PR, but could be the issue here, would need to check JavaMelody for info)

@LiamStanziani LiamStanziani changed the title Fix: slow consult pages Fix: slow consultation pages Feb 3, 2026
…tch case instead of if else for performance, remove space seperator from date time string
…void potential NullPointerExceptions, add NumberFormatException handling inside of EctConsultationFormRequestUtil and ctViewConsultationRequestsUtil, prevent stale professionalSpecialist values by clearing contact fields if request is null, restore legacy date time matching, sanitize field before audit logging, added javadoc to FaxJobDao and FaxJobDaoImpl new methods
…rvices entities and their EAGER specialist collections
…alize blank providerNo's to ensure rows load correctly with privacy filters, return null provider to avoid outputting null provider name, populate all parallel lists in ectConsultationVecByDemographic to preven IndexOutOfBounds Exception, replace hardcoded extension keys for enum refs, add extra context to error log messages, return default sorting by ascending
@LiamStanziani LiamStanziani force-pushed the bug/slow-consult-pages branch from 8d71af4 to 0eba7d2 Compare February 4, 2026 18:59
@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

Force pushed to amend commit message with some fixes to a typo, and one missing fix explanation to it

@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

This PR is looking good at this point, I will see if there are any last AI comments with this PR through sourcery and then it will be ready for review

@LiamStanziani LiamStanziani marked this pull request as ready for review February 4, 2026 19:02
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • In ConsultationRequestDaoImpl, DTO_SELECT/DTO_FROM and buildConsultationDTOQuery are built with table/column-style identifiers (e.g., Demographic d, d.DemographicNo, ON clauses) but are executed via createQuery as JPQL; this will not parse as JPQL, so either switch to createNativeQuery with proper result mapping or refactor the query to valid JPQL using entity field names and join syntax.
  • The Javadoc for ConsultationRequestDao#getConsultationDTOsByDemographic states results are ordered by referral date descending, but the implementation in ConsultationRequestDaoImpl uses ORDER BY cr.referralDate ASC; align the ordering with the documented behavior or update the Javadoc to avoid surprises.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In ConsultationRequestDaoImpl, DTO_SELECT/DTO_FROM and buildConsultationDTOQuery are built with table/column-style identifiers (e.g., Demographic d, d.DemographicNo, ON clauses) but are executed via createQuery as JPQL; this will not parse as JPQL, so either switch to createNativeQuery with proper result mapping or refactor the query to valid JPQL using entity field names and join syntax.
- The Javadoc for ConsultationRequestDao#getConsultationDTOsByDemographic states results are ordered by referral date descending, but the implementation in ConsultationRequestDaoImpl uses ORDER BY cr.referralDate ASC; align the ordering with the documented behavior or update the Javadoc to avoid surprises.

## Individual Comments

### Comment 1
<location> `src/main/java/ca/openosp/openo/commn/dao/ConsultationRequestDaoImpl.java:110-119` </location>
<code_context>
             }
         }

-        String orderDesc = desc != null && desc.equals("1") ? "DESC" : "";
-        String service = ", service.serviceDesc";
         if (orderby == null) {
</code_context>

<issue_to_address>
**issue (bug_risk):** ORDER BY clauses reference JPQL fields with database-style casing, which likely do not match entity property names.

In `buildConsultationDTOQuery`, the `orderby` switch uses `d.LastName`, `mrp.LastName`, and `svc.serviceDesc`. JPQL is case-sensitive and requires entity property names (e.g. `d.lastName`), not column names. Update these ORDER BY expressions to use the correct entity properties, consistent with other JPQL in the project, to avoid query failures.
</issue_to_address>

### Comment 2
<location> `src/main/java/ca/openosp/openo/commn/dao/ConsultationRequestDaoImpl.java:279-280` </location>
<code_context>
+     */
+    @Override
+    public List<ConsultationListDTO> getConsultationDTOsByDemographic(Integer demoNo) {
+        String sql = DTO_SELECT + DTO_FROM +
+                "WHERE cr.demographicId = ?1 " +
+                "ORDER BY cr.referralDate ASC";
+
</code_context>

<issue_to_address>
**issue (bug_risk):** Method-level documentation promises descending order but the implementation orders by referral date ascending.

The Javadoc for `getConsultationDTOsByDemographic` specifies "referral date descending", but the query uses `ORDER BY cr.referralDate ASC`. Please align the query and documentation so callers get the expected sort order.
</issue_to_address>

### Comment 3
<location> `database/mysql/updates/update-2026-01-26-consultation-indexes.sql:5` </location>
<code_context>
+-- Addresses slow consultation page load times by optimizing common query patterns
+
+-- Index for status + referral date filtering (common filter pattern)
+CREATE INDEX IF NOT EXISTS idx_consult_status_referaldate ON consultationRequests (status, referalDate);
+
+-- Index for team-based queries with status and date filtering (main team listing query)
</code_context>

<issue_to_address>
**issue (bug_risk):** Index definition appears to use a misspelled column name (`referalDate`) which may not match the actual schema.

The entity and queries use `referralDate`, but this index targets `referalDate`. If the actual column is `referralDate`, this migration will fail at deploy. Please confirm the correct column name and align both the index name and column reference accordingly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

Ready for review @lacarmen

TIcket link for manual testing: openo-beta#2099

@LiamStanziani
Copy link
Copy Markdown
Collaborator Author

@lacarmen

Deval has reviewed this PR, see this comment from the other PR (openo-beta#2264)

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant