JdbcEventStore implements EventStore { @Override public List<EventRow> getEventRows( EventSearchParams params, List<OrganisationUnit> organisationUnits ) { User user = currentUserService.getCurrentUser(); setAccessiblePrograms( user, params ); List<EventRow> eventRows = new ArrayList<>(); String sql = buildSql( params, organisationUnits, user ); SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql ); log.debug( "Event query SQL: " + sql ); EventRow eventRow = new EventRow(); eventRow.setEvent( "not_valid" ); Set<String> notes = new HashSet<>(); Map<String, List<DataValue>> processedDataValues = new HashMap<>(); while ( rowSet.next() ) { if ( rowSet.getString( "psi_uid" ) == null || ( params.getCategoryOptionCombo() == null && !isSuper( user ) && !userHasAccess( rowSet ) ) ) { continue; } if ( eventRow.getUid() == null || !eventRow.getUid().equals( rowSet.getString( "psi_uid" ) ) ) { validateIdentifiersPresence( rowSet, params.getIdSchemes(), false ); eventRow = new EventRow(); eventRow.setUid( rowSet.getString( "psi_uid" ) ); eventRow.setEvent( rowSet.getString( "psi_uid" ) ); eventRow.setTrackedEntityInstance( rowSet.getString( "tei_uid" ) ); eventRow.setTrackedEntityInstanceOrgUnit( rowSet.getString( "tei_ou" ) ); eventRow.setTrackedEntityInstanceOrgUnitName( rowSet.getString( "tei_ou_name" ) ); eventRow.setTrackedEntityInstanceCreated( rowSet.getString( "tei_created" ) ); eventRow.setTrackedEntityInstanceInactive( rowSet.getBoolean( "tei_inactive" ) ); eventRow.setDeleted( rowSet.getBoolean( "psi_deleted" ) ); eventRow.setProgram( rowSet.getString( "p_identifier" ) ); eventRow.setProgramStage( rowSet.getString( "ps_identifier" ) ); eventRow.setOrgUnit( rowSet.getString( "ou_identifier" ) ); ProgramType programType = ProgramType.fromValue( rowSet.getString( "p_type" ) ); if ( programType == ProgramType.WITHOUT_REGISTRATION ) { eventRow.setEnrollment( rowSet.getString( "pi_uid" ) ); eventRow.setFollowup( rowSet.getBoolean( "pi_followup" ) ); } eventRow.setTrackedEntityInstance( rowSet.getString( "tei_uid" ) ); eventRow.setOrgUnitName( rowSet.getString( "ou_name" ) ); eventRow.setDueDate( DateUtils.getIso8601NoTz( rowSet.getDate( "psi_duedate" ) ) ); eventRow.setEventDate( DateUtils.getIso8601NoTz( rowSet.getDate( "psi_executiondate" ) ) ); eventRows.add( eventRow ); } if ( rowSet.getString( "pav_value" ) != null && rowSet.getString( "ta_uid" ) != null ) { String valueType = rowSet.getString( "ta_valuetype" ); Attribute attribute = new Attribute(); attribute.setCreated( DateUtils.getIso8601NoTz( rowSet.getDate( "pav_created" ) ) ); attribute.setLastUpdated( DateUtils.getIso8601NoTz( rowSet.getDate( "pav_lastupdated" ) ) ); attribute.setValue( rowSet.getString( "pav_value" ) ); attribute.setDisplayName( rowSet.getString( "ta_name" ) ); attribute.setValueType( valueType != null ? ValueType.valueOf( valueType.toUpperCase() ) : null ); attribute.setAttribute( rowSet.getString( "ta_uid" ) ); eventRow.getAttributes().add( attribute ); } if ( !org.springframework.util.StringUtils.isEmpty( rowSet.getString( "psi_eventdatavalues" ) ) && !processedDataValues.containsKey( rowSet.getString( "psi_uid" ) ) ) { List<DataValue> dataValues = new ArrayList<>(); Set<EventDataValue> eventDataValues = convertEventDataValueJsonIntoSet( rowSet.getString( "psi_eventdatavalues" ) ); for ( EventDataValue dv : eventDataValues ) { dataValues.add( convertEventDataValueIntoDtoDataValue( dv ) ); } processedDataValues.put( rowSet.getString( "psi_uid" ), dataValues ); } if ( rowSet.getString( "psinote_value" ) != null && !notes.contains( rowSet.getString( "psinote_id" ) ) ) { Note note = new Note(); note.setNote( rowSet.getString( "psinote_uid" ) ); note.setValue( rowSet.getString( "psinote_value" ) ); note.setStoredDate( DateUtils.getIso8601NoTz( rowSet.getDate( "psinote_storeddate" ) ) ); note.setStoredBy( rowSet.getString( "psinote_storedby" ) ); eventRow.getNotes().add( note ); notes.add( rowSet.getString( "psinote_id" ) ); } } eventRows.forEach( e -> e.setDataValues( processedDataValues.get( e.getUid() ) ) ); IdSchemes idSchemes = ObjectUtils.firstNonNull( params.getIdSchemes(), new IdSchemes() ); IdScheme dataElementIdScheme = idSchemes.getDataElementIdScheme(); if ( dataElementIdScheme != IdScheme.ID && dataElementIdScheme != IdScheme.UID ) { CachingMap<String, String> dataElementUidToIdentifierCache = new CachingMap<>(); List<Collection<DataValue>> dataValuesList = eventRows.stream().map( EventRow::getDataValues ) .collect( Collectors.toList() ); populateCache( dataElementIdScheme, dataValuesList, dataElementUidToIdentifierCache ); convertDataValuesIdentifiers( dataElementIdScheme, dataValuesList, dataElementUidToIdentifierCache ); } return eventRows; } JdbcEventStore( StatementBuilder statementBuilder, JdbcTemplate jdbcTemplate,
        @Qualifier( "dataValueJsonMapper" ) ObjectMapper jsonMapper,
        CurrentUserService currentUserService, IdentifiableObjectManager identifiableObjectManager, Environment env ); @Override List<Event> getEvents( EventSearchParams params, List<OrganisationUnit> organisationUnits,
        Map<String, Set<String>> psdesWithSkipSyncTrue ); List<ProgramStageInstance> saveEvents(List<ProgramStageInstance> events ); @Override List<ProgramStageInstance> updateEvents(List<ProgramStageInstance> programStageInstances ); @Override List<Map<String, String>> getEventsGrid( EventSearchParams params, List<OrganisationUnit> organisationUnits ); @Override List<EventRow> getEventRows( EventSearchParams params, List<OrganisationUnit> organisationUnits ); @Override int getEventCount( EventSearchParams params, List<OrganisationUnit> organisationUnits ); void updateTrackedEntityInstances( List<String> teiUids, User user ); void delete( final List<Event> events );  }
@Test public void verifyEventDataValuesAreProcessedOnceForEachPSI() { mockRowSet(); EventSearchParams eventSearchParams = new EventSearchParams(); List<EventRow> rows = subject.getEventRows( eventSearchParams, new ArrayList<>() ); assertThat( rows, hasSize( 1 ) ); verify( rowSet, times( 4 ) ).getString( "psi_eventdatavalues" ); }