diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java new file mode 100644 index 000000000..b08ea9ad8 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java @@ -0,0 +1,118 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import cwms.cda.data.dao.JooqDao; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import org.jetbrains.annotations.NotNull; +import org.jooq.Condition; +import org.jooq.DSLContext; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.impl.DSL; + +import usace.cwms.db.jooq.codegen.packages.CWMS_TS_PROFILE_PACKAGE; +import usace.cwms.db.jooq.codegen.udt.records.STR_TAB_T; +import usace.cwms.db.jooq.codegen.udt.records.TS_PROFILE_T; + +import static usace.cwms.db.jooq.codegen.tables.AV_TS_PROFILE.AV_TS_PROFILE; + +public class TimeSeriesProfileDao extends JooqDao { + public TimeSeriesProfileDao(DSLContext dsl) { + super(dsl); + } + + public void storeTimeSeriesProfile(TimeSeriesProfile timeSeriesProfile, boolean failIfExists) { + + connection(dsl, conn -> { + List parameterList = timeSeriesProfile.getParameterList(); + StringBuilder parameterString = new StringBuilder(parameterList.get(0)); + + for (int i = 1; i < parameterList.size(); i++) { + parameterString.append(",").append(parameterList.get(i)); + } + String referenceTsId = null; + if (timeSeriesProfile.getReferenceTsId() != null) { + referenceTsId = timeSeriesProfile.getReferenceTsId().getName(); + } + CWMS_TS_PROFILE_PACKAGE.call_STORE_TS_PROFILE(DSL.using(conn).configuration(), timeSeriesProfile.getLocationId().getName(), + timeSeriesProfile.getKeyParameter(), + parameterString.toString(), + timeSeriesProfile.getDescription(), referenceTsId, failIfExists?"T":"F", "T", timeSeriesProfile.getLocationId().getOfficeId()); + }); + } + + public TimeSeriesProfile retrieveTimeSeriesProfile(String locationId, String parameterId, String officeId) { + return connectionResult(dsl, conn -> { + TS_PROFILE_T timeSeriesProfile = CWMS_TS_PROFILE_PACKAGE.call_RETRIEVE_TS_PROFILE( + DSL.using(conn).configuration(), locationId, parameterId, officeId); + return map(timeSeriesProfile, locationId, parameterId, officeId); + }); + } + + public void deleteTimeSeriesProfile(String locationId, String keyParameter, String officeId) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_DELETE_TS_PROFILE(DSL.using(conn).configuration(), locationId, keyParameter, "DELETE ALL", + officeId)); + } + + public void copyTimeSeriesProfile(String locationId, String keyParameter, String destinationLocation, String destRefTsId, String officeId) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_COPY_TS_PROFILE(DSL.using(conn).configuration(), locationId, keyParameter, destinationLocation, + destRefTsId, "F", "F", + officeId)); + } + public List catalogTimeSeriesProfiles(String locationIdMask, String parameterIdMask, String officeIdMask) { + List timeSeriesProfileList = new ArrayList<>(); + + Condition whereCondition = JooqDao.caseInsensitiveLikeRegexNullTrue(AV_TS_PROFILE.LOCATION_ID, locationIdMask); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE.OFFICE_ID, officeIdMask)); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE.KEY_PARAMETER_ID, parameterIdMask)); + + @NotNull Result timeSeriesProfileResults = dsl.select(DSL.asterisk()).from(AV_TS_PROFILE) + .where(whereCondition) + .fetch(); + for (Record timeSeriesProfileResult : timeSeriesProfileResults) { + String parameters = timeSeriesProfileResult.get("PARAMETERS", String.class); + String[] parameterArray = parameters.split(","); + List parameterList = Arrays.asList(parameterArray); + + CwmsId locationId = new CwmsId.Builder() + .withName((String) timeSeriesProfileResult.get("LOCATION_ID")) + .withOfficeId((String) timeSeriesProfileResult.get("OFFICE_ID")) + .build(); + CwmsId referenceTsId = new CwmsId.Builder() + .withName((String) timeSeriesProfileResult.get("ELEV_TS_ID")) + .withOfficeId((String) timeSeriesProfileResult.get("OFFICE_ID")) + .build(); + timeSeriesProfileList.add(new TimeSeriesProfile.Builder() + .withDescription((String) timeSeriesProfileResult.get("DESCRIPTION")) + .withReferenceTsId(referenceTsId) + .withKeyParameter((String) timeSeriesProfileResult.get("KEY_PARAMETER_ID")) + .withLocationId(locationId) + .withParameterList(parameterList) + .build()); + } + return timeSeriesProfileList; + } + + private TimeSeriesProfile map(TS_PROFILE_T timeSeriesProfile, String locationName, String keyParameter, String officeId) { + STR_TAB_T profileParams = timeSeriesProfile.getPROFILE_PARAMS(); + List parameterList = new ArrayList<>(profileParams); + CwmsId locationId = new CwmsId.Builder().withName(locationName).withOfficeId(officeId).build(); + CwmsId referenceTsId = null; + if (timeSeriesProfile.getREFERENCE_TS_ID() != null) { + referenceTsId = new CwmsId.Builder().withName(timeSeriesProfile.getREFERENCE_TS_ID()).withOfficeId(officeId).build(); + } + return new TimeSeriesProfile.Builder() + .withLocationId(locationId) + .withDescription(timeSeriesProfile.getDESCRIPTION()) + .withReferenceTsId(referenceTsId) + .withKeyParameter(keyParameter) + .withParameterList(parameterList) + .build(); + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDao.java new file mode 100644 index 000000000..adaa24328 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDao.java @@ -0,0 +1,317 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import cwms.cda.data.dao.JooqDao; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.ProfileTimeSeries; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileInstance; +import cwms.cda.data.dto.timeseriesprofile.TimeValuePair; +import org.jetbrains.annotations.NotNull; +import org.jooq.Condition; +import org.jooq.Configuration; +import org.jooq.DSLContext; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.impl.DSL; +import usace.cwms.db.jooq.codegen.packages.CWMS_LOC_PACKAGE; +import usace.cwms.db.jooq.codegen.packages.CWMS_TS_PROFILE_PACKAGE; +import usace.cwms.db.jooq.codegen.packages.CWMS_UTIL_PACKAGE; +import usace.cwms.db.jooq.codegen.tables.AV_TS_PROFILE_INST; +import usace.cwms.db.jooq.codegen.udt.records.PVQ_T; +import usace.cwms.db.jooq.codegen.udt.records.PVQ_TAB_T; +import usace.cwms.db.jooq.codegen.udt.records.STR_TAB_T; +import usace.cwms.db.jooq.codegen.udt.records.TS_PROF_DATA_REC_T; +import usace.cwms.db.jooq.codegen.udt.records.TS_PROF_DATA_T; +import usace.cwms.db.jooq.codegen.udt.records.TS_PROF_DATA_TAB_T; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TimeSeriesProfileInstanceDao extends JooqDao +{ + public TimeSeriesProfileInstanceDao(DSLContext dsl) + { + super(dsl); + } + + void storeTimeSeriesProfileInstance(TimeSeriesProfile timeSeriesProfile, String profileData, Instant versionDate, + String versionId, String storeRule, boolean overrideProtection) + { + connection(dsl, conn -> CWMS_TS_PROFILE_PACKAGE.call_STORE_TS_PROFILE_INSTANCE__2(DSL.using(conn).configuration(), + timeSeriesProfile.getLocationId().getName(), + timeSeriesProfile.getKeyParameter(), + profileData, + versionId, + storeRule, + overrideProtection?"T":"F", + versionDate!=null?Timestamp.from(versionDate):null, + timeSeriesProfile.getLocationId().getOfficeId())); + } + + void storeTimeSeriesProfileInstance(TimeSeriesProfileInstance timeseriesProfileInstance, String versionId, Instant versionInstant, String storeRule,String overrideProtection) + { + connection(dsl, conn -> { + BigDecimal locationCodeId = CWMS_LOC_PACKAGE.call_GET_LOCATION_CODE(DSL.using(conn).configuration(), + timeseriesProfileInstance.getTimeSeriesProfile().getLocationId().getOfficeId(), + timeseriesProfileInstance.getTimeSeriesProfile().getLocationId().getName()); + + + Map parameterIdToCode = new HashMap<>(); + + String parameter = timeseriesProfileInstance.getTimeSeriesProfile().getKeyParameter(); + BigDecimal parameterCodeDec = CWMS_UTIL_PACKAGE.call_GET_PARAMETER_CODE(DSL.using(conn).configuration(), parameter, + timeseriesProfileInstance.getTimeSeriesProfile().getLocationId().getOfficeId()); + parameterIdToCode.put(parameter, parameterCodeDec.toBigInteger()); + + List timeSeriesList = timeseriesProfileInstance.getTimeSeriesList(); + for(ProfileTimeSeries profileTimeSeries : timeSeriesList) + { + parameter = profileTimeSeries.getParameter(); + parameterCodeDec = CWMS_UTIL_PACKAGE.call_GET_PARAMETER_CODE(DSL.using(conn).configuration(), parameter, + timeseriesProfileInstance.getTimeSeriesProfile().getLocationId().getOfficeId()); + parameterIdToCode.put(parameter, parameterCodeDec.toBigInteger()); + } + + TS_PROF_DATA_T tsProfileData = new TS_PROF_DATA_T(); + tsProfileData.attach(DSL.using(conn).configuration()); + + TS_PROF_DATA_TAB_T records = new TS_PROF_DATA_TAB_T(); + + for(int i=0; i catalogTimeSeriesProfileInstances( String officeIdMask, String locationIdMask, String parameterIdMask, String versionMask) + { + List timeSeriesProfileInstanceList = new ArrayList<>(); + + Condition whereCondition = JooqDao.caseInsensitiveLikeRegexNullTrue(AV_TS_PROFILE_INST.AV_TS_PROFILE_INST.LOCATION_ID, locationIdMask); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_INST.AV_TS_PROFILE_INST.OFFICE_ID, officeIdMask)); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_INST.AV_TS_PROFILE_INST.KEY_PARAMETER_ID, parameterIdMask)); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_INST.AV_TS_PROFILE_INST.VERSION_ID, versionMask)); + + @NotNull Result timeSeriesProfileInstanceResults = dsl.select(DSL.asterisk()).from(AV_TS_PROFILE_INST.AV_TS_PROFILE_INST) + .where(whereCondition) + .fetch(); + for (Record result : timeSeriesProfileInstanceResults) { + CwmsId locationId = new CwmsId.Builder() + .withOfficeId(result.get("OFFICE_ID",String.class)) + .withName(result.get("LOCATION_ID", String.class)) + .build(); + String parameterId = result.get("KEY_PARAMETER_ID", String.class); + TimeSeriesProfile timeSeriesProfile = new TimeSeriesProfile.Builder() + .withLocationId(locationId) + .withKeyParameter(parameterId) + .build(); + TimeSeriesProfileInstance timeSeriesProfileInstance = new TimeSeriesProfileInstance.Builder() + .withTimeSeriesProfile(timeSeriesProfile) + .withVersion(result.get("VERSION_ID", String.class)) + .withVersionDate(result.get("VERSION_DATE", Instant.class)) + .withFirstDate(result.get("FIRST_DATE_TIME", Instant.class)) + .withLastDate(result.get("LAST_DATE_TIME", Instant.class)) + .build(); + + timeSeriesProfileInstanceList.add(timeSeriesProfileInstance); + } + return timeSeriesProfileInstanceList; + } + + TimeSeriesProfileInstance retrieveTimeSeriesProfileInstance(CwmsId location, String keyParameter, + String version, + String unit, + Instant startTime, + Instant endTime, + String timeZone, + String startInclusive, + String endInclusive, + String previous, + String next, + Instant versionDate, + String maxVersion) + { + return connectionResult(dsl, conn -> { + TS_PROF_DATA_T timeSeriesProfileData; + timeSeriesProfileData = CWMS_TS_PROFILE_PACKAGE.call_RETRIEVE_TS_PROFILE_DATA( + DSL.using(conn).configuration(), + location.getName(), + keyParameter, + version, + unit, + Timestamp.from(startTime), + Timestamp.from(endTime), + timeZone, + startInclusive, + endInclusive, + previous, + next, + versionDate!=null?Timestamp.from(versionDate):null, + maxVersion, + location.getOfficeId() + ); + + return map(DSL.using(conn).configuration(), location.getOfficeId(), timeSeriesProfileData, version, versionDate); + }); + } + void deleteTimeSeriesProfileInstance(CwmsId location, String keyParameter, + String version, Instant firstDate, String timeZone,boolean overrideProtection, Instant versionDate) + { + connection(dsl, conn -> { + + Timestamp versionTimestamp = null; + if(versionDate!=null) + { + versionTimestamp = Timestamp.from(versionDate); + } + + CWMS_TS_PROFILE_PACKAGE.call_DELETE_TS_PROFILE_INSTANCE( + DSL.using(conn).configuration(), + location.getName(), + keyParameter, + version, + Timestamp.from(firstDate), + timeZone, + overrideProtection?"T":"F", + versionTimestamp, + location.getOfficeId() + ); + + }); + } + + + private TimeSeriesProfileInstance map(@NotNull Configuration configuration, String officeId, TS_PROF_DATA_T timeSeriesProfileData, String version, Instant versionDate) { + String timeZone = timeSeriesProfileData.getTIME_ZONE(); + STR_TAB_T units = timeSeriesProfileData.getUNITS(); + TS_PROF_DATA_TAB_T records = timeSeriesProfileData.getRECORDS(); + BigInteger locationCode = timeSeriesProfileData.getLOCATION_CODE(); + String location = CWMS_UTIL_PACKAGE.call_GET_LOCATION_ID(configuration, locationCode, officeId); + BigInteger keyParameterCode = timeSeriesProfileData.getKEY_PARAMETER(); + String keyParameter = CWMS_UTIL_PACKAGE.call_GET_PARAMETER_ID(configuration, keyParameterCode); + List timeList = new ArrayList<>(); + List> valuesList = new ArrayList<>(); + List> qualitiesList = new ArrayList<>(); + List> parametersList = new ArrayList<>(); + for(TS_PROF_DATA_REC_T dataRecord : records) + { + Instant dateTime = dataRecord.get(0, Instant.class); + timeList.add(dateTime); + PVQ_TAB_T parameters = dataRecord.getPARAMETERS(); + List valueList = new ArrayList<>(); + List qualityList = new ArrayList<>(); + List parameterList = new ArrayList<>(); + for(PVQ_T parameter : parameters) + { + valueList.add(parameter.getVALUE()); + qualityList.add(parameter.getQUALITY_CODE().intValue()); + parameterList.add(parameter.getPARAMETER_CODE()); + } + valuesList.add(valueList); + parametersList.add(parameterList); + qualitiesList.add(qualityList); + } + List parameterList = new ArrayList<>(); + List> timeValuePairList = new ArrayList<>(); + if(!parametersList.isEmpty()) { + for (int i = 0; i < parametersList.get(0).size(); i++) { + String parameter = CWMS_UTIL_PACKAGE.call_GET_PARAMETER_ID(configuration, parametersList.get(0).get(i)); + parameterList.add(parameter); + timeValuePairList.add(new ArrayList<>()); + } + } + if(!valuesList.isEmpty()) + { + for(int i = 0; i timeSeriesList = new ArrayList<>(); + if(!timeValuePairList.isEmpty()) { + for (int i = 0; i < timeValuePairList.size(); i++) { + ProfileTimeSeries timeSeries = new ProfileTimeSeries.Builder() + .withValues(timeValuePairList.get(i)) + .withTimeZone(timeZone) + .withParameter(parameterList.get(i)) + .withUnit(units.get(i)) + .build(); + timeSeriesList.add(timeSeries); + } + } + CwmsId locationId = new CwmsId.Builder() + .withOfficeId(officeId) + .withName(location) + .build(); + TimeSeriesProfile timeSeriesProfile = new TimeSeriesProfile.Builder() + .withKeyParameter(keyParameter) + .withLocationId(locationId) + .withParameterList(parameterList) + .build(); + return new TimeSeriesProfileInstance.Builder() + .withTimeSeriesProfile(timeSeriesProfile) + .withTimeSeriesList(timeSeriesList) + .withVersion(version) + .withVersionDate(versionDate) + .build(); + } +} \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDao.java new file mode 100644 index 000000000..3bc04145d --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDao.java @@ -0,0 +1,278 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.util.ArrayList; +import java.util.List; + +import cwms.cda.data.dao.JooqDao; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfo; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfoColumnar; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfoIndexed; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParser; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParserColumnar; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParserIndexed; +import org.jetbrains.annotations.NotNull; +import org.jooq.Condition; +import org.jooq.DSLContext; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.impl.DSL; + +import usace.cwms.db.jooq.codegen.packages.CWMS_TS_PROFILE_PACKAGE; +import usace.cwms.db.jooq.codegen.packages.cwms_ts_profile.RETRIEVE_TS_PROFILE_PARSER; +import usace.cwms.db.jooq.codegen.tables.AV_TS_PROFILE_PARSER; +import usace.cwms.db.jooq.codegen.tables.AV_TS_PROFILE_PARSER_PARAM; + + +public class TimeSeriesProfileParserDao extends JooqDao { + private static final String PARAMETER_ID = "PARAMETER_ID"; + private static final String KEY_PARAMETER_ID = "KEY_PARAMTER_ID"; + private static final String TIME_FORMAT = "TIME_FORMAT"; + private static final String TIME_ZONE = "TIME_ZONE"; + public TimeSeriesProfileParserDao(DSLContext dsl) { + super(dsl); + } + + private List getParameterInfoList(String info, String recordDelimiter, String fieldDelimiter) { + List parameterInfoList = new ArrayList<>(); + String[] records = info.split(recordDelimiter); + for (String aRecord : records) { + String[] fields = aRecord.split(fieldDelimiter); + int index = Integer.parseInt(fields[2]); + ParameterInfo parameterInfo = new ParameterInfoIndexed.Builder().withIndex(index) + .withParameter(fields[0]) + .withUnit(fields[1]) + .build(); + parameterInfoList.add(parameterInfo); + } + return parameterInfoList; + } + + private String getParameterInfoString(TimeSeriesProfileParser timeSeriesProfileParser) { + List parameterInfo = timeSeriesProfileParser.getParameterInfoList(); + + StringBuilder parameterInfoBuilder = new StringBuilder(); + parameterInfoBuilder.append(parameterInfo.get(0).getParameterInfoString()); + + for (int i = 1; i < parameterInfo.size(); i++) { + parameterInfoBuilder.append(timeSeriesProfileParser.getRecordDelimiter()) + .append(parameterInfo.get(i).getParameterInfoString()); + } + return parameterInfoBuilder.toString(); + } + + public void storeTimeSeriesProfileParser(TimeSeriesProfileParserIndexed timeSeriesProfileParser, boolean failIfExists) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_STORE_TS_PROFILE_PARSER(DSL.using(conn).configuration(), timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), String.valueOf(timeSeriesProfileParser.getRecordDelimiter()), + String.valueOf(timeSeriesProfileParser.getFieldDelimiter()), timeSeriesProfileParser.getTimeField(), + null, null, timeSeriesProfileParser.getTimeFormat(), + timeSeriesProfileParser.getTimeZone(), getParameterInfoString(timeSeriesProfileParser), + timeSeriesProfileParser.getTimeInTwoFields() ? "T" : "F", + failIfExists ? "T" : "F", "T", timeSeriesProfileParser.getLocationId().getOfficeId()) + ); + } + + public void storeTimeSeriesProfileParser(TimeSeriesProfileParserColumnar timeSeriesProfileParser, boolean failIfExists) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_STORE_TS_PROFILE_PARSER(DSL.using(conn).configuration(), timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), String.valueOf(timeSeriesProfileParser.getRecordDelimiter()), + null, null, + timeSeriesProfileParser.getTimeStartColumn(), timeSeriesProfileParser.getTimeEndColumn(), timeSeriesProfileParser.getTimeFormat(), + timeSeriesProfileParser.getTimeZone(), getParameterInfoString(timeSeriesProfileParser), + timeSeriesProfileParser.getTimeInTwoFields() ? "T" : "F", + failIfExists ? "T" : "F", "F", timeSeriesProfileParser.getLocationId().getOfficeId()) + ); + } + + public TimeSeriesProfileParser retrieveTimeSeriesProfileParser(String locationId, String parameterId, String officeId) { + return connectionResult(dsl, conn -> { + RETRIEVE_TS_PROFILE_PARSER timeSeriesProfileParser = CWMS_TS_PROFILE_PACKAGE.call_RETRIEVE_TS_PROFILE_PARSER( + DSL.using(conn).configuration(), locationId, parameterId, officeId); + return map(timeSeriesProfileParser, locationId, parameterId, officeId); + }); + } + + public List retrieveParameterInfoList(String locationId, String parameterId, String officeId) { + List parameterInfoList = new ArrayList<>(); + Condition whereCondition = JooqDao.caseInsensitiveLikeRegexNullTrue(AV_TS_PROFILE_PARSER_PARAM.AV_TS_PROFILE_PARSER_PARAM.LOCATION_ID, locationId); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_PARSER_PARAM.AV_TS_PROFILE_PARSER_PARAM.OFFICE_ID, officeId)); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_PARSER_PARAM.AV_TS_PROFILE_PARSER_PARAM.KEY_PARAMETER_ID, parameterId)); + Result parameterInfoResults = dsl.select(DSL.asterisk()).from(AV_TS_PROFILE_PARSER_PARAM.AV_TS_PROFILE_PARSER_PARAM) + .where(whereCondition) + .fetch(); + for (Record recordParameterInfo : parameterInfoResults) { + Short parameterField = recordParameterInfo.get("PARAMETER_FIELD", Short.class); + if (parameterField != null) { + parameterInfoList.add(new ParameterInfoIndexed.Builder() + .withIndex(parameterField) + .withParameter((String) recordParameterInfo.get(PARAMETER_ID)) + .withUnit((String) recordParameterInfo.get("PARAMETER_UNIT")) + .build()); + } else { + parameterInfoList.add(new ParameterInfoColumnar.Builder() + .withStartColumn(recordParameterInfo.get("PARAMETER_COL_START", Short.class)) + .withEndColumn(recordParameterInfo.get("PARAMETER_COL_END", Short.class)) + .withParameter((String) recordParameterInfo.get(PARAMETER_ID)) + .withUnit((String) recordParameterInfo.get("PARAMETER_UNIT")) + .build()); + } + } + return parameterInfoList; + } + + public List catalogTimeSeriesProfileParsers(String locationIdMask, String parameterIdMask, String officeIdMask, boolean includeParameters) { + List timeSeriesProfileParserList = new ArrayList<>(); + + Condition whereCondition = JooqDao.caseInsensitiveLikeRegexNullTrue(AV_TS_PROFILE_PARSER.AV_TS_PROFILE_PARSER.LOCATION_ID, locationIdMask); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_PARSER.AV_TS_PROFILE_PARSER.OFFICE_ID, officeIdMask)); + whereCondition = whereCondition.and(JooqDao.caseInsensitiveLikeRegex(AV_TS_PROFILE_PARSER.AV_TS_PROFILE_PARSER.KEY_PARAMETER_ID, parameterIdMask)); + + @NotNull Result timeSeriesProfileParserResults = dsl.select(DSL.asterisk()).from(AV_TS_PROFILE_PARSER.AV_TS_PROFILE_PARSER) + .where(whereCondition) + .fetch(); + for (Record profileParser : timeSeriesProfileParserResults) { + String recordDelimiter = profileParser.get("RECORD_DELIMTER_VALUE", String.class); + String fieldDelimiter = profileParser.get("FIELD_DELIMIETER_VALUE", String.class); + Short timeField = profileParser.get("TIME_FIELD", Short.class); + Short timeStartCol = profileParser.get("TIME_COL_START", Short.class); + Short timeEndCol = profileParser.get("TIME_COL_END", Short.class); + CwmsId locationId = new CwmsId.Builder() + .withOfficeId((String) profileParser.get("OFFICE_ID")) + .withName((String) profileParser.get("LOCATION_ID")) + .build(); + String keyParameter = profileParser.get("KEY_PARAMETER_ID", String.class); + TimeSeriesProfileParser timeSeriesProfileParser; + List parameterInfoList = null; + if (includeParameters) { + parameterInfoList = retrieveParameterInfoList(locationId.getName(), keyParameter, locationId.getOfficeId()); + } + if (timeField != null) { + timeSeriesProfileParser = new TimeSeriesProfileParserIndexed.Builder() + .withFieldDelimiter(fieldDelimiter.toCharArray()[0]) + .withTimeField(timeField) + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withParameterInfoList(parameterInfoList) + .withTimeFormat((String) profileParser.get(TIME_FORMAT)) + .withTimeZone((String) profileParser.get("TIME_ZONE_ID")) + .withRecordDelimiter(recordDelimiter.toCharArray()[0]) + .build(); + timeSeriesProfileParserList.add(timeSeriesProfileParser); + } else if (timeStartCol != null && timeEndCol != null) { + timeSeriesProfileParser = new TimeSeriesProfileParserColumnar.Builder() + .withTimeStartColumn(timeStartCol) + .withTimeEndColumn(timeEndCol) + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withParameterInfoList(parameterInfoList) + .withTimeFormat((String) profileParser.get(TIME_FORMAT)) + .withTimeZone((String) profileParser.get("TIME_ZONE_ID")) + .withRecordDelimiter(recordDelimiter.toCharArray()[0]) + .build(); + timeSeriesProfileParserList.add(timeSeriesProfileParser); + } + } + return timeSeriesProfileParserList; + } + + public List catalogTimeSeriesProfileParsers(String locationIdMask, String parameterIdMask, String officeIdMask) { + return connectionResult(dsl, conn -> { + Result tsProfileParserResult = CWMS_TS_PROFILE_PACKAGE.call_CAT_TS_PROFILE_PARSER(DSL.using(conn).configuration(), + locationIdMask, parameterIdMask, officeIdMask); + List timeSeriesProfileParserList = new ArrayList<>(); + for (Record profileParser : tsProfileParserResult) { + String recordDelimiter = profileParser.get("RECORD_DELIMITER", String.class); + String fieldDelimiter = profileParser.get("FIELD_DELIMITER", String.class); + Short timeField = profileParser.get("TIME_FIELD", Short.class); + Short timeStartCol = profileParser.get("TIME_START_COL", Short.class); + Short timeEndCol = profileParser.get("TIME_END_COL", Short.class); + Result parameterInfoResult = profileParser.get("PARAMETER_INFO", Result.class); + + List parameterInfoList = new ArrayList<>(); + for (Record recordParam : parameterInfoResult) { + if (timeField != null) { + parameterInfoList.add(new ParameterInfoIndexed.Builder() + .withIndex(recordParam.get("FIELD_NUMBER", Short.class)) + .withParameter((String) recordParam.get(PARAMETER_ID)) + .withUnit((String) recordParam.get("UNIT")) + .build()); + } else { + parameterInfoList.add(new ParameterInfoColumnar.Builder() + .withStartColumn(recordParam.get("START_COL", Short.class)) + .withEndColumn(recordParam.get("END_COL", Short.class)) + .withParameter((String) recordParam.get(PARAMETER_ID)) + .withUnit((String) recordParam.get("UNIT")) + .build()); + } + } + + + CwmsId locationId = new CwmsId.Builder() + .withOfficeId((String) profileParser.get("OFFICE_ID")) + .withName((String) profileParser.get("LOCATION_ID")) + .build(); + TimeSeriesProfileParser timeSeriesProfileParser; + if (timeField != null) { + timeSeriesProfileParser = new TimeSeriesProfileParserIndexed.Builder() + .withFieldDelimiter(fieldDelimiter.toCharArray()[0]) + .withTimeField(timeField) + .withLocationId(locationId) + .withKeyParameter(profileParser.get(KEY_PARAMETER_ID, String.class)) + .withTimeFormat((String) profileParser.get(TIME_FORMAT)) + .withTimeZone((String) profileParser.get(TIME_ZONE)) + .withRecordDelimiter(recordDelimiter.toCharArray()[0]) + .withParameterInfoList(parameterInfoList) + .build(); + timeSeriesProfileParserList.add(timeSeriesProfileParser); + } else if (timeStartCol != null && timeEndCol != null) { + timeSeriesProfileParser = new TimeSeriesProfileParserColumnar.Builder() + .withTimeStartColumn(timeStartCol) + .withTimeEndColumn(timeEndCol) + .withLocationId(locationId) + .withKeyParameter((String) profileParser.get(KEY_PARAMETER_ID)) + .withTimeFormat((String) profileParser.get(TIME_FORMAT)) + .withTimeZone((String) profileParser.get(TIME_ZONE)) + .withRecordDelimiter(recordDelimiter.toCharArray()[0]) + .withParameterInfoList(parameterInfoList) + .build(); + timeSeriesProfileParserList.add(timeSeriesProfileParser); + } + + } + return timeSeriesProfileParserList; + }); + } + + + public void copyTimeSeriesProfileParser(String locationId, String parameterId, String officeId, String destinationLocation) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_COPY_TS_PROFILE_PARSER(DSL.using(conn).configuration(), locationId, parameterId, destinationLocation, + "F", officeId)); + } + + public void deleteTimeSeriesProfileParser(String locationId, String parameterId, String officeId) { + connection(dsl, conn -> + CWMS_TS_PROFILE_PACKAGE.call_DELETE_TS_PROFILE_PARSER(DSL.using(conn).configuration(), locationId, + parameterId, officeId) + ); + } + + private TimeSeriesProfileParser map(RETRIEVE_TS_PROFILE_PARSER timeSeriesProfileParser, String locationName, String keyParameter, String officeId) { + String info = timeSeriesProfileParser.getP_PARAMETER_INFO(); + List parameterInfo = getParameterInfoList(info, timeSeriesProfileParser.getP_RECORD_DELIMITER(), + timeSeriesProfileParser.getP_FIELD_DELIMITER()); + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(locationName).build(); + return new TimeSeriesProfileParser.Builder() + .withLocationId(locationId) +// .withTimeField(timeSeriesProfileParser.getP_TIME_FIELD()) + .withTimeZone(timeSeriesProfileParser.getP_TIME_ZONE()) + .withTimeFormat(timeSeriesProfileParser.getP_TIME_FORMAT()) + .withKeyParameter(keyParameter) +// .withFieldDelimiter(timeSeriesProfileParser.getP_FIELD_DELIMITER().toCharArray()[0]) + .withRecordDelimiter(timeSeriesProfileParser.getP_RECORD_DELIMITER().toCharArray()[0]) + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfo) + .build(); + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java new file mode 100644 index 000000000..2d62cf29d --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java @@ -0,0 +1,50 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOBase; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +@JsonSubTypes({@JsonSubTypes.Type(value = ParameterInfoIndexed.class, name = "indexed-parameter-info"), + @JsonSubTypes.Type(value = ParameterInfoColumnar.class, name = "columnar-parameter-info") +}) + +public abstract class ParameterInfo extends CwmsDTOBase { + private final String parameter; + private final String unit; + + ParameterInfo(ParameterInfo.Builder builder) { + parameter = builder.parameter; + unit = builder.unit; + } + public abstract String getParameterInfoString(); + + public String getParameter() { + return parameter; + } + + public String getUnit() { + return unit; + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public abstract static class Builder { + private String parameter; + private String unit; + + public Builder withParameter(String parameter) { + this.parameter = parameter; + return this; + } + + public Builder withUnit(String unit) { + this.unit = unit; + return this; + } + public abstract ParameterInfo build(); + } +} \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoColumnar.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoColumnar.java new file mode 100644 index 000000000..844b282f3 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoColumnar.java @@ -0,0 +1,74 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = ParameterInfoColumnar.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class ParameterInfoColumnar extends ParameterInfo { + private final Integer startColumn; + private final Integer endColumn; + + ParameterInfoColumnar(ParameterInfoColumnar.Builder builder) { + super(builder); + startColumn = builder.startColumn; + endColumn = builder.endColumn; + } + + public Integer getStartColumn(){ + return startColumn; + } + public Integer getEndColumn(){ + return endColumn; + } + @Override + protected void validateInternal(CwmsDTOValidator validator) { + validator.required(startColumn, "startColumn"); + validator.required(endColumn, "endColumn"); + } + + @JsonIgnore + @Override + public String getParameterInfoString() + { + return getParameter() + + "," + + getUnit() + + "," + + "," + + getStartColumn() + + "," + + getEndColumn(); + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder extends ParameterInfo.Builder{ + private Integer startColumn; + private Integer endColumn; + + public ParameterInfoColumnar.Builder withStartColumn(int startColumn){ + this.startColumn = startColumn; + return this; + } + public ParameterInfoColumnar.Builder withEndColumn(int endColumn){ + this.endColumn = endColumn; + return this; + } + public ParameterInfo build() { + return new ParameterInfoColumnar(this); + } + + } +} \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoIndexed.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoIndexed.java new file mode 100644 index 000000000..5c72bd0d2 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoIndexed.java @@ -0,0 +1,64 @@ +package cwms.cda.data.dto.timeseriesprofile; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = ParameterInfoIndexed.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class ParameterInfoIndexed extends ParameterInfo { + private final Integer index; + + ParameterInfoIndexed(ParameterInfoIndexed.Builder builder) { + super(builder); + index = builder.index; + } + + public Integer getIndex() { + return index; + } + + @Override + protected void validateInternal(CwmsDTOValidator validator) { + validator.required(getIndex(), "index"); + } + + @JsonIgnore + @Override + public String getParameterInfoString() { + return getParameter() + + "," + + getUnit() + + "," + + getIndex() + + "," + + ","; + } + + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder extends ParameterInfo.Builder { + private Integer index; + + public ParameterInfoIndexed.Builder withIndex(int index) { + this.index = index; + return this; + } + + public ParameterInfo build() { + return new ParameterInfoIndexed(this); + } + + } +} \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ProfileTimeSeries.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ProfileTimeSeries.java new file mode 100644 index 000000000..703902162 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ProfileTimeSeries.java @@ -0,0 +1,78 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +import java.util.List; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = ProfileTimeSeries.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class ProfileTimeSeries { + private final String parameter; + private final String unit; + private final String timeZone; + private final List values; + + ProfileTimeSeries(Builder builder) + { + parameter = builder.parameter; + unit = builder.unit; + values = builder.values; + timeZone = builder.timeZone; + } + public String getTimeZone() + { + return timeZone; + } + public String getParameter() + { + return parameter; + } + public String getUnit() + { + return unit; + } + public List getValues() + { + return values; + } + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private List values; + private String unit; + private String parameter; + private String timeZone; + public Builder withValues(List values) { + this.values = values; + return this; + } + + public Builder withParameter(String parameter) { + this.parameter = parameter; + return this; + } + + public Builder withUnit(String unit) { + this.unit = unit; + return this; + } + + public Builder withTimeZone(String timeZone){ + this.timeZone = timeZone; + return this; + } + public ProfileTimeSeries build() { + return new ProfileTimeSeries(this); + } + } + +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java new file mode 100644 index 000000000..5dd954d57 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java @@ -0,0 +1,113 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOBase; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; +import io.swagger.v3.oas.annotations.media.Schema; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfile.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeSeriesProfile extends CwmsDTOBase { + @Schema(description = "Location ID") + private final CwmsId locationId; + @Schema(description = "Description") + private final String description; + @Schema(description = "Parameter List") + private final List parameterList; + @Schema(description = "Key Parameter") + private final String keyParameter; + @Schema(description = "Reference TS") + private final CwmsId referenceTsId; + + private TimeSeriesProfile(Builder builder) { + this.locationId = builder.locationId; + this.description = builder.description; + this.keyParameter = builder.keyParameter; + this.parameterList = builder.parameterList; + this.referenceTsId = builder.referenceTsId; + } + + public CwmsId getLocationId() { + return locationId; + } + + public String getDescription() { + return description; + } + + public String getKeyParameter() { + return keyParameter; + } + + public List getParameterList() { + return parameterList; + } + + public CwmsId getReferenceTsId() { + return referenceTsId; + } + + @Override + protected void validateInternal(CwmsDTOValidator validator) { + super.validateInternal(validator); + validator.required(getParameterList(), "parameterList"); + validator.required(getKeyParameter(), "keyParameter"); + validator.required(getLocationId(), "locationId"); + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private final List parameterList = new ArrayList<>(); + private String keyParameter; + private String description; + private CwmsId locationId; + private CwmsId referenceTsId; + + public TimeSeriesProfile.Builder withLocationId(CwmsId locationId) { + this.locationId = locationId; + return this; + } + + public TimeSeriesProfile.Builder withDescription(String description) { + this.description = description; + return this; + } + + public TimeSeriesProfile.Builder withKeyParameter(String keyParameter) { + this.keyParameter = keyParameter; + return this; + } + + public TimeSeriesProfile.Builder withParameterList(List parameterList) { + this.parameterList.clear(); + if (parameterList != null) { + this.parameterList.addAll(parameterList); + } + return this; + } + + public TimeSeriesProfile.Builder withReferenceTsId(CwmsId referenceTsId) { + this.referenceTsId = referenceTsId; + return this; + } + + + public TimeSeriesProfile build() { + return new TimeSeriesProfile(this); + } + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java new file mode 100644 index 000000000..790da2801 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java @@ -0,0 +1,115 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.api.errors.RequiredFieldException; +import cwms.cda.data.dto.CwmsDTOBase; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +import java.time.Instant; +import java.util.List; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfileInstance.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeSeriesProfileInstance extends CwmsDTOBase { + private final TimeSeriesProfile timeSeriesProfile; + private final List timeSeriesList; + private final String version; + private final Instant versionDate; + private final Instant firstDate; + private final Instant lastDate; + + private TimeSeriesProfileInstance(Builder builder) + { + timeSeriesList = builder.timeSeriesList; + timeSeriesProfile = builder.timeSeriesProfile; + version = builder.version; + versionDate = builder.versionDate; + firstDate = builder.firstDate; + lastDate = builder.lastDate; + } + + public TimeSeriesProfile getTimeSeriesProfile() { + return timeSeriesProfile; + } + + public List getTimeSeriesList() { + return timeSeriesList; + } + + public String getVersion() + { + return version; + } + public Instant getVersionDate() + { + return versionDate; + } + public Instant getFirstDate() + { + return firstDate; + } + public Instant getLastDate() + { + return lastDate; + } + @Override + protected void validateInternal(CwmsDTOValidator validator){ + if(timeSeriesProfile==null) + { + throw new RequiredFieldException("timeSeriesProfile"); + } + } + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private List timeSeriesList; + private TimeSeriesProfile timeSeriesProfile; + private String version; + private Instant versionDate; + private Instant firstDate; + private Instant lastDate; + + public TimeSeriesProfileInstance.Builder withTimeSeriesProfile(TimeSeriesProfile timeSeriesProfile) { + this.timeSeriesProfile = timeSeriesProfile; + return this; + } + + public TimeSeriesProfileInstance.Builder withTimeSeriesList(List timeSeriesList) { + this.timeSeriesList = timeSeriesList; + return this; + } + + public TimeSeriesProfileInstance.Builder withVersion(String version) + { + this.version = version; + return this; + } + public TimeSeriesProfileInstance.Builder withVersionDate(Instant instant) + { + this.versionDate = instant; + return this; + } + public TimeSeriesProfileInstance.Builder withFirstDate(Instant instant) + { + this.firstDate = instant; + return this; + } + public TimeSeriesProfileInstance.Builder withLastDate(Instant instant) + { + this.lastDate = instant; + return this; + } + public TimeSeriesProfileInstance build() { + return new TimeSeriesProfileInstance(this); + } + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java new file mode 100644 index 000000000..0e21bde83 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java @@ -0,0 +1,126 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOBase; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.data.dto.CwmsId; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +@JsonSubTypes({@JsonSubTypes.Type(value = TimeSeriesProfileParserIndexed.class, name = "indexed-timeseries-profile-parser"), + @JsonSubTypes.Type(value = TimeSeriesProfileParserColumnar.class, name = "columnar-timeseries-profile-parser") +}) + +public class TimeSeriesProfileParser extends CwmsDTOBase { + private final CwmsId locationId; + private final String keyParameter; + private final char recordDelimiter; + private final String timeFormat; + private final String timeZone; + private final List parameterInfoList; + private final boolean timeInTwoFields; + + TimeSeriesProfileParser(Builder builder) { + locationId = builder.locationId; + keyParameter = builder.keyParameter; + recordDelimiter = builder.recordDelimiter; + timeFormat = builder.timeFormat; + timeZone = builder.timeZone; + parameterInfoList = builder.parameterInfoList; + timeInTwoFields = builder.timeInTwoFields; + } + + @Override + protected void validateInternal(CwmsDTOValidator validator) { + // there must be a key parameter + validator.required(getKeyParameter(),"keyParameter"); + } + + + public CwmsId getLocationId() { + return locationId; + } + + public String getKeyParameter() { + return keyParameter; + } + + public char getRecordDelimiter() { + return recordDelimiter; + } + + public List getParameterInfoList() { + return parameterInfoList; + } + + public String getTimeFormat() { + return timeFormat; + } + + public String getTimeZone() { + return timeZone; + } + + public boolean getTimeInTwoFields() { + return timeInTwoFields; + } + + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static class Builder { + private List parameterInfoList; + private String keyParameter; + private char recordDelimiter; + private String timeFormat; + private String timeZone; + private boolean timeInTwoFields; + private CwmsId locationId; + + public TimeSeriesProfileParser.Builder withLocationId(CwmsId locationId) { + this.locationId = locationId; + return this; + } + + public TimeSeriesProfileParser.Builder withKeyParameter(String keyParameter) { + this.keyParameter = keyParameter; + return this; + } + + public TimeSeriesProfileParser.Builder withRecordDelimiter(char delimiter) { + this.recordDelimiter = delimiter; + return this; + } + + + public TimeSeriesProfileParser.Builder withTimeFormat(String timeFormat) { + this.timeFormat = timeFormat; + return this; + } + + public TimeSeriesProfileParser.Builder withTimeZone(String timeZone) { + this.timeZone = timeZone; + return this; + } + + + public TimeSeriesProfileParser.Builder withTimeInTwoFields(boolean timeInTwoFields) { + this.timeInTwoFields = timeInTwoFields; + return this; + } + + public TimeSeriesProfileParser.Builder withParameterInfoList(List parameterInfoList) { + this.parameterInfoList = parameterInfoList; + return this; + } + + public TimeSeriesProfileParser build() { + return new TimeSeriesProfileParser(this); + } + } + +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserColumnar.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserColumnar.java new file mode 100644 index 000000000..75a8eef4a --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserColumnar.java @@ -0,0 +1,70 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +import java.math.BigInteger; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfileParserColumnar.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeSeriesProfileParserColumnar extends TimeSeriesProfileParser { + private final Integer timeStartColumn; + private final Integer timeEndColumn; + + TimeSeriesProfileParserColumnar(Builder builder) { + super(builder); + timeStartColumn = builder.timeStartColumn; + timeEndColumn = builder.timeEndColumn; + } + + @Override + protected void validateInternal(CwmsDTOValidator validator) { + validator.required(getTimeStartColumn(),"timeStartColumn"); + validator.required(getTimeEndColumn(),"timeEndColumn"); + } + + public BigInteger getTimeStartColumn() { + if (timeStartColumn != null) { + return BigInteger.valueOf(timeStartColumn); + } + return null; + } + public BigInteger getTimeEndColumn(){ + if (timeEndColumn != null) { + return BigInteger.valueOf(timeEndColumn); + } + return null; + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder extends TimeSeriesProfileParser.Builder{ + private Integer timeStartColumn = null; + private Integer timeEndColumn = null; + + public TimeSeriesProfileParserColumnar.Builder withTimeStartColumn(int timeStartColumn) + { + this.timeStartColumn = timeStartColumn; + return this; + } + public TimeSeriesProfileParserColumnar.Builder withTimeEndColumn(int timeEndColumn) + { + this.timeEndColumn = timeEndColumn; + return this; + } + @Override + public TimeSeriesProfileParserColumnar build() { + return new TimeSeriesProfileParserColumnar(this); + } + } + +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserIndexed.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserIndexed.java new file mode 100644 index 000000000..1d49f7b7c --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserIndexed.java @@ -0,0 +1,68 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOValidator; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +import java.math.BigInteger; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfileParserIndexed.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public class TimeSeriesProfileParserIndexed extends TimeSeriesProfileParser { + private final Character fieldDelimiter; + private final Integer timeField; + + TimeSeriesProfileParserIndexed(Builder builder) { + super(builder); + fieldDelimiter = builder.fieldDelimiter; + timeField = builder.timeField; + } + + @Override + protected void validateInternal(CwmsDTOValidator validator) { + validator.required(getFieldDelimiter(),"fieldDelimiter"); + validator.required(getTimeField(),"timeField"); + } + + + public Character getFieldDelimiter() { + return fieldDelimiter; + } + + + public BigInteger getTimeField() { + return BigInteger.valueOf(timeField); + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static class Builder extends TimeSeriesProfileParser.Builder{ + private Character fieldDelimiter = null; + private Integer timeField = null; + + + public TimeSeriesProfileParserIndexed.Builder withFieldDelimiter(char delimiter) { + this.fieldDelimiter = delimiter; + return this; + } + + + public TimeSeriesProfileParserIndexed.Builder withTimeField(int field) { + this.timeField = field; + return this; + } + @Override + public TimeSeriesProfileParserIndexed build() { + return new TimeSeriesProfileParserIndexed(this); + } + } + +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeValuePair.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeValuePair.java new file mode 100644 index 000000000..52253db5b --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeValuePair.java @@ -0,0 +1,67 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.data.dto.CwmsDTOBase; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +import java.time.Instant; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeValuePair.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeValuePair extends CwmsDTOBase { + private final Instant dateTime; + private final double value; + private final int quality; + + private TimeValuePair(Builder builder) + { + dateTime = builder.dateTime; + value = builder.value; + quality = builder.quality; + } + public Instant getDateTime() + { + return dateTime; + } + public double getValue() + { + return value; + } + public int getQuality() + { + return quality; + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private Instant dateTime; + private double value; + private int quality; + + public Builder withDateTime(Instant dateTime) { + this.dateTime = dateTime; + return this; + } + + public Builder withValue(double value) { + this.value = value; + return this; + } + public Builder withQuality(int quality) { + this.quality = quality; + return this; + } + public TimeValuePair build() { + return new TimeValuePair(this); + } + } +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java new file mode 100644 index 000000000..83c21a868 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java @@ -0,0 +1,133 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import cwms.cda.api.DataApiTestIT; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileTest; +import fixtures.CwmsDataApiSetupCallback; +import mil.army.usace.hec.test.database.CwmsDatabaseContainer; +import org.jooq.DSLContext; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static cwms.cda.data.dao.DaoTest.getDslContext; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Tag("integration") +class TimeSeriesProfileDaoIT extends DataApiTestIT { + @Test + void testCopyTimeSeriesProfile() throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + String officeId ="LRL"; + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, "Glensboro", "Depth"); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + timeSeriesProfileDao.copyTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + "Greensburg", null, + timeSeriesProfile.getLocationId().getOfficeId()); + TimeSeriesProfile timeSeriesProfileCopied = timeSeriesProfileDao.retrieveTimeSeriesProfile( + "Greensburg", + timeSeriesProfile.getKeyParameter(), timeSeriesProfile.getLocationId().getOfficeId()); + assertEquals("Greensburg", timeSeriesProfileCopied.getLocationId().getName()); + assertEquals(timeSeriesProfile.getKeyParameter(), timeSeriesProfileCopied.getKeyParameter()); + assertEquals(timeSeriesProfile.getParameterList(), timeSeriesProfileCopied.getParameterList()); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), timeSeriesProfile.getLocationId().getOfficeId()); + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfileCopied.getLocationId().getName(), + timeSeriesProfileCopied.getKeyParameter(), timeSeriesProfileCopied.getLocationId().getOfficeId()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testRetrieveTimeSeriesProfile() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + String officeId = "LRL"; + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfileIn = buildTestTimeSeriesProfile(officeId,"Glensboro","Depth"); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfileIn, false); + + TimeSeriesProfile timeSeriesProfileOut = timeSeriesProfileDao.retrieveTimeSeriesProfile(timeSeriesProfileIn.getLocationId().getName(), + timeSeriesProfileIn.getKeyParameter(), timeSeriesProfileIn.getLocationId().getOfficeId()); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfileIn.getLocationId().getName(), + timeSeriesProfileIn.getKeyParameter(), timeSeriesProfileIn.getLocationId().getOfficeId()); + + TimeSeriesProfileTest.testAssertEquals(timeSeriesProfileOut, timeSeriesProfileIn, ""); + + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testRetrieveCatalog() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + String officeId = "LRL"; + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + timeSeriesProfileDao.storeTimeSeriesProfile(buildTestTimeSeriesProfile(officeId,"Glensboro","Depth"), false); + timeSeriesProfileDao.storeTimeSeriesProfile(buildTestTimeSeriesProfile(officeId,"Greensburg","Pres"), false); + + + List timeSeriesProfileListBefore = + timeSeriesProfileDao.catalogTimeSeriesProfiles("*", "*", "*"); + + for (TimeSeriesProfile timeSeriesProfile : timeSeriesProfileListBefore) { + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + } + List timeSeriesProfileListAfter = timeSeriesProfileDao.catalogTimeSeriesProfiles("*", "*", "*"); + + assertEquals(0, timeSeriesProfileListAfter.size()); + assertEquals(2, timeSeriesProfileListBefore.size()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testDeleteTimeSeriesProfile() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + String officeId = "LRL"; + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId,"Glensboro","Depth"); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + List timeSeriesProfileListBefore = + timeSeriesProfileDao.catalogTimeSeriesProfiles("*", "*", "*"); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + + List timeSeriesProfileListAfter = + timeSeriesProfileDao.catalogTimeSeriesProfiles("*", "*", "*"); + + + assertEquals(timeSeriesProfileListBefore.size() - 1, timeSeriesProfileListAfter.size()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + static private TimeSeriesProfile buildTestTimeSeriesProfile(String officeId, String location, String keyParameter) { + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(location).build(); + CwmsId refTsId = new CwmsId.Builder().withOfficeId(officeId).withName("Greensburg.Stage.Inst.1Hour.0.USGS-rev").build(); + return new TimeSeriesProfile.Builder() + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withParameterList(Arrays.asList("Pres", "Depth")) + .withDescription("description") + .withReferenceTsId(refTsId) + .build(); + + } +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDaoIT.java b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDaoIT.java new file mode 100644 index 000000000..795e69332 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDaoIT.java @@ -0,0 +1,562 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import cwms.cda.api.DataApiTestIT; +import cwms.cda.data.dao.StoreRule; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfo; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfoColumnar; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfoIndexed; +import cwms.cda.data.dto.timeseriesprofile.ProfileTimeSeries; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileInstance; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParserColumnar; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParserIndexed; +import cwms.cda.data.dto.timeseriesprofile.TimeValuePair; +import fixtures.CwmsDataApiSetupCallback; +import mil.army.usace.hec.test.database.CwmsDatabaseContainer; +import org.apache.commons.io.IOUtils; +import org.jooq.DSLContext; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import usace.cwms.db.dao.ifc.ts.CwmsDbTs; +import usace.cwms.db.dao.util.services.CwmsDbServiceLookup; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.sql.SQLException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cwms.cda.data.dao.DaoTest.getDslContext; +import static org.junit.jupiter.api.Assertions.*; + +@Tag("integration") +class TimeSeriesProfileInstanceDaoIT extends DataApiTestIT { + + @Test + void testStoreTimeSeriesProfileInstanceWithDataBlock() throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + String officeId = "LRL"; + String locationName = "Glensboro"; + String versionId = "VERSION"; + String unit = "kPa,m"; + String[] parameterArray = {"Depth", "Pres"}; + int[] parameterIndexArray = {7, 8}; + String[] parameterUnitArray = {"m", "kPa"}; + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + Instant startTime = Instant.parse("2018-07-09T19:06:20.00Z"); + Instant endTime = Instant.parse("2025-07-09T19:06:20.00Z"); + String profileData; + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileData.txt"); + assertNotNull(resource); + try { + profileData = IOUtils.toString(resource, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + String timeZone = "UTC"; + boolean startInclusive = true; + boolean endInclusive = true; + boolean previous = true; + boolean next = true; + boolean maxVersion = true; + char fieldDelimiter = ','; + char recordDelimiter = '\n'; + int timeField = 1; + String timeFormat = "MM/DD/YYYY,HH24:MI:SS"; + + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + // store a time series profile + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameterArray[0], parameterArray[1]); + TimeSeriesProfileDao profileDao = new TimeSeriesProfileDao(context); + profileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + // store a time series parser + TimeSeriesProfileParserIndexed parser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameterArray, parameterIndexArray, parameterUnitArray, recordDelimiter, fieldDelimiter, + timeFormat, timeZone, timeField); + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + + // now store the new one. + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(parser, false); + + // create a time series profile instance and test storeTimeSeriesProfileInstance + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + String storeRule = StoreRule.REPLACE_ALL.toString(); + timeSeriesProfileInstanceDao.storeTimeSeriesProfileInstance(timeSeriesProfile, profileData, versionDate, versionId, storeRule, false); + + try { + // retrieve the time series profile instance we just stored + TimeSeriesProfileInstance timeSeriesProfileInstance = retrieveTimeSeriesProfileInstance(officeId, locationName, parameterArray[0], versionId, unit, + startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, maxVersion); + // cleanup: delete the instance + profileDao.deleteTimeSeriesProfile(timeSeriesProfileInstance.getTimeSeriesProfile().getLocationId().getName(), timeSeriesProfileInstance.getTimeSeriesProfile().getKeyParameter(), + timeSeriesProfileInstance.getTimeSeriesProfile().getLocationId().getOfficeId()); + // check if the instant contains the timeseries we stpred + assertEquals(parameterArray.length, timeSeriesProfileInstance.getTimeSeriesList().size()); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }, CwmsDataApiSetupCallback.getWebUser()); + } + @Test + void testStoreTimeSeriesProfileInstanceWithDataBlockColumnar() throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + String officeId = "LRL"; + String locationName = "Glensboro"; + String versionId = "VERSION"; + String unit = "kPa,m"; + String[] parameterArray = {"Depth", "Pres"}; + int[][] parameterStartEndArray = {{21, 23}, {25, 27}}; + String[] parameterUnitArray = {"m", "kPa"}; + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + Instant startTime = Instant.parse("2018-07-09T19:06:20.00Z"); + Instant endTime = Instant.parse("2025-07-09T19:06:20.00Z"); + String profileData; + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileDataColumnar.txt"); + assertNotNull(resource); + try { + profileData = IOUtils.toString(resource, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + String timeZone = "UTC"; + boolean startInclusive = true; + boolean endInclusive = true; + boolean previous = true; + boolean next = true; + boolean maxVersion = true; + char recordDelimiter = '\n'; + int[] timeStartEnd = {1, 19}; + + String timeFormat = "MM/DD/YYYY,HH24:MI:SS"; + + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + // store a time series profile + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameterArray[0], parameterArray[1]); + TimeSeriesProfileDao profileDao = new TimeSeriesProfileDao(context); + profileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + // store a time series parser + TimeSeriesProfileParserColumnar parser = buildTestTimeSeriesProfileParserColumnar(officeId, locationName, parameterArray, parameterStartEndArray, parameterUnitArray, recordDelimiter, + timeFormat, timeZone, timeStartEnd); + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(parser, false); + + // create a time series profile instance and test storeTimeSeriesProfileInstance + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + String storeRule = StoreRule.REPLACE_ALL.toString(); + timeSeriesProfileInstanceDao.storeTimeSeriesProfileInstance(timeSeriesProfile, profileData, versionDate, versionId, storeRule, false); + + try { + // retrieve the time series profile instance we just stored + TimeSeriesProfileInstance timeSeriesProfileInstance = retrieveTimeSeriesProfileInstance(officeId, locationName, parameterArray[0], versionId, unit, + startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, maxVersion); + // cleanup: delete the instance + profileDao.deleteTimeSeriesProfile(timeSeriesProfileInstance.getTimeSeriesProfile().getLocationId().getName(), timeSeriesProfileInstance.getTimeSeriesProfile().getKeyParameter(), + timeSeriesProfileInstance.getTimeSeriesProfile().getLocationId().getOfficeId()); + + // check if the instant contains the timeseries we stpred + assertEquals(parameterArray.length, timeSeriesProfileInstance.getTimeSeriesList().size()); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }, CwmsDataApiSetupCallback.getWebUser()); + } + + + @Test + void testCatalogTimeSeriesProfileInstances() throws SQLException { + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + String officeId = "LRL"; + String location = "Glensboro"; + String[] keyParameter = {"Depth", "m"}; + String[] parameter1 = {"Pres", "psi"}; + String[] versions = {"VERSION", "VERSION2", "VERSION3"}; + String officeIdMask = "*"; + String locationMask = "*"; + String parameterMask = "*"; + String versionMask = "*"; + String timeZone = "UTC"; + Instant firstDate = Instant.parse("2024-07-09T19:00:11.00Z"); + Instant[] dateTimeArray = {Instant.parse("2024-07-09T19:00:11.00Z"), Instant.parse("2024-07-09T20:00:22.00Z")}; + double[] valueArray = {1, 4}; + + // store a few timeseries profile instances + for (String version : versions) { + storeTimeSeriesProfileInstance(officeId, location, keyParameter, parameter1, version, versionDate, dateTimeArray, valueArray, timeZone); + } + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + // test retrieveTimeSeriesProfileInstances + List result = timeSeriesProfileInstanceDao.catalogTimeSeriesProfileInstances(officeIdMask, locationMask, parameterMask, + versionMask); + + // cleanup: delete the time series profile instances we created + boolean overrideProtection = false; + for (TimeSeriesProfileInstance timeSeriesProfileInstance : result) { + timeSeriesProfileInstanceDao.deleteTimeSeriesProfileInstance(timeSeriesProfileInstance.getTimeSeriesProfile().getLocationId(), + timeSeriesProfileInstance.getTimeSeriesProfile().getKeyParameter(), timeSeriesProfileInstance.getVersion(), + firstDate, timeZone, overrideProtection, timeSeriesProfileInstance.getVersionDate()); + break; + } + // check if we retrieve all the instances we stored + assertEquals(versions.length, result.size(), CwmsDataApiSetupCallback.getWebUser()); + }); + } + + @Test + void testRetrieveTimeSeriesProfileInstance() throws SQLException { + String officeId = "LRL"; + String versionID = "VERSION"; + String locationName = "Glensboro"; + String[] keyParameter = {"Depth", "m"}; + String[] parameter1 = {"Pres", "psi"}; + String unit = "bar,m"; + Instant startTime = Instant.parse("2024-07-09T19:00:11.00Z"); + Instant endTime = Instant.parse("2025-01-01T19:00:22.00Z"); + String timeZone = "UTC"; + String startInclusive = "T"; + String endInclusive = "T"; + String previous = "T"; + String next = "T"; + String maxVersion = "T"; + Instant[] dateTimeArray = {Instant.parse("2024-07-09T19:00:11.00Z"), Instant.parse("2024-07-09T20:00:22.00Z")}; + double[] valueArray = {1, 4}; + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + + // store a time series profile instance + storeTimeSeriesProfileInstance(officeId, locationName, keyParameter, parameter1, versionID, versionDate, dateTimeArray, valueArray, timeZone); + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + CwmsId location = new CwmsId.Builder() + .withName(locationName) + .withOfficeId(officeId) + .build(); + // test the retrieveTimeSeriesProfileInstance method + TimeSeriesProfileInstance result = timeSeriesProfileInstanceDao.retrieveTimeSeriesProfileInstance(location, keyParameter[0], versionID, + unit, startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, + maxVersion); + + // cleanup: delete the timeseries we created + timeSeriesProfileInstanceDao.deleteTimeSeriesProfileInstance(result.getTimeSeriesProfile().getLocationId(), + result.getTimeSeriesProfile().getKeyParameter(), result.getVersion(), + startTime, timeZone, false, result.getVersionDate()); + + // check if the retrieved timeseries profile instance has the same tineseries as the one we stored + assertEquals(2, result.getTimeSeriesList().size()); + assertEquals(2, result.getTimeSeriesList().get(0).getValues().size()); + + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testDeleteTimeSeriesProfileInstance() throws SQLException { + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + String officeId = "LRL"; + String locationName = "Glensboro"; + String[] keyParameter = {"Depth", "m"}; + String[] parameter1 = {"Pres", "psi"}; + String unit = "kPa,m"; + String version = "VERSION"; + String timeZone = "UTC"; + Instant startTime = Instant.parse("2018-07-09T19:06:20.00Z"); + Instant endTime = Instant.parse("2025-07-09T19:06:20.00Z"); + boolean overrideProtection = false; + boolean startInclusive = true; + boolean endInclusive = true; + boolean previous = true; + boolean next = true; + boolean maxVersion = true; + Instant firstDate = Instant.parse("2024-07-09T19:00:11.00Z"); + Instant[] dateTimeArray = {Instant.parse("2024-07-09T19:00:11.00Z"), Instant.parse("2024-07-09T20:00:22.00Z")}; + double[] valueArray = {3, 5}; + + // store a time series profile instance + storeTimeSeriesProfileInstance(officeId, locationName, keyParameter, parameter1, version, versionDate, dateTimeArray, valueArray, timeZone); + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + + // retrieve the instance make sure it exists + TimeSeriesProfileInstance timeSeriesProfileInstance; + try { + timeSeriesProfileInstance = retrieveTimeSeriesProfileInstance(officeId, locationName, keyParameter[0], version, unit, + startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, maxVersion); + } catch (SQLException e) { + throw new RuntimeException(e); + } + // instance exists? + assertNotNull(timeSeriesProfileInstance); + + CwmsId location = new CwmsId.Builder() + .withName(locationName) + .withOfficeId(officeId) + .build(); + + // testing delete + timeSeriesProfileInstanceDao.deleteTimeSeriesProfileInstance(location, keyParameter[0], version, + firstDate, timeZone, overrideProtection, versionDate); + + // check if instance was deleted + try { + timeSeriesProfileInstance = retrieveTimeSeriesProfileInstance(officeId, locationName, keyParameter[0], version, unit, + startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, maxVersion); + } catch (SQLException e) { + throw(new RuntimeException(e)); + } + // instance does not exist anymore + assertNull(timeSeriesProfileInstance); +// +// // cleanup the timeseries +// try { +// CwmsDbTs tsDao = CwmsDbServiceLookup.buildCwmsDb(CwmsDbTs.class, c); +// tsDao.deleteAll(c, officeId, locationName + "." + keyParameter[0] + ".Inst.0.0." + version); +// tsDao.deleteAll(c, officeId, locationName + "." + parameter1[0] + ".Inst.0.0." + version); +// } catch (SQLException e) { +// throw(new RuntimeException(e)); +// } + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testStoreTimeSeriesProfileInstance() throws SQLException { + String versionId = "VERSION"; + String officeId = "LRL"; + String locationName = "Glensboro"; + String[] parameterArray = {"Depth", "Pres"}; + String[] parameterUnitArray = {"m", "bar"}; + int[] parameterIndexArray = {5, 6}; + String[] keyParameter = {parameterArray[0], parameterUnitArray[0]}; + String[] parameter1 = {parameterArray[1], parameterUnitArray[1]}; + String unit = "kPa,m"; + Instant versionDate = Instant.parse("2024-07-09T12:00:00.00Z"); + String timeZone = "UTC"; + Instant startTime = Instant.parse("2018-07-09T19:06:20.00Z"); + Instant endTime = Instant.parse("2025-07-09T19:06:20.00Z"); + Instant firstDate = Instant.parse("2024-07-09T19:00:11.00Z"); + boolean startInclusive = true; + boolean endInclusive = true; + boolean previous = true; + boolean next = true; + boolean maxVersion = true; + Instant[] dateTimeArray = {Instant.parse("2024-07-09T19:00:11.00Z"), Instant.parse("2024-07-09T20:00:22.00Z")}; + double[] valueArray = {1.0, 5.0}; + char fieldDelimiter = ','; + char recordDelimiter = '\n'; + int timeField = 1; + String timeFormat = "MM/DD/YYYY,HH24:MI:SS"; + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileInstance timeSeriesProfileInstance; + + + // store a profile + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, keyParameter[0], parameter1[0]); + TimeSeriesProfileDao profileDao = new TimeSeriesProfileDao(context); + profileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + // store a parser + TimeSeriesProfileParserIndexed parser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameterArray, parameterIndexArray, parameterUnitArray, recordDelimiter, fieldDelimiter, + timeFormat, timeZone, timeField); + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(parser, false); + + String storeRule = StoreRule.REPLACE_ALL.toString(); + /// create an instance for parameter Depth + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + TimeSeriesProfileInstance timeseriesProfileInstance = buildTestTimeSeriesProfileInstance(officeId, locationName, keyParameter, parameter1, versionId, + dateTimeArray, valueArray, timeZone, versionDate); + // test storeTImeSeriesProfileInstance method + timeSeriesProfileInstanceDao.storeTimeSeriesProfileInstance(timeseriesProfileInstance, versionId, versionDate, storeRule, null); + // check is the timeseries profile instance can be retrieved + try { + timeSeriesProfileInstance = retrieveTimeSeriesProfileInstance(officeId, locationName, keyParameter[0], versionId, unit, + startTime, endTime, timeZone, startInclusive, endInclusive, previous, next, versionDate, maxVersion); + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + // instance exists? + + // cleanup delete the timeseries profile instance and its timeseries + boolean overrideProtection = false; + timeSeriesProfileInstanceDao.deleteTimeSeriesProfileInstance(timeseriesProfileInstance.getTimeSeriesProfile().getLocationId(), + timeSeriesProfile.getKeyParameter(), versionId, + firstDate, timeZone, overrideProtection, versionDate); + + try { + CwmsDbTs tsDao = CwmsDbServiceLookup.buildCwmsDb(CwmsDbTs.class, c); + tsDao.deleteAll(c, officeId, locationName + "." + keyParameter[0] + ".Inst.0.0." + versionId); + tsDao.deleteAll(c, officeId, locationName + "." + parameter1[0] + ".Inst.0.0." + versionId); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + assertNotNull(timeSeriesProfileInstance); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + private TimeSeriesProfileInstance retrieveTimeSeriesProfileInstance(String officeId, String locationName, String keyParameter, String version, String unit, + Instant startTime, Instant endTime, String timeZone, boolean startInclusive, boolean endInclusive, boolean previous, boolean next, + Instant versionDate, boolean maxVersion) throws SQLException { + final TimeSeriesProfileInstance[] result = {null}; + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + CwmsId location = new CwmsId.Builder() + .withOfficeId(officeId) + .withName(locationName) + .build(); + try { + result[0] = timeSeriesProfileInstanceDao.retrieveTimeSeriesProfileInstance(location, keyParameter, version, + unit, startTime, endTime, timeZone, startInclusive ? "T" : "F", endInclusive ? "T" : "F", previous ? "T" : "F", next ? "T" : "F", versionDate, + maxVersion ? "T" : "F"); + } + catch(cwms.cda.api.errors.NotFoundException ex) + { + // return null for not found + } + }, CwmsDataApiSetupCallback.getWebUser()); + return result[0]; + } + + private void storeTimeSeriesProfileInstance(String officeId, String location, String[] keyParameter, String[] parameter1, String version, Instant versionInstant, Instant[] dateTimeArray, double[] valueArray, + String timeZone) throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, location, keyParameter[0], parameter1[0]); + TimeSeriesProfileDao profileDao = new TimeSeriesProfileDao(context); + profileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + /// create an instance for parameter Depth + TimeSeriesProfileInstanceDao timeSeriesProfileInstanceDao = new TimeSeriesProfileInstanceDao(context); + TimeSeriesProfileInstance timeseriesProfileInstance = buildTestTimeSeriesProfileInstance(officeId, location, keyParameter, parameter1, version, dateTimeArray, valueArray, timeZone, versionInstant); + String storeRule = StoreRule.REPLACE_ALL.toString(); + + timeSeriesProfileInstanceDao.storeTimeSeriesProfileInstance(timeseriesProfileInstance, version, versionInstant, storeRule, "F"); + + }, CwmsDataApiSetupCallback.getWebUser()); + } + + private static TimeSeriesProfileInstance buildTestTimeSeriesProfileInstance(String officeId, String locationName, String[] keyParameterUnit, String[] parameterUnit1, String version, + Instant[] dateTimeArray, double[] valueArray, String timeZone, Instant versionInstant) { + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, keyParameterUnit[0], parameterUnit1[0]); + + + List timeValuePairList = new ArrayList<>(); + for (int i = 0; i < dateTimeArray.length; i++) { + TimeValuePair timeValuePair = new TimeValuePair.Builder() + .withValue(valueArray[i]) + .withDateTime(dateTimeArray[i]) + .build(); + timeValuePairList.add(timeValuePair); + } + + ProfileTimeSeries profileTimeSeries = new ProfileTimeSeries.Builder() + .withParameter(keyParameterUnit[0]) + .withUnit(keyParameterUnit[1]) + .withTimeZone(timeZone) + .withValues(timeValuePairList) + .build(); + + List timeSeriesList = new ArrayList<>(); + timeSeriesList.add(profileTimeSeries); + profileTimeSeries = new ProfileTimeSeries.Builder() + .withParameter(parameterUnit1[0]) + .withUnit(parameterUnit1[1]) + .withTimeZone(timeZone) + .withValues(timeValuePairList) + .build(); + + timeSeriesList.add(profileTimeSeries); + return new TimeSeriesProfileInstance.Builder() + .withTimeSeriesProfile(timeSeriesProfile) + .withTimeSeriesList(timeSeriesList) + .withVersion(version) + .withVersionDate(versionInstant) + .build(); + } + + static private TimeSeriesProfile buildTestTimeSeriesProfile(String officeId, String locationName, String keyParameter, String parameter1) { + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(locationName).build(); + return new TimeSeriesProfile.Builder() + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withParameterList(Arrays.asList(parameter1, keyParameter)) + .withDescription("description") + .build(); + + } + private TimeSeriesProfileParserColumnar buildTestTimeSeriesProfileParserColumnar(String officeId, String location, String[] parameterArray, int[][] parameterStartEndArray, String[] parameterUnitArray, char recordDelimiter, String timeFormat, String timeZone, int[] timeStartEnd) { + List parameterInfoList = new ArrayList<>(); + for (int i = 0; i < parameterArray.length; i++) { + parameterInfoList.add(new ParameterInfoColumnar.Builder() + .withStartColumn(parameterStartEndArray[i][0]) + .withEndColumn(parameterStartEndArray[i][1]) + .withUnit(parameterUnitArray[i]) + .withParameter(parameterArray[i]) + .build()); + } + + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(location).build(); + return (TimeSeriesProfileParserColumnar) + + new TimeSeriesProfileParserColumnar.Builder() + .withTimeStartColumn(timeStartEnd[0]) + .withTimeEndColumn(timeStartEnd[1]) + .withLocationId(locationId) + .withKeyParameter(parameterArray[0]) + .withRecordDelimiter(recordDelimiter) + .withTimeFormat(timeFormat) + .withTimeZone(timeZone) + + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfoList) + .build(); + } + + static private TimeSeriesProfileParserIndexed buildTestTimeSeriesProfileParserIndexed(String officeId, String location, String[] parameterArray, int[] parameterIndexArray, String[] parameterUnitArray, + char recordDelimiter, char fieldDelimiter, String timeFormat, String timeZone, int timeField) { + List parameterInfoList = new ArrayList<>(); + for (int i = 0; i < parameterArray.length; i++) { + parameterInfoList.add(new ParameterInfoIndexed.Builder() + .withIndex(parameterIndexArray[i]) + .withParameter(parameterArray[i]) + .withUnit(parameterUnitArray[i]) + .build()); + } + + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(location).build(); + return (TimeSeriesProfileParserIndexed) + + new TimeSeriesProfileParserIndexed.Builder() + .withFieldDelimiter(fieldDelimiter) + .withTimeField(timeField) + .withLocationId(locationId) + .withKeyParameter(parameterArray[0]) + .withRecordDelimiter(recordDelimiter) + .withTimeFormat(timeFormat) + .withTimeZone(timeZone) + .withTimeInTwoFields(true) + .withParameterInfoList(parameterInfoList) + .build(); + } +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java new file mode 100644 index 000000000..e77acc576 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java @@ -0,0 +1,252 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import cwms.cda.api.DataApiTestIT; +import cwms.cda.data.dto.CwmsId; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfo; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfoIndexed; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParser; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParserIndexed; +import fixtures.CwmsDataApiSetupCallback; +import mil.army.usace.hec.test.database.CwmsDatabaseContainer; +import org.jooq.DSLContext; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static cwms.cda.data.dao.DaoTest.getDslContext; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Tag("integration") +final class TimeSeriesProfileParserDaoIT extends DataApiTestIT { + + + @Test + void testStoreAndRetrieve() throws Exception { + String officeId = "LRL"; + String locationName = "Glensboro"; + String locationName1 = "Greensburg"; + String[] parameter = {"Depth", "Temp-Water"}; + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameter[0], parameter); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName1, parameter[0], parameter); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + TimeSeriesProfileParserIndexed timeSeriesProfileParser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameter[0]); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(timeSeriesProfileParser, false); + + TimeSeriesProfileParser retrieved = timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId()); + assertEquals(timeSeriesProfileParser.getLocationId().getName(), retrieved.getLocationId().getName()); + assertEquals(timeSeriesProfileParser.getLocationId().getOfficeId(), retrieved.getLocationId().getOfficeId()); + assertEquals(timeSeriesProfileParser.getTimeFormat(), retrieved.getTimeFormat()); + assertEquals(timeSeriesProfileParser.getKeyParameter(), retrieved.getKeyParameter()); + + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId()); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testStoreAndDelete() throws SQLException { + String officeId = "LRL"; + String locationName = "Glensboro"; + String[] parameter = { "Depth", "Temp-Water"}; + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameter[0], parameter); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + TimeSeriesProfileParserIndexed timeSeriesProfileParser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameter[0]); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser( timeSeriesProfileParser, false); + + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId()); + + assertThrows(Exception.class, () -> timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser( + timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId())); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testCatalogTimeSeriesProfileInclusive() throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + String officeId = "LRL"; + String locationName = "Glensboro"; + String[] parameters = {"Depth", "Temp-Water"}; + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + List timeSeriesProfileList = new ArrayList<>(); + for(String parameter : parameters) { + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameter, parameters); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + timeSeriesProfileList.add(timeSeriesProfile); + } + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + + + for(String parameter : parameters) { + TimeSeriesProfileParserIndexed timeSeriesProfileParser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameter); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(timeSeriesProfileParser, false); + } + + List profileParserList = timeSeriesProfileParserDao.catalogTimeSeriesProfileParsers("*", "*", "*",true); + for (TimeSeriesProfileParser profileParser : profileParserList) { + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(profileParser.getLocationId().getName(), profileParser.getKeyParameter(), profileParser.getLocationId().getOfficeId()); + } + + for(TimeSeriesProfile timeSeriesProfile : timeSeriesProfileList) { + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + } + + assertEquals(2, profileParserList.size()); + assertEquals(2, profileParserList.get(0).getParameterInfoList().size() ); + assertEquals(2, profileParserList.get(1).getParameterInfoList().size() ); + }, CwmsDataApiSetupCallback.getWebUser()); + + } + @Test + void testStoreAndRetrieveMultiple() throws SQLException { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + String officeId = "LRL"; + String locationName = "Glensboro"; + String[] parameters = {"Depth", "Temp-Water"}; + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + List timeSeriesProfileList = new ArrayList<>(); + for(String parameter : parameters) { + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameter, parameters); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + timeSeriesProfileList.add(timeSeriesProfile); + } + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + + + for(String parameter : parameters) { + TimeSeriesProfileParserIndexed timeSeriesProfileParser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameter); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(timeSeriesProfileParser, false); + } + + List profileParserList = timeSeriesProfileParserDao.catalogTimeSeriesProfileParsers("*", "*", "*"); + for (TimeSeriesProfileParser profileParser : profileParserList) { + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(profileParser.getLocationId().getName(), profileParser.getKeyParameter(), profileParser.getLocationId().getOfficeId()); + } + + for(TimeSeriesProfile timeSeriesProfile : timeSeriesProfileList) { + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId().getName(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getLocationId().getOfficeId()); + } + + assertEquals(2, profileParserList.size()); + }, CwmsDataApiSetupCallback.getWebUser()); + } + + @Test + void testStoreAndCopy() throws SQLException { + String officeId = "LRL"; + String locationName = "Glensboro"; + String locationName1 = "Greensburg"; + String[] parameter = {"Depth", "Temp-Water"}; + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName, parameter[0], parameter); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + timeSeriesProfile = buildTestTimeSeriesProfile(officeId, locationName1, parameter[0], parameter); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + TimeSeriesProfileParserIndexed timeSeriesProfileParser = buildTestTimeSeriesProfileParserIndexed(officeId, locationName, parameter[0]); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser( timeSeriesProfileParser, false); + + TimeSeriesProfileParser retrieved = timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId()); + + timeSeriesProfileParserDao.copyTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId().getName(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId(), locationName1); + + TimeSeriesProfileParser retrieved1 = timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser(locationName1, + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getLocationId().getOfficeId()); + assertEquals(timeSeriesProfileParser.getKeyParameter(), retrieved.getKeyParameter()); + assertEquals(locationName1, retrieved1.getLocationId().getName()); + assertEquals(timeSeriesProfileParser.getTimeFormat(), retrieved1.getTimeFormat()); + + }, CwmsDataApiSetupCallback.getWebUser()); + } + + private static TimeSeriesProfile buildTestTimeSeriesProfile(String officeId, String location, String keyParameter, String[] parameters) { + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(location).build(); + return new TimeSeriesProfile.Builder() + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withParameterList(Arrays.asList(parameters)) + .build(); + + } + + static private TimeSeriesProfileParserIndexed buildTestTimeSeriesProfileParserIndexed(String officeId, String location, String keyParameter) { + List parameterInfoList = new ArrayList<>(); + parameterInfoList.add(new ParameterInfoIndexed.Builder() + .withIndex(6) + .withParameter("Depth") + .withUnit("m") + .build()); + parameterInfoList.add(new ParameterInfoIndexed.Builder() + .withIndex(5) + .withParameter("Pres") + .withUnit("bar") + .build()); + CwmsId locationId = new CwmsId.Builder().withOfficeId(officeId).withName(location).build(); + return + (TimeSeriesProfileParserIndexed) + new TimeSeriesProfileParserIndexed.Builder() + .withFieldDelimiter(',') + .withTimeField(1) + .withLocationId(locationId) + .withKeyParameter(keyParameter) + .withRecordDelimiter((char) 10) + .withTimeFormat("MM/DD/YYYY,HH24:MI:SS") + .withTimeZone("UTC") + .withTimeInTwoFields(true) + .withParameterInfoList(parameterInfoList) + .build(); + } + + +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java new file mode 100644 index 000000000..7d16ce7e0 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java @@ -0,0 +1,81 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import cwms.cda.formatters.ContentType; +import cwms.cda.formatters.Formats; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ParameterInfoTest { + @Test + void testParameterInfoColumnarRoundTrip() { + ParameterInfo parameterInfo = buildParameterInfoColumnar(); + ContentType contentType = Formats.parseHeader(Formats.JSONV2, ParameterInfoColumnar.class); + String serialized = Formats.format(contentType, parameterInfo); + ParameterInfoColumnar deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, ParameterInfoColumnar.class), serialized, ParameterInfoColumnar.class); + testAssertEquals((ParameterInfoColumnar)parameterInfo, deserialized, "Roundtrip serialization failed"); + } + @Test + void testParameterInfoIndexedRoundTrip() { + ParameterInfo parameterInfo = buildParameterInfoIndexed(); + ContentType contentType = Formats.parseHeader(Formats.JSONV2, ParameterInfoIndexed.class); + String serialized = Formats.format(contentType, parameterInfo); + ParameterInfoIndexed deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, ParameterInfoIndexed.class), serialized, ParameterInfoIndexed.class); + testAssertEquals((ParameterInfoIndexed) parameterInfo, deserialized, "Roundtrip serialization failed"); + } + + @Test + void testParameterInfoColumnarRoundTripFromFile() throws Exception { + ParameterInfo parameterInfo = buildParameterInfoColumnar(); + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/parameterinfocolumnar.json"); + assertNotNull(resource); + String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); + ParameterInfoColumnar deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, ParameterInfoColumnar.class), serialized, ParameterInfoColumnar.class); + testAssertEquals((ParameterInfoColumnar)parameterInfo, deserialized, "Roundtrip serialization from file failed"); + } + @Test + void testParameterInfoIndexedRoundTripFromFile() throws Exception { + ParameterInfo parameterInfo = buildParameterInfoIndexed(); + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/parameterinfoindexed.json"); + assertNotNull(resource); + String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); + ParameterInfoIndexed deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, ParameterInfoIndexed.class), serialized, ParameterInfoIndexed.class); + testAssertEquals((ParameterInfoIndexed)parameterInfo, deserialized, "Roundtrip serialization from file failed"); + } + + static ParameterInfo buildParameterInfoColumnar() { + return new ParameterInfoColumnar.Builder() + .withEndColumn(20) + .withStartColumn(10) + .withParameter("Depth") + .withUnit("m") + .build(); + } + static ParameterInfo buildParameterInfoIndexed() { + return new ParameterInfoIndexed.Builder() + .withIndex(1) + .withParameter("Depth") + .withUnit("m") + .build(); + } + + static void testAssertEquals(ParameterInfoColumnar expected, ParameterInfoColumnar actual, String message) { + assertEquals(expected.getParameter(), actual.getParameter(), message); + assertEquals(expected.getParameterInfoString(), actual.getParameterInfoString(), message); + assertEquals(expected.getStartColumn(), actual.getStartColumn(), message); + assertEquals(expected.getEndColumn(), actual.getEndColumn(), message); + assertEquals(expected.getUnit(), actual.getUnit(), message); + } + static void testAssertEquals(ParameterInfoIndexed expected, ParameterInfoIndexed actual, String message) { + assertEquals(expected.getParameter(), actual.getParameter(), message); + assertEquals(expected.getParameterInfoString(), actual.getParameterInfoString(), message); + assertEquals(expected.getIndex(), actual.getIndex(), message); + assertEquals(expected.getUnit(), actual.getUnit(), message); + } + +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java new file mode 100644 index 000000000..9632fe73b --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java @@ -0,0 +1,108 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import cwms.cda.formatters.ContentType; +import cwms.cda.formatters.Formats; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class TimeSeriesProfileInstanceTest { + private static final Map PARAMETER_UNIT_MAP = new HashMap<>(); + @BeforeAll + public static void setup() { + PARAMETER_UNIT_MAP.put("Depth", "ft"); + PARAMETER_UNIT_MAP.put("Temp-Water", "F"); + } + @Test + void testTimeSeriesProfileInstanceSerializationRoundTrip() { + TimeSeriesProfileInstance timeSeriesProfileInstance = buildTestTimeSeriesProfileInstance(); + ContentType contentType = Formats.parseHeader(Formats.JSONV2, TimeSeriesProfileInstance.class); + + String serialized = Formats.format(contentType, timeSeriesProfileInstance); + TimeSeriesProfileInstance deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, TimeSeriesProfileInstance.class), serialized, TimeSeriesProfileInstance.class); + testAssertEquals(timeSeriesProfileInstance, deserialized, "Roundtrip serialization failed"); + } + @Test + void testTimeSeriesProfileInstanceSerializationRoundTripFromFile() throws Exception { + TimeSeriesProfileInstance timeSeriesProfileInstance = buildTestTimeSeriesProfileInstance(); + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json"); + assertNotNull(resource); + String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); + TimeSeriesProfileInstance deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2, TimeSeriesProfileInstance.class), serialized, TimeSeriesProfileInstance.class); + testAssertEquals(timeSeriesProfileInstance, deserialized, "Roundtrip serialization from file failed"); + } + + private TimeSeriesProfileInstance buildTestTimeSeriesProfileInstance() { + TimeSeriesProfile timeSeriesProfile = TimeSeriesProfileTest.buildTestTimeSeriesProfile(); + List timeSeriesList = buildTimeSeriesList(timeSeriesProfile.getParameterList()); + return new TimeSeriesProfileInstance.Builder() + .withTimeSeriesProfile(timeSeriesProfile) + .withTimeSeriesList(timeSeriesList) + .withFirstDate(Instant.parse("2020-07-09T12:00:00.00Z")) + .withLastDate(Instant.parse("2025-07-09T12:00:00.00Z")) + .build(); + } + + private List buildTimeSeriesList(List parameterList) { + List timeSeriesList = new ArrayList<>(); + for(String parameter : parameterList) + { + ProfileTimeSeries profileTimeSeries = new ProfileTimeSeries.Builder() + .withParameter(parameter) + .withUnit(PARAMETER_UNIT_MAP.get(parameter)) + .withTimeZone("PST") + .withValues(buildTimeValueList()) + .build(); + timeSeriesList.add(profileTimeSeries); + } + return timeSeriesList; + } + + private List buildTimeValueList() { + List timeValueList = new ArrayList<>(); + timeValueList.add( new TimeValuePair.Builder().withValue(1.0).withDateTime(Instant.parse("2021-02-09T11:19:42.12Z")).build()); + timeValueList.add( new TimeValuePair.Builder().withValue(3.0).withDateTime(Instant.parse("2021-02-09T11:19:42.22Z")).build()); + return timeValueList; + } + + private void testAssertEquals(TimeSeriesProfileInstance expected, TimeSeriesProfileInstance actual, String message) { + TimeSeriesProfileTest.testAssertEquals(expected.getTimeSeriesProfile(), actual.getTimeSeriesProfile(), message); + testAssertEquals(expected.getTimeSeriesList(), actual.getTimeSeriesList(), message); + assertEquals(expected.getFirstDate(), actual.getFirstDate()); + assertEquals(expected.getLastDate(), actual.getLastDate()); + } + + private void testAssertEquals(List expected, List actual, String message) { + assertEquals(expected.size(), actual.size(), message); + for (int i = 0; i < expected.size(); i++) { + testAssertEquals(expected.get(i), actual.get(i), message); + } + } + + private void testAssertEquals(ProfileTimeSeries expected, ProfileTimeSeries actual, String message) { + assertEquals(expected.getTimeZone(), actual.getTimeZone(), message); + assertEquals(expected.getParameter(), actual.getParameter(), message); + assertEquals(expected.getUnit(),actual.getUnit(), message); + testAssertEquals(expected.getValues(), actual.getValues()); + } + + private void testAssertEquals(List expected, List actual) { + assertEquals(expected.size(), actual.size()); + for(int i=0;i parameterInfo = new ArrayList<>(); + parameterInfo.add(new ParameterInfoColumnar.Builder() + .withStartColumn(11) + .withEndColumn(20) + .withParameter("Depth") + .withUnit("m") + .build()); + parameterInfo.add(new ParameterInfoColumnar.Builder() + .withStartColumn(21) + .withEndColumn(30) + .withParameter("Temp-Water") + .withUnit("F") + .build()); + CwmsId locationId = new CwmsId.Builder() + .withOfficeId("SWT") + .withName("location") + .build(); + return (TimeSeriesProfileParserColumnar) + new TimeSeriesProfileParserColumnar.Builder() + .withTimeStartColumn(1) + .withTimeEndColumn(10) + .withLocationId(locationId) + .withKeyParameter("Depth") + .withRecordDelimiter((char) 10) + .withTimeFormat("MM/DD/YYYY,HH24:MI:SS") + .withTimeZone("UTC") + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfo) + .build(); + } + private static TimeSeriesProfileParser buildTestTimeSeriesProfileParserIndexed() { + List parameterInfo = new ArrayList<>(); + parameterInfo.add(new ParameterInfoIndexed.Builder() + .withIndex(3) + .withParameter("Depth") + .withUnit("m") + .build()); + parameterInfo.add(new ParameterInfoIndexed.Builder() + .withIndex(5) + .withParameter("Temp-Water") + .withUnit("F") + .build()); + CwmsId locationId = new CwmsId.Builder() + .withOfficeId("SWT") + .withName("location") + .build(); + return + new TimeSeriesProfileParserIndexed.Builder() + .withTimeField(1) + .withFieldDelimiter(',') + .withLocationId(locationId) + .withKeyParameter("Depth") + .withRecordDelimiter((char) 10) + .withTimeFormat("MM/DD/YYYY,HH24:MI:SS") + .withTimeZone("UTC") + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfo) + .build(); + } + + private void testAssertEquals(TimeSeriesProfileParserColumnar expected, TimeSeriesProfileParserColumnar actual, String message) { + assertEquals(expected.getLocationId().getName(), actual.getLocationId().getName(), message); + assertEquals(expected.getLocationId().getOfficeId(), actual.getLocationId().getOfficeId(), message); + assertEquals(expected.getLocationId().getName(), actual.getLocationId().getName(), message); + assertEquals(expected.getLocationId().getOfficeId(), actual.getLocationId().getOfficeId(), message); + assertEquals(expected.getKeyParameter(), actual.getKeyParameter(), message); + assertEquals(expected.getTimeFormat(), actual.getTimeFormat(), message); + testAssertEquals(expected.getParameterInfoList(), actual.getParameterInfoList(),message); + assertEquals(expected.getRecordDelimiter(), actual.getRecordDelimiter(), message); + assertEquals(expected.getTimeZone(), actual.getTimeZone()); + assertEquals(expected.getTimeInTwoFields(), actual.getTimeInTwoFields()); + assertEquals(expected.getTimeEndColumn(), actual.getTimeEndColumn()); + assertEquals(expected.getTimeStartColumn(), actual.getTimeStartColumn()); + } + private void testAssertEquals(TimeSeriesProfileParserIndexed expected, TimeSeriesProfileParserIndexed actual, String message) { + assertEquals(expected.getLocationId().getName(), actual.getLocationId().getName(), message); + assertEquals(expected.getLocationId().getOfficeId(), actual.getLocationId().getOfficeId(), message); + assertEquals(expected.getLocationId().getName(), actual.getLocationId().getName(), message); + assertEquals(expected.getLocationId().getOfficeId(), actual.getLocationId().getOfficeId(), message); + assertEquals(expected.getKeyParameter(), actual.getKeyParameter(), message); + assertEquals(expected.getTimeFormat(), actual.getTimeFormat(), message); + testAssertEquals(expected.getParameterInfoList(), actual.getParameterInfoList(),message); + assertEquals(expected.getRecordDelimiter(), actual.getRecordDelimiter(), message); + assertEquals(expected.getTimeZone(), actual.getTimeZone()); + assertEquals(expected.getTimeInTwoFields(), actual.getTimeInTwoFields()); + assertEquals(expected.getTimeField(), actual.getTimeField()); + assertEquals(expected.getFieldDelimiter(), actual.getFieldDelimiter()); + } + private void testAssertEquals(List expected, List actual, String message) { + assertEquals(expected.size(), actual.size()); + for(int i=0;i