From d9740e27c47c54f9b3bd0138e7649af3ab113a95 Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Tue, 19 May 2026 15:25:05 +0100 Subject: [PATCH 1/8] CME-206: Implement DateRangeMetaDataCriterion and enhance parameter binding in Criterion classes --- .../data/casedetails/search/Criterion.java | 6 ++++ .../casedetails/search/CriterionFactory.java | 12 ++++--- .../search/DateRangeMetaDataCriterion.java | 32 +++++++++++++++++++ .../search/SearchQueryFactoryOperation.java | 2 +- .../data/casedetails/search/CriteraTest.java | 10 ++++++ .../search/CriteriaFactoryTest.java | 6 +++- .../SearchQueryFactoryOperationTest.java | 26 +++++++++++++++ 7 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/DateRangeMetaDataCriterion.java diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/Criterion.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/Criterion.java index 9c56ee0049..69507c385b 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/Criterion.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/Criterion.java @@ -1,5 +1,7 @@ package uk.gov.hmcts.ccd.data.casedetails.search; +import jakarta.persistence.Query; + public abstract class Criterion { protected static final String TOKEN_SEPARATOR = "."; @@ -29,6 +31,10 @@ public String buildParameterId() { public abstract String buildClauseString(String operation); + public void bindParameters(Query query) { + query.setParameter(buildParameterId(), getSoughtValue()); + } + protected String makeCaseInsensitive(String in) { return "TRIM( UPPER ( " + in + "))"; } diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/CriterionFactory.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/CriterionFactory.java index f6d613306e..039baf6be2 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/CriterionFactory.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/CriterionFactory.java @@ -2,6 +2,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -48,14 +49,13 @@ private List buildFromMetaData(MetaData metadata) { result.add(new MetaDataCriterion(CaseDetailsEntity.STATE_FIELD_COL, s))); ifPresentAndNotBlank(metadata.getCreatedDate(), cd -> - result.add(new MetaDataCriterion("date(" + CaseDetailsEntity.CREATED_DATE_FIELD_COL + ")", cd))); + result.add(buildDateRangeCriterion(CaseDetailsEntity.CREATED_DATE_FIELD_COL, cd))); ifPresentAndNotBlank(metadata.getLastModifiedDate(), lm -> - result.add(new MetaDataCriterion("date(" + CaseDetailsEntity.LAST_MODIFIED_FIELD_COL + ")", lm))); + result.add(buildDateRangeCriterion(CaseDetailsEntity.LAST_MODIFIED_FIELD_COL, lm))); ifPresentAndNotBlank(metadata.getLastStateModifiedDate(), lsm -> - result.add(new MetaDataCriterion( - "date(" + CaseDetailsEntity.LAST_STATE_MODIFIED_DATE_FIELD_COL + ")", lsm))); + result.add(buildDateRangeCriterion(CaseDetailsEntity.LAST_STATE_MODIFIED_DATE_FIELD_COL, lsm))); ifPresentAndNotBlank(metadata.getSecurityClassification(), sc -> result.add(new MetaDataCriterion( @@ -64,6 +64,10 @@ private List buildFromMetaData(MetaData metadata) { return result; } + private Criterion buildDateRangeCriterion(String field, String soughtValue) { + return new DateRangeMetaDataCriterion(field, LocalDate.parse(soughtValue)); + } + private void ifPresentAndNotBlank(Optional metadata, Consumer metadataConsumer) { metadata.ifPresent(m -> { if (isNotBlank(m)) { diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/DateRangeMetaDataCriterion.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/DateRangeMetaDataCriterion.java new file mode 100644 index 0000000000..77c6c9a50a --- /dev/null +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/DateRangeMetaDataCriterion.java @@ -0,0 +1,32 @@ +package uk.gov.hmcts.ccd.data.casedetails.search; + +import java.time.LocalDate; + +import jakarta.persistence.Query; + +public class DateRangeMetaDataCriterion extends MetaDataCriterion { + + private static final String FROM_SUFFIX = "_from"; + private static final String TO_SUFFIX = "_to"; + + private final LocalDate soughtDate; + + public DateRangeMetaDataCriterion(String field, LocalDate soughtDate) { + super(field, soughtDate.toString()); + this.soughtDate = soughtDate; + } + + @Override + public String buildClauseString(String operation) { + String parameterId = buildParameterId(); + return getField() + " >= " + PARAM_PREFIX + parameterId + FROM_SUFFIX + + " AND " + getField() + " < " + PARAM_PREFIX + parameterId + TO_SUFFIX; + } + + @Override + public void bindParameters(Query query) { + String parameterId = buildParameterId(); + query.setParameter(parameterId + FROM_SUFFIX, soughtDate.atStartOfDay()); + query.setParameter(parameterId + TO_SUFFIX, soughtDate.plusDays(1).atStartOfDay()); + } +} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java index fb7058b348..d55e12a42f 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java @@ -133,7 +133,7 @@ private String addUserCaseStateAccessClause(MetaData metadata, Map criteria) { - criteria.forEach(criterion -> query.setParameter(criterion.buildParameterId(), criterion.getSoughtValue())); + criteria.forEach(criterion -> criterion.bindParameters(query)); } private String toClauses(final List criteria) { diff --git a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteraTest.java b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteraTest.java index dd0a612b17..6c806d2600 100644 --- a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteraTest.java +++ b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteraTest.java @@ -1,5 +1,7 @@ package uk.gov.hmcts.ccd.data.casedetails.search; +import java.time.LocalDate; + import org.junit.jupiter.api.Test; import static org.junit.Assert.assertTrue; @@ -25,4 +27,12 @@ public void checkMetaDataCreationTestCriteraString() { assertTrue(subject.buildClauseString("AND").contains(META_DATA_1)); } + @Test + public void checkDateRangeMetaDataCreationTestCriteraString() { + DateRangeMetaDataCriterion subject = new DateRangeMetaDataCriterion("created_date", + LocalDate.parse("2020-09-12")); + assertTrue(subject.buildClauseString("AND").contains("created_date >= :created_date_from")); + assertTrue(subject.buildClauseString("AND").contains("created_date < :created_date_to")); + } + } diff --git a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteriaFactoryTest.java b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteriaFactoryTest.java index 886779b4c3..a5ccae6ceb 100644 --- a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteriaFactoryTest.java +++ b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/CriteriaFactoryTest.java @@ -83,7 +83,11 @@ public void checkLastStateModifiedDateMetaDataTest() { List result = subject.build(metaData, params); assertEquals(3, result.size()); - assertThat(result).filteredOn(m -> m.getField().equals("date(last_state_modified_date)")) + assertThat(result).filteredOn(DateRangeMetaDataCriterion.class::isInstance) + .hasSize(1) + .extracting(Criterion::getField) + .containsOnly("last_state_modified_date"); + assertThat(result).filteredOn(m -> m.getField().equals("last_state_modified_date")) .hasSize(1) .extracting(e -> e.getSoughtValue()) .containsOnly(LAST_STATE_MODIFIED_VALUE); diff --git a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java index 1fcab3e038..5422937bac 100644 --- a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java +++ b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java @@ -1,10 +1,14 @@ package uk.gov.hmcts.ccd.data.casedetails.search; +import static org.assertj.core.api.Assertions.assertThat; import com.google.common.collect.Maps; import java.io.IOException; +import java.time.LocalDateTime; import java.util.List; import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; +import org.mockito.ArgumentCaptor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -22,6 +26,7 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -139,4 +144,25 @@ void shouldNotCallRoleAssignmentServiceWhenRANotEnabled() { verify(userAuthorisation).getUserId(); verify(entityManager).createNativeQuery(anyString(), any(Class.class)); } + + @Test + void shouldBindDateMetadataAsTimestampRange() { + Query query = mock(Query.class); + when(applicationParam.getEnableAttributeBasedAccessControl()).thenReturn(false); + when(authorisedCaseDefinitionDataService.getUserAuthorisedCaseStateIds(anyString(), anyString(), any())) + .thenReturn(List.of("caseStateId_1")); + when(entityManager.createNativeQuery(anyString(), any(Class.class))).thenReturn(query); + + MetaData metadata = new MetaData(META_DATA_0_VALUE, META_DATA_1_VALUE); + metadata.setCreatedDate(java.util.Optional.of("2020-09-12")); + + classUnderTest.build(metadata, Maps.newHashMap(), false); + + ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(String.class); + verify(entityManager).createNativeQuery(queryCaptor.capture(), any(Class.class)); + assertThat(queryCaptor.getValue()).contains("created_date >= :created_date_from"); + assertThat(queryCaptor.getValue()).contains("created_date < :created_date_to"); + verify(query).setParameter("created_date_from", LocalDateTime.of(2020, 9, 12, 0, 0)); + verify(query).setParameter("created_date_to", LocalDateTime.of(2020, 9, 13, 0, 0)); + } } From f01149c073fcb1e30262bd35a2d50f3072ceacfd Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Tue, 19 May 2026 16:13:07 +0100 Subject: [PATCH 2/8] Add keepalive time configuration and disable open-in-view for JPA --- src/main/resources/application.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e6a04cd0d6..a262ffaaf9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -21,6 +21,8 @@ spring.datasource.hikari.connection-timeout=${DATA_STORE_DB_CONNECTION_TIMEOUT:4 spring.datasource.hikari.idle-timeout=${DATA_STORE_DB_IDLE_TIMEOUT:300000} spring.datasource.hikari.minimum-idle=${DATA_STORE_DB_MIN_IDLE:8} spring.datasource.hikari.maximum-pool-size=${DATA_STORE_DB_MAX_POOL_SIZE:16} +spring.datasource.hikari.keepalive-time=${DATA_STORE_DB_KEEPALIVE_TIME:30000} +spring.jpa.open-in-view=false # Disable feature detection to avoid the java.sql.SQLFeatureNotSupportedException # Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented. spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false From bdc5d431e1b71ca89197555b26829bf31c8f2d51 Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Wed, 20 May 2026 13:41:11 +0100 Subject: [PATCH 3/8] Refactor import statements in SearchQueryFactoryOperationTest for clarity --- .../casedetails/search/SearchQueryFactoryOperationTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java index 5422937bac..18dd6e6418 100644 --- a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java +++ b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java @@ -1,6 +1,5 @@ package uk.gov.hmcts.ccd.data.casedetails.search; -import static org.assertj.core.api.Assertions.assertThat; import com.google.common.collect.Maps; import java.io.IOException; import java.time.LocalDateTime; @@ -22,11 +21,11 @@ import uk.gov.hmcts.ccd.domain.service.security.AuthorisedCaseDefinitionDataService; import uk.gov.hmcts.ccd.infrastructure.user.UserAuthorisation; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; From 6c2ab391407851e4d70fde090bd93752cf6b672c Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Fri, 22 May 2026 12:28:44 +0100 Subject: [PATCH 4/8] Refactor query building in SearchQueryFactoryOperation and add SQL index migrations for case data metadata --- .../search/SearchQueryFactoryOperation.java | 13 ++++++++++--- ...206__CME-206_case_data_metadata_date_indexes.sql | 10 ++++++++++ .../search/SearchQueryFactoryOperationTest.java | 8 ++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java index d55e12a42f..f89bb9cc94 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperation.java @@ -76,9 +76,7 @@ public Optional build(MetaData metadata, Map params, bool return Optional.empty(); } - String sortClause = sortOrderQueryBuilder.buildSortOrderClause(metadata); - String queryToFormat = isCountQuery ? MAIN_COUNT_QUERY : MAIN_QUERY; - String queryString = String.format(queryToFormat, whereClausePart, sortClause); + String queryString = buildQueryString(isCountQuery, whereClausePart, metadata); Query query; if (isCountQuery) { @@ -136,6 +134,15 @@ private void addParameters(final Query query, List criteria) { criteria.forEach(criterion -> criterion.bindParameters(query)); } + private String buildQueryString(boolean isCountQuery, String whereClausePart, MetaData metadata) { + if (isCountQuery) { + return String.format(MAIN_COUNT_QUERY, whereClausePart); + } + + String sortClause = sortOrderQueryBuilder.buildSortOrderClause(metadata); + return String.format(MAIN_QUERY, whereClausePart, sortClause); + } + private String toClauses(final List criteria) { return criteria.stream() .map(criterion -> criterion.buildClauseString(getOperation())) diff --git a/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql b/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql new file mode 100644 index 0000000000..0deee75d04 --- /dev/null +++ b/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql @@ -0,0 +1,10 @@ +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_created_date + ON public.case_data USING btree (jurisdiction, case_type_id, created_date); + +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_last_modified + ON public.case_data USING btree (jurisdiction, case_type_id, last_modified) + WHERE last_modified IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_last_state_modified_date + ON public.case_data USING btree (jurisdiction, case_type_id, last_state_modified_date) + WHERE last_state_modified_date IS NOT NULL; diff --git a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java index 18dd6e6418..ccdbf730ad 100644 --- a/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java +++ b/src/test/java/uk/gov/hmcts/ccd/data/casedetails/search/SearchQueryFactoryOperationTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -91,8 +92,11 @@ void shouldUserCountWhenCountIsTrue() { classUnderTest.build(metadata, Maps.newHashMap(), true); - verify(sortOrderQueryBuilder).buildSortOrderClause(metadata); - verify(entityManager).createNativeQuery(anyString()); + ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(String.class); + verify(sortOrderQueryBuilder, never()).buildSortOrderClause(any(MetaData.class)); + verify(entityManager).createNativeQuery(queryCaptor.capture()); + assertThat(queryCaptor.getValue()).startsWith("SELECT count(*)"); + assertThat(queryCaptor.getValue()).doesNotContain("ORDER BY"); } @Test From c01de4d423dafc5ab895acd922dbe2a4c02f08c8 Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Fri, 22 May 2026 15:04:29 +0100 Subject: [PATCH 5/8] Remove keepalive time configuration from application.properties and add warning about Open Session in View --- src/main/resources/application.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a262ffaaf9..131d917bd2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -21,7 +21,8 @@ spring.datasource.hikari.connection-timeout=${DATA_STORE_DB_CONNECTION_TIMEOUT:4 spring.datasource.hikari.idle-timeout=${DATA_STORE_DB_IDLE_TIMEOUT:300000} spring.datasource.hikari.minimum-idle=${DATA_STORE_DB_MIN_IDLE:8} spring.datasource.hikari.maximum-pool-size=${DATA_STORE_DB_MAX_POOL_SIZE:16} -spring.datasource.hikari.keepalive-time=${DATA_STORE_DB_KEEPALIVE_TIME:30000} +# WARNING: disabling Open Session in View means lazy JPA associations must be loaded/mapped inside service or +# repository transactions. Accessing lazy associations during response serialization can cause LazyInitializationException. spring.jpa.open-in-view=false # Disable feature detection to avoid the java.sql.SQLFeatureNotSupportedException # Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented. From 8fa4f6c3edc9a628bb6c626ed90ea7cb7f2d39ae Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Fri, 22 May 2026 16:50:29 +0100 Subject: [PATCH 6/8] Update V20260522_0206__CME-206_case_data_metadata_date_indexes.sql --- ...6__CME-206_case_data_metadata_date_indexes.sql | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql b/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql index 0deee75d04..e133dff656 100644 --- a/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql +++ b/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql @@ -1,10 +1,13 @@ -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_created_date - ON public.case_data USING btree (jurisdiction, case_type_id, created_date); +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_created_date + ON public.case_data USING btree (jurisdiction, case_type_id, state, created_date); -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_last_modified - ON public.case_data USING btree (jurisdiction, case_type_id, last_modified) +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_last_modified + ON public.case_data USING btree (jurisdiction, case_type_id, state, last_modified) WHERE last_modified IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_last_state_modified_date - ON public.case_data USING btree (jurisdiction, case_type_id, last_state_modified_date) +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_last_state_modified_date + ON public.case_data USING btree (jurisdiction, case_type_id, state, last_state_modified_date) WHERE last_state_modified_date IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_event_case_data_id_created_date + ON public.case_event USING btree (case_data_id, created_date DESC); From 939252b2d9a2cee7a11116a02161a601599f0291 Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Fri, 22 May 2026 16:51:50 +0100 Subject: [PATCH 7/8] Delete V20260522_0206__CME-206_case_data_metadata_date_indexes.sql --- ...206__CME-206_case_data_metadata_date_indexes.sql | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql diff --git a/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql b/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql deleted file mode 100644 index e133dff656..0000000000 --- a/src/main/resources/db/migration/V20260522_0206__CME-206_case_data_metadata_date_indexes.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_created_date - ON public.case_data USING btree (jurisdiction, case_type_id, state, created_date); - -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_last_modified - ON public.case_data USING btree (jurisdiction, case_type_id, state, last_modified) - WHERE last_modified IS NOT NULL; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_data_jur_case_type_state_last_state_modified_date - ON public.case_data USING btree (jurisdiction, case_type_id, state, last_state_modified_date) - WHERE last_state_modified_date IS NOT NULL; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_case_event_case_data_id_created_date - ON public.case_event USING btree (case_data_id, created_date DESC); From 976650c539fc66ca53421c3d89fb139c1bd6f9c0 Mon Sep 17 00:00:00 2001 From: Antony Leons Date: Tue, 26 May 2026 11:21:45 +0100 Subject: [PATCH 8/8] Optimize audit event query by limiting results to the latest entry --- .../gov/hmcts/ccd/data/casedetails/CaseAuditEventEntity.java | 4 +--- .../hmcts/ccd/data/casedetails/CaseAuditEventRepository.java | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventEntity.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventEntity.java index 59ae3158fe..fb99706226 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventEntity.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventEntity.java @@ -33,9 +33,7 @@ ), @NamedQuery(name = CaseAuditEventEntity.FIND_CREATE_EVENT, query = FIND_BY_CASE_DATA_ID_HQL - + " AND cae.createdDate = " - + "(select min(caeDate.createdDate) from CaseAuditEventEntity caeDate WHERE caeDate.caseDataId = :" - + CaseAuditEventEntity.CASE_DATA_ID + ")" + + " ORDER BY cae.createdDate ASC" ), @NamedQuery(name = CaseAuditEventEntity.FIND_BY_ID, query = FIND_BY_ID_HQL diff --git a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventRepository.java b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventRepository.java index 902dbd0df5..b8ecfee07e 100644 --- a/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventRepository.java +++ b/src/main/java/uk/gov/hmcts/ccd/data/casedetails/CaseAuditEventRepository.java @@ -55,6 +55,7 @@ public Optional getCreateEvent(CaseDetails caseDetails) { final Query query = em.createNamedQuery(CaseAuditEventEntity.FIND_CREATE_EVENT); query.setParameter(CaseAuditEventEntity.CASE_DATA_ID, Long.valueOf(caseDetails.getId())); + query.setMaxResults(1); List auditEvents = query.getResultList(); return (auditEvents == null || auditEvents.size() == 0)