Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enhance TimeSeriesSource with method to retrieve the previous value before a given key. #1183

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Enhance `TimeSeriesSource` with method to retrieve all time keys after a given key [#543](https://github.com/ie3-institute/PowerSystemDataModel/issues/543)
- Enhance `WeatherSource` with method to retrieve all time keys after a given key [#572](https://github.com/ie3-institute/PowerSystemDataModel/issues/572)
- Enhance `TimeSeriesSource` with method to retrieve the previous value before a given key [#1182](https://github.com/ie3-institute/PowerSystemDataModel/issues/1182)

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ protected Try<TimeBasedValue<V>, FactoryException> createTimeBasedValue(
public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTime> timeInterval)
throws SourceException;

public abstract Optional<V> getValue(ZonedDateTime time) throws SourceException;
public abstract Optional<V> getValue(ZonedDateTime time);

public abstract Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time);

/**
* Method to return all time keys after a given timestamp.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ public Optional<V> getValue(ZonedDateTime time) {
return timeSeries.getValue(time);
}

@Override
public Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time) {
return timeSeries.getPreviousTimeBasedValue(time);
}

public Optional<TimeBasedValue<V>> getNextTimeBasedValue(ZonedDateTime time) {
return timeSeries.getNextTimeBasedValue(time);
}

@Override
public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
return timeSeries.getTimeKeysAfter(time);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

private final String queryTimeInterval;
private final String queryTimeKeysAfter;
private final String queryForValueBefore;
private final String queryTime;

public SqlTimeSeriesSource(
Expand All @@ -63,15 +64,16 @@
final ColumnScheme columnScheme = ColumnScheme.parse(valueClass).orElseThrow();
this.tableName = sqlDataSource.databaseNamingStrategy.getTimeSeriesEntityName(columnScheme);

String schemaName = sqlDataSource.schemaName;

String dbTimeColumnName =
sqlDataSource.getDbColumnName(factory.getTimeFieldString(), tableName);

this.queryFull = createQueryFull(sqlDataSource.schemaName, tableName);
this.queryTimeInterval =
createQueryForTimeInterval(sqlDataSource.schemaName, tableName, dbTimeColumnName);
this.queryTimeKeysAfter =
createQueryForTimeKeysAfter(sqlDataSource.schemaName, tableName, dbTimeColumnName);
this.queryTime = createQueryForTime(sqlDataSource.schemaName, tableName, dbTimeColumnName);
this.queryFull = createQueryFull(schemaName, tableName);
this.queryTimeInterval = createQueryForTimeInterval(schemaName, tableName, dbTimeColumnName);
this.queryTimeKeysAfter = createQueryForTimeKeysAfter(schemaName, tableName, dbTimeColumnName);
this.queryForValueBefore = createQueryForValueBefore(schemaName, tableName, dbTimeColumnName);
this.queryTime = createQueryForTime(schemaName, tableName, dbTimeColumnName);
}

/**
Expand Down Expand Up @@ -179,6 +181,14 @@
return Optional.of(timeBasedValues.stream().toList().get(0).getValue());
}

@Override
public Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time) {
return getTimeBasedValueSet(
queryForValueBefore, ps -> ps.setTimestamp(1, Timestamp.from(time.toInstant())))
.stream()
.max(TimeBasedValue::compareTo);
}

@Override
public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
return dataSource
Expand Down Expand Up @@ -247,7 +257,7 @@
+ TIME_SERIES
+ " = '"
+ timeSeriesUuid.toString()
+ "' AND "

Check failure on line 260 in src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesSource.java

View check run for this annotation

SonarQubeGithubPRChecks / PowerSystemDataModel Sonarqube Results

src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesSource.java#L260

Define a constant instead of duplicating this literal "' AND " 4 times.
+ timeColumnName
+ " BETWEEN ? AND ?;";
}
Expand Down Expand Up @@ -278,8 +288,30 @@
}

/**
* Creates a basic query to retrieve an entry for the given time series uuid and time with the
* following pattern: <br>
* Creates a base query to retrieve all time keys after a given time for given time series with
* the following pattern: <br>
* {@code <base query> WHERE time_series = $timeSeriesUuid AND <time column> < ?;}
*
* @param schemaName the name of the database schema
* @param tableName the name of the database table
* @param timeColumnName the name of the column holding the timestamp info
* @return the query string
*/
private String createQueryForValueBefore(
String schemaName, String tableName, String timeColumnName) {
return createBaseQueryString(schemaName, tableName)
+ WHERE
+ TIME_SERIES
+ " = '"
+ timeSeriesUuid.toString()
+ "' AND "
+ timeColumnName
+ " < ?"
+ "ORDER BY time DESC LIMIT 1;";
}
/**
* Creates a base query to retrieve all time keys before a given time for given time series with
* the following pattern: <br>
* {@code <base query> WHERE time_series = $timeSeriesUuid AND <time column>=?;}
*
* @param schemaName the name of the database schema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ public Optional<V> getValue(ZonedDateTime time) {
@Override
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
return timeToValue.keySet().stream()
.filter(valueTime -> valueTime.compareTo(time) <= 0)
.filter(valueTime -> valueTime.compareTo(time) < 0)
.max(Comparator.naturalOrder());
}

@Override
protected Optional<ZonedDateTime> getNextDateTime(ZonedDateTime time) {
return timeToValue.keySet().stream()
.filter(valueTime -> valueTime.compareTo(time) >= 0)
.filter(valueTime -> valueTime.compareTo(time) > 0)
.min(Comparator.naturalOrder());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ public PValue calc(ZonedDateTime time) {
@Override
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
// dummy value
return Optional.of(time.minusHours(1));
return Optional.of(time.minusMinutes(15));
}

@Override
protected Optional<ZonedDateTime> getNextDateTime(ZonedDateTime time) {
// dummy value
return Optional.of(time.plusHours(1));
return Optional.of(time.plusMinutes(15));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,24 @@ class CsvTimeSeriesSourceIT extends Specification implements CsvTestDataMeta {
actual.present
actual.get() == PH_VALUE_15MIN
}

def "A csv time series source is able to return the previous value for a given time"() {
when:
def actual = source.getPreviousTimeBasedValue(TIME_15MIN)

then:
actual.isPresent()
actual.get().time == TIME_00MIN
actual.get().value == PH_VALUE_00MIN
}

def "A csv time series source is able to return the next value for a given time"() {
when:
def actual = source.getNextTimeBasedValue(TIME_00MIN)

then:
actual.isPresent()
actual.get().time == TIME_15MIN
actual.get().value == PH_VALUE_15MIN
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import edu.ie3.datamodel.io.connectors.SqlConnector
import edu.ie3.datamodel.io.naming.DatabaseNamingStrategy
import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme
import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation
import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue
import edu.ie3.datamodel.models.value.*
import edu.ie3.test.helper.TestContainerHelper
import edu.ie3.util.TimeUtil
Expand Down Expand Up @@ -123,6 +124,21 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
value.get() == P_VALUE_00MIN
}

def "A SqlTimeSeriesSource is able to return the previous value for a given time"() {
when:
def actual = pSource.getPreviousTimeBasedValue(time)

then:
actual.isPresent() == expectedResult.isPresent()
actual == expectedResult

where:
time | expectedResult
TIME_00MIN | Optional.empty()
TIME_15MIN | Optional.of(new TimeBasedValue<>(TIME_00MIN, P_VALUE_00MIN))
TIME_30MIN | Optional.of(new TimeBasedValue<>(TIME_15MIN, P_VALUE_15MIN))
}

def "A SqlTimeSeriesSource can read multiple time series values for a time interval"() {
given:
def timeInterval = new ClosedInterval(TIME_00MIN, TIME_15MIN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class IndividualTimeSeriesTest extends Specification implements TimeSeriesTestDa
Optional<TimeBasedValue<IntValue>> expected = Optional.of(new TimeBasedValue<>(ZonedDateTime.of(1990, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), new IntValue(3)))

when:
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getPreviousTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")))
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getPreviousTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 5, 0, 0, ZoneId.of("UTC")))

then:
expected.present
Expand Down Expand Up @@ -103,7 +103,7 @@ class IndividualTimeSeriesTest extends Specification implements TimeSeriesTestDa
Optional<TimeBasedValue<IntValue>> expected = Optional.of(new TimeBasedValue<>(ZonedDateTime.of(1990, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")), new IntValue(4)))

when:
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getNextTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")))
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getNextTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 10, 0, 0, ZoneId.of("UTC")))

then:
expected.present
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ final class TimeSeriesSourceTestData {

public static final ZonedDateTime TIME_00MIN = ZonedDateTime.parse("2020-01-01T00:00:00Z")
public static final ZonedDateTime TIME_15MIN = ZonedDateTime.parse("2020-01-01T00:15:00Z")
public static final ZonedDateTime TIME_30MIN = ZonedDateTime.parse("2020-01-01T00:30:00Z")

public static final PValue P_VALUE_00MIN = new PValue(
Quantities.getQuantity(1000.0d, StandardUnits.ACTIVE_POWER_IN)
Expand Down