diff --git a/backend/src/main/java/com/bakdata/conquery/models/common/CDateSet.java b/backend/src/main/java/com/bakdata/conquery/models/common/CDateSet.java index bbeeb1f3a1..59011b6108 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/common/CDateSet.java +++ b/backend/src/main/java/com/bakdata/conquery/models/common/CDateSet.java @@ -271,7 +271,11 @@ private void putRange(CDateRange range) { } - public void maskedAdd(CDateRange toAdd, CDateSet mask){ + public void maskedAdd(CDateRange toAdd, CDateSet mask) { + maskedAdd(toAdd, mask, CDateRange.POSITIVE_INFINITY); + } + + public void maskedAdd(CDateRange toAdd, CDateSet mask, int truncateMax){ if(mask.isEmpty()){ return; } @@ -317,27 +321,29 @@ public void maskedAdd(CDateRange toAdd, CDateSet mask){ search = mask.rangesByLowerBound.higherKey(search); - int min = range.getMinValue(); - int max = range.getMaxValue(); + int lowerBound = range.getMinValue(); + int upperBound = range.getMaxValue(); - if(max < toAdd.getMinValue()){ + if(upperBound < toAdd.getMinValue()){ continue; } - if(min < toAdd.getMinValue()){ - min = toAdd.getMinValue(); + if(lowerBound < toAdd.getMinValue()){ + lowerBound = toAdd.getMinValue(); } - if(max > toAdd.getMaxValue()){ - max = toAdd.getMaxValue(); + if(upperBound > toAdd.getMaxValue()){ + upperBound = toAdd.getMaxValue(); } + upperBound = Math.min(upperBound, truncateMax); + // value was not contained - if(min > max){ + if(lowerBound > upperBound){ continue; } - add(CDateRange.of(min, max)); + add(CDateRange.of(lowerBound, upperBound)); } } diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/QueryExecutionContext.java b/backend/src/main/java/com/bakdata/conquery/models/query/QueryExecutionContext.java index f0afe24756..5b912ef6a8 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/QueryExecutionContext.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/QueryExecutionContext.java @@ -1,14 +1,16 @@ package com.bakdata.conquery.models.query; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import com.bakdata.conquery.io.storage.ModificationShieldedWorkerStorage; +import com.bakdata.conquery.models.common.CDate; import com.bakdata.conquery.models.common.CDateSet; -import com.bakdata.conquery.models.datasets.concepts.Connector; import com.bakdata.conquery.models.datasets.Column; import com.bakdata.conquery.models.datasets.SecondaryIdDescription; import com.bakdata.conquery.models.datasets.Table; +import com.bakdata.conquery.models.datasets.concepts.Connector; import com.bakdata.conquery.models.events.Bucket; import com.bakdata.conquery.models.events.BucketManager; import com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId; @@ -44,6 +46,8 @@ public class QueryExecutionContext { */ private SecondaryIdDescription activeSecondaryId = null; + private final int today = CDate.ofLocalDate(LocalDate.now()); + public List getEntityBucketsForTable(Entity entity, Table table) { return bucketManager.getEntityBucketsForTable(entity, table); } diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DateUnionAggregator.java b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DateUnionAggregator.java index 7060acef63..3032d83582 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DateUnionAggregator.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DateUnionAggregator.java @@ -20,6 +20,8 @@ public class DateUnionAggregator extends SingleColumnAggregator { private CDateSet set = CDateSet.create(); private CDateSet dateRestriction; + private int realUpperBound; + public DateUnionAggregator(Column column) { super(column); } @@ -27,6 +29,7 @@ public DateUnionAggregator(Column column) { @Override public void init(Entity entity, QueryExecutionContext context) { set.clear(); + realUpperBound = context.getToday(); } @Override @@ -40,13 +43,9 @@ public void acceptEvent(Bucket bucket, int event) { return; } - CDateRange value = bucket.getAsDateRange(event, getColumn()); - //otherwise the result would be something weird - if (value.isOpen()) { - return; - } + final CDateRange value = bucket.getAsDateRange(event, getColumn()); - set.maskedAdd(value, dateRestriction); + set.maskedAdd(value, dateRestriction, realUpperBound); } @Override diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DurationSumAggregator.java b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DurationSumAggregator.java index e396e5776b..4c25c8db35 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DurationSumAggregator.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/DurationSumAggregator.java @@ -1,5 +1,6 @@ package com.bakdata.conquery.models.query.queryplan.aggregators.specific; +import com.bakdata.conquery.models.common.CDate; import com.bakdata.conquery.models.common.CDateSet; import com.bakdata.conquery.models.common.daterange.CDateRange; import com.bakdata.conquery.models.datasets.Column; @@ -20,6 +21,8 @@ public class DurationSumAggregator extends SingleColumnAggregator { private CDateSet set = CDateSet.create(); private CDateSet dateRestriction; + private int realUpperBound; + public DurationSumAggregator(Column column) { super(column); } @@ -27,6 +30,7 @@ public DurationSumAggregator(Column column) { @Override public void init(Entity entity, QueryExecutionContext context) { set.clear(); + realUpperBound = context.getToday(); } @Override @@ -42,17 +46,15 @@ public void acceptEvent(Bucket bucket, int event) { final CDateRange value = bucket.getAsDateRange(event, getColumn()); - if (value.isOpen()) { - return; - } - - - set.maskedAdd(value, dateRestriction); + set.maskedAdd(value, dateRestriction, realUpperBound); } @Override public Long createAggregationResult() { - return set.isEmpty() ? null : set.countDays(); + if (set.isEmpty() || CDate.isNegativeInfinity(set.getMinValue())) { + return null; + } + return set.countDays(); } @Override diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/EventDurationSumAggregator.java b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/EventDurationSumAggregator.java index 21a39258c5..32f85d6269 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/EventDurationSumAggregator.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/EventDurationSumAggregator.java @@ -21,17 +21,18 @@ @ToString(onlyExplicitlyIncluded = true) public class EventDurationSumAggregator extends Aggregator { - private Optional> queryDateAggregator = Optional.empty(); private final CDateSet set = CDateSet.create(); - + private Optional> queryDateAggregator = Optional.empty(); @CheckForNull private CDateSet dateRestriction; @CheckForNull private Column validityDateColumn; + private int realUpperBound; @Override public void init(Entity entity, QueryExecutionContext context) { set.clear(); + realUpperBound = context.getToday(); } @Override @@ -53,12 +54,8 @@ public void acceptEvent(Bucket bucket, int event) { final CDateRange value = bucket.getAsDateRange(event, validityDateColumn); - if (value.isOpen()) { - return; - } - - set.maskedAdd(value, dateRestriction); + set.maskedAdd(value, dateRestriction, realUpperBound); } @Override diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/QuarterAggregator.java b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/QuarterAggregator.java index 302d01fa50..fd314ea415 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/QuarterAggregator.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/QuarterAggregator.java @@ -33,6 +33,8 @@ public class QuarterAggregator extends Aggregator { private Column column; + private int realUpperBound; + public QuarterAggregator(TemporalSamplerFactory samplerFactory) { this.samplerFactory = samplerFactory; } @@ -41,6 +43,7 @@ public QuarterAggregator(TemporalSamplerFactory samplerFactory) { public void init(Entity entity, QueryExecutionContext context) { set.clear(); sampler = samplerFactory.sampler(); + realUpperBound = context.getToday(); } @Override @@ -57,11 +60,7 @@ public void acceptEvent(Bucket bucket, int event) { final CDateRange value = bucket.getAsDateRange(event, getColumn()); - if (value.isOpen()) { - return; - } - - set.maskedAdd(value, dateRestriction); + set.maskedAdd(value, dateRestriction, realUpperBound); } @Override @@ -70,13 +69,19 @@ public String createAggregationResult() { return null; } - final OptionalInt sampled = sampler.sample(set); + final OptionalInt maybeSampled = sampler.sample(set); + + if (maybeSampled.isEmpty()) { + return null; + } + + final int sampled = maybeSampled.getAsInt(); - if (sampled.isEmpty()) { + if (CDate.isNegativeInfinity(sampled) || CDate.isPositiveInfinity(sampled)) { return null; } - final LocalDate date = CDate.toLocalDate(sampled.getAsInt()); + final LocalDate date = CDate.toLocalDate(sampled); final int quarter = QuarterUtils.getQuarter(date); final int year = date.getYear(); diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/SpecialDateUnion.java b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/SpecialDateUnion.java index 05a4e00dd6..7527c870de 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/SpecialDateUnion.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/queryplan/aggregators/specific/SpecialDateUnion.java @@ -37,21 +37,20 @@ public void nextTable(QueryExecutionContext ctx, Table table) { @Override public void acceptEvent(Bucket bucket, int event) { - if (currentColumn != null && bucket.has(event, currentColumn)) { - set.maskedAdd(bucket.getAsDateRange(event, currentColumn), dateRestriction); + if (currentColumn == null || !bucket.has(event, currentColumn)) { + set.addAll(dateRestriction); return; } - if(!dateRestriction.isEmpty()) { - set.addAll(dateRestriction); - } + set.maskedAdd(bucket.getAsDateRange(event, currentColumn), dateRestriction); } /** * Helper method to insert dates from outside. + * * @param other CDateSet to be included. */ - public void merge(CDateSet other){ + public void merge(CDateSet other) { set.addAll(other); } diff --git a/backend/src/main/java/com/bakdata/conquery/util/DateReader.java b/backend/src/main/java/com/bakdata/conquery/util/DateReader.java index ca97532492..b94004a5b7 100644 --- a/backend/src/main/java/com/bakdata/conquery/util/DateReader.java +++ b/backend/src/main/java/com/bakdata/conquery/util/DateReader.java @@ -24,27 +24,14 @@ /** * Utility class for parsing multiple date-formats. - * + *

* We cache successfully parsed dates, hoping to achieve a speedup that way. - * + *

* We also assume that date-formats do not change over the course of parsing and use the last successfully parsed format as candidate for parsing other values. - * */ @Slf4j public class DateReader { - /** - * All available formats for parsing. - */ - @JsonIgnore - private List dateFormats; - - @JsonIgnore - private List rangeStartEndSeperators; - - @JsonIgnore - private List dateSetLayouts; - /** * Index of the last successfully parsed date format in dateFormats. */ @@ -55,16 +42,18 @@ public class DateReader { */ @JsonIgnore private final ThreadLocal lastRangeFormatIndex = ThreadLocal.withInitial(() -> 0); - /** * Index of the last successfully parsed dateset format in dateSetLayouts */ @JsonIgnore private final ThreadLocal lastDateSetLayoutIndex = ThreadLocal.withInitial(() -> 0); - @JsonIgnore private final LocalDate ERROR_DATE = LocalDate.MIN; - + /** + * All available formats for parsing. + */ + @JsonIgnore + private List dateFormats; /** * Parsed values cache. */ @@ -73,6 +62,10 @@ public class DateReader { .weakValues() .concurrencyLevel(10) .build(CacheLoader.from(this::tryParseDate)); + @JsonIgnore + private List rangeStartEndSeperators; + @JsonIgnore + private List dateSetLayouts; @JsonCreator public DateReader(Set dateParsingFormats, List rangeStartEndSeperators, List dateSetLayouts) { @@ -81,23 +74,6 @@ public DateReader(Set dateParsingFormats, List rangeStartEndSepe this.dateSetLayouts = dateSetLayouts; } - /** - * Try parsing the String value to a LocalDate. - */ - public LocalDate parseToLocalDate(String value) throws ParsingException { - if (Strings.isNullOrEmpty(value)) { - return null; - } - - final LocalDate out = DATE_CACHE.getUnchecked(value); - - if (out.equals(ERROR_DATE)) { - throw new ParsingException(String.format("Failed to parse `%s` as LocalDate.", value)); - } - - return out; - } - /** * Try and parse value to {@link CDateRange} using all available rangeFormats, starting at the last known successful one. */ @@ -130,8 +106,19 @@ public CDateRange parseToCDateRange(String value) { */ private CDateRange parseToCDateRange(String value, String sep) { + // Shorthand formats for open ranges without resorting to two-column formats + if (value.startsWith(sep)) { + return CDateRange.atMost(parseToLocalDate(value.substring(sep.length()))); + } + + if (value.endsWith(sep)) { + return CDateRange.atMost(parseToLocalDate(value.substring(0, value.length() - sep.length()))); + } + + String[] parts = StringUtils.split(value, sep); + if (parts.length == 1) { // If it looks like a single date, try to parse it at one return CDateRange.exactly(parseToLocalDate(parts[0])); @@ -147,6 +134,23 @@ private CDateRange parseToCDateRange(String value, String sep) { throw ParsingException.of(value, String.format("DateRange: Unexpected length of Parts (%d) for `%s` using sep=`%s`", parts.length, value, sep)); } + /** + * Try parsing the String value to a LocalDate. + */ + public LocalDate parseToLocalDate(String value) throws ParsingException { + if (Strings.isNullOrEmpty(value)) { + return null; + } + + final LocalDate out = DATE_CACHE.getUnchecked(value); + + if (out.equals(ERROR_DATE)) { + throw new ParsingException(String.format("Failed to parse `%s` as LocalDate.", value)); + } + + return out; + } + /** * Try and parse value to CDateSet using all available layouts, but starting at the last known successful one. */ diff --git a/backend/src/test/java/com/bakdata/conquery/integration/common/CDateSetTest.java b/backend/src/test/java/com/bakdata/conquery/integration/common/CDateSetTest.java index 3203cfacb0..aa01ddc0c1 100644 --- a/backend/src/test/java/com/bakdata/conquery/integration/common/CDateSetTest.java +++ b/backend/src/test/java/com/bakdata/conquery/integration/common/CDateSetTest.java @@ -3,14 +3,12 @@ import static org.assertj.core.api.Assertions.assertThat; import java.time.LocalDate; -import java.util.Arrays; import java.util.List; import java.util.stream.Stream; import com.bakdata.conquery.models.common.CDateSet; import com.bakdata.conquery.models.common.daterange.CDateRange; import com.bakdata.conquery.models.config.ConqueryConfig; -import net.bytebuddy.asm.Advice; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -22,104 +20,178 @@ public class CDateSetTest { public static Stream arguments() { return Stream - .of( - Arguments.of("{2000-01-01/2000-01-01}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 1, 1) - )} - ), - Arguments.of("{2000-01-01/2000-01-01, 2001-01-01/2001-01-02}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 1, 1) - ), CDateRange.of( - LocalDate.of(2001, 1, 1), - LocalDate.of(2001, 1, 2) - )} - ), - Arguments.of("{2000-01-01/2004-01-01}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2004, 1, 1) - ), CDateRange.of( - LocalDate.of(2002, 1, 1), - LocalDate.of(2002, 1, 2) - )} - ), - Arguments.of("{2000-01-01/2000-01-07}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 1, 4) - ), CDateRange.of( - LocalDate.of(2000, 1, 4), - LocalDate.of(2000, 1, 7) - )} - ), - Arguments.of("{2000-01-01/2000-01-07}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 1, 3) - ), CDateRange.of( - LocalDate.of(2000, 1, 4), - LocalDate.of(2000, 1, 7) - )} - ), - Arguments.of("{2000-01-01/2000-01-02, 2000-01-04/2000-01-07}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 1, 2) - ), CDateRange.of( - LocalDate.of(2000, 1, 4), - LocalDate.of(2000, 1, 7) - )} - ), - Arguments.of("{2012-01-01/2012-01-02}", - new CDateRange[] {CDateRange.of( - LocalDate.of(2012, 1, 2), - LocalDate.of(2012, 1, 2) - ), CDateRange.of( - LocalDate.of(2012, 1, 1), - LocalDate.of(2012, 1, 1) - )} - ) - ); + .of( + Arguments.of( + "{2000-01-01/2000-01-01}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 1) + ) + } + ), + Arguments.of( + "{2000-01-01/2000-01-01, 2001-01-01/2001-01-02}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 1) + ), CDateRange.of( + LocalDate.of(2001, 1, 1), + LocalDate.of(2001, 1, 2) + ) + } + ), + Arguments.of( + "{2000-01-01/2004-01-01}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2004, 1, 1) + ), CDateRange.of( + LocalDate.of(2002, 1, 1), + LocalDate.of(2002, 1, 2) + ) + } + ), + Arguments.of( + "{2000-01-01/2000-01-07}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 4) + ), CDateRange.of( + LocalDate.of(2000, 1, 4), + LocalDate.of(2000, 1, 7) + ) + } + ), + Arguments.of( + "{2000-01-01/2000-01-07}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 3) + ), CDateRange.of( + LocalDate.of(2000, 1, 4), + LocalDate.of(2000, 1, 7) + ) + } + ), + Arguments.of( + "{2000-01-01/2000-01-02, 2000-01-04/2000-01-07}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 2) + ), CDateRange.of( + LocalDate.of(2000, 1, 4), + LocalDate.of(2000, 1, 7) + ) + } + ), + Arguments.of( + "{2012-01-01/2012-01-02}", + new CDateRange[]{ + CDateRange.of( + LocalDate.of(2012, 1, 2), + LocalDate.of(2012, 1, 2) + ), CDateRange.of( + LocalDate.of(2012, 1, 1), + LocalDate.of(2012, 1, 1) + ) + } + ) + ); } - - @ParameterizedTest(name="{0}") @MethodSource("arguments") + + public static Stream argumentsParsing() { + return Stream + .of( + Arguments.of( + "{2000-01-01/2000-01-01}", + CDateSet.create(CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01))) + ), + Arguments.of( + "01.01.2000-01.01.2000", + CDateSet.create(CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01))) + ), + Arguments.of( + "{2000-01-01/2000-01-01, 2001-01-01/2001-01-01}", + CDateSet.create( + List.of( + CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01)), + CDateRange.of(LocalDate.of(2001, 01, 01), LocalDate.of(2001, 01, 01)) + ) + ) + ), + Arguments.of( + "01.01.2000-01.01.2000, 01.01.2001-01.01.2001", + CDateSet.create( + List.of( + CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01)), + CDateRange.of(LocalDate.of(2001, 01, 01), LocalDate.of(2001, 01, 01)) + ) + ) + ), + Arguments.of( + "{2000-05-01, 2000-01-01/2000-01-01, 2001-01-01/2001-01-01}", + CDateSet.create( + List.of( + CDateRange.exactly(LocalDate.of(2000, 05, 01)), + CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01)), + CDateRange.of(LocalDate.of(2001, 01, 01), LocalDate.of(2001, 01, 01)) + ) + ) + ), + Arguments.of( + "01.05.2000, 01.01.2000-01.01.2000, 01.01.2001-01.01.2001", + CDateSet.create( + List.of( + CDateRange.exactly(LocalDate.of(2000, 05, 01)), + CDateRange.of(LocalDate.of(2000, 01, 01), LocalDate.of(2000, 01, 01)), + CDateRange.of(LocalDate.of(2001, 01, 01), LocalDate.of(2001, 01, 01)) + ) + ) + ) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("arguments") public void testAddMerging(String expected, CDateRange[] ranges) { CDateSet set = CDateSet.create(); - for(CDateRange range: ranges) { + for (CDateRange range : ranges) { set.add(range); } assertThat(set).hasToString(expected); } - + @Test public void testRemove() { CDateSet set = CDateSet.create(); set.add(CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 12, 31) + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 12, 31) )); set.remove(CDateRange.of( - LocalDate.of(2000, 6, 1), - LocalDate.of(2000, 6, 20) + LocalDate.of(2000, 6, 1), + LocalDate.of(2000, 6, 20) )); assertThat(set).hasToString("{2000-01-01/2000-05-31, 2000-06-21/2000-12-31}"); } - + @Test public void testRetain() { CDateSet set = CDateSet.create(); set.add(CDateRange.of( - LocalDate.of(2000, 1, 1), - LocalDate.of(2000, 12, 31) + LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 12, 31) )); CDateSet retain = CDateSet.create(); retain.add(CDateRange.of( - LocalDate.of(2000, 6, 1), - LocalDate.of(2000, 6, 20) + LocalDate.of(2000, 6, 1), + LocalDate.of(2000, 6, 20) )); retain.add(CDateRange.atLeast(LocalDate.of(2000, 12, 1))); set.retainAll(retain); @@ -136,6 +208,20 @@ public void testMaskedAddClosedMaskClosed() { assertThat(set.asRanges()).containsExactly(CDateRange.of(-5, 5)); } + @Test + public void testMaskedAddOpenMaskWithTruncateMax() { + final CDateSet mask = CDateSet.create(); + + mask.add(CDateRange.of(-10, -5)); + mask.add(CDateRange.atLeast(-1)); + + final CDateSet set = CDateSet.create(); + + set.maskedAdd(CDateRange.of(-5, 7), mask, 4); + + assertThat(set.asRanges()).containsExactly(CDateRange.exactly(-5), CDateRange.of(-1, 4)); + } + @Test public void testMaskedTEST() { CDateSet set = CDateSet.create(); @@ -173,7 +259,7 @@ public void testMaskedAddNoIntersection() { @Test public void testMaskedAddAtMostMaskClosed() { CDateSet set = CDateSet.create(); - CDateSet mask = CDateSet.create(CDateRange.of(-10,10)); + CDateSet mask = CDateSet.create(CDateRange.of(-10, 10)); set.maskedAdd(CDateRange.atMost(5), mask); @@ -183,7 +269,7 @@ public void testMaskedAddAtMostMaskClosed() { @Test public void testMaskedAddAtLeastMaskClosed() { CDateSet set = CDateSet.create(); - CDateSet mask = CDateSet.create(CDateRange.of(-10,10)); + CDateSet mask = CDateSet.create(CDateRange.of(-10, 10)); set.maskedAdd(CDateRange.atLeast(5), mask); @@ -200,55 +286,7 @@ public void testMaskedAddAtLeastMaskMultiple() { assertThat(set.asRanges()).containsExactly(CDateRange.of(5, 10), CDateRange.atLeast(30)); } - public static Stream argumentsParsing() { - return Stream - .of( - Arguments.of( - "{2000-01-01/2000-01-01}", - CDateSet.create(CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01))) - ), - Arguments.of( - "01.01.2000-01.01.2000", - CDateSet.create(CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01))) - ), - Arguments.of( - "{2000-01-01/2000-01-01, 2001-01-01/2001-01-01}", - CDateSet.create( - List.of( - CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01)), - CDateRange.of(LocalDate.of(2001,01,01), LocalDate.of(2001,01,01))) - ) - ), - Arguments.of( - "01.01.2000-01.01.2000, 01.01.2001-01.01.2001", - CDateSet.create( - List.of( - CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01)), - CDateRange.of(LocalDate.of(2001,01,01), LocalDate.of(2001,01,01))) - ) - ), - Arguments.of( - "{2000-05-01, 2000-01-01/2000-01-01, 2001-01-01/2001-01-01}", - CDateSet.create( - List.of( - CDateRange.exactly(LocalDate.of(2000,05,01)), - CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01)), - CDateRange.of(LocalDate.of(2001,01,01), LocalDate.of(2001,01,01))) - ) - ), - Arguments.of( - "01.05.2000, 01.01.2000-01.01.2000, 01.01.2001-01.01.2001", - CDateSet.create( - List.of( - CDateRange.exactly(LocalDate.of(2000,05,01)), - CDateRange.of(LocalDate.of(2000,01,01), LocalDate.of(2000,01,01)), - CDateRange.of(LocalDate.of(2001,01,01), LocalDate.of(2001,01,01))) - ) - ) - ); - } - - @ParameterizedTest(name="{0}") + @ParameterizedTest(name = "{0}") @MethodSource("argumentsParsing") public void parse(String input, CDateSet expected) { CDateSet set = config.getLocale().getDateReader().parseToCDateSet(input); diff --git a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/DURATION_SUM.test.json b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/DURATION_SUM.test.json index 18bcfe481e..4c3ef4ea25 100644 --- a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/DURATION_SUM.test.json +++ b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/DURATION_SUM.test.json @@ -25,7 +25,7 @@ "type": "TREE", "connectors": [ { - "label": "connector", + "name": "connector", "table": "table", "validityDates": { "label": "datum", @@ -33,7 +33,7 @@ }, "selects": { "type": "DURATION_SUM", - "name" : "select", + "name": "select", "column": "table.datum" } } diff --git a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/content.csv b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/content.csv index b52f8968ed..4eb17469e2 100644 --- a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/content.csv +++ b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/content.csv @@ -5,3 +5,4 @@ pid,datum 4,"2010-06-16/2010-06-18" 5,"2011-03-02/2011-03-10" 5,"2011-03-05/2011-03-13" +6,"/2011-03-13" \ No newline at end of file diff --git a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/expected.csv b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/expected.csv index f368d11bf8..6aa97311cc 100644 --- a/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/expected.csv +++ b/backend/src/test/resources/tests/aggregator/DURATION_SUM_AGGREGATOR/expected.csv @@ -2,4 +2,5 @@ result,dates,concept select 1,{2010-01-01/2010-01-31},31 3,{2013-08-10/2013-08-11},2 4,{2010-06-15/2010-06-20},6 -5,{2011-03-02/2011-03-13},12 \ No newline at end of file +5,{2011-03-02/2011-03-13},12 +6,{-∞/2011-03-13}, \ No newline at end of file