diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryBackend.java b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryBackend.java index 6f04df66ed37..7d721779601d 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryBackend.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryBackend.java @@ -50,7 +50,7 @@ public interface QueryBackend { T generate(SearchJob job, Query query, Set predecessorResults); default boolean isAllMessages(TimeRange timeRange) { - return timeRange instanceof RelativeRange && ((RelativeRange)timeRange).range() == 0; + return timeRange instanceof RelativeRange && ((RelativeRange)timeRange).isAllMessages(); } default AbsoluteRange effectiveTimeRangeForResult(Query query, QueryResult queryResult) { diff --git a/graylog2-server/src/main/java/org/graylog2/plugin/indexer/searches/timeranges/RelativeRange.java b/graylog2-server/src/main/java/org/graylog2/plugin/indexer/searches/timeranges/RelativeRange.java index 742dc98a87b1..10186b1e571b 100644 --- a/graylog2-server/src/main/java/org/graylog2/plugin/indexer/searches/timeranges/RelativeRange.java +++ b/graylog2-server/src/main/java/org/graylog2/plugin/indexer/searches/timeranges/RelativeRange.java @@ -18,19 +18,21 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; import org.graylog2.plugin.Tools; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; -import org.joda.time.Seconds; -import java.util.Map; +import java.util.OptionalInt; @AutoValue @JsonTypeName(RelativeRange.RELATIVE) +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = RelativeRange.Builder.class) public abstract class RelativeRange extends TimeRange { public static final String RELATIVE = "relative"; @@ -40,56 +42,97 @@ public abstract class RelativeRange extends TimeRange { public abstract String type(); @JsonProperty - public abstract int range(); + public abstract OptionalInt range(); + + @JsonProperty + public abstract OptionalInt from(); + + @JsonProperty + public abstract OptionalInt to(); public int getRange() { - return range(); + return range().orElse(0); } @Override @JsonIgnore public DateTime getFrom() { // TODO this should be computed once - if (range() > 0) { - return Tools.nowUTC().minus(Seconds.seconds(range())); + if (range().isPresent()) { + final int range = range().getAsInt(); + return range > 0 + ? Tools.nowUTC().minusSeconds(range().getAsInt()) + : new DateTime(0, DateTimeZone.UTC); } - return new DateTime(0, DateTimeZone.UTC); + + return Tools.nowUTC().minusSeconds(from().orElseThrow(() -> new IllegalStateException("Neither `range` nor `from` specified!"))); } @Override @JsonIgnore public DateTime getTo() { // TODO this should be fixed - return Tools.nowUTC(); - } + if (range().isPresent()) { + return Tools.nowUTC(); + } - @JsonCreator - public static RelativeRange create(@JsonProperty("type") String type, @JsonProperty("range") int range) throws InvalidRangeParametersException { - return builder().type(type).checkRange(range).build(); + return Tools.nowUTC().minusSeconds(to().orElseThrow(() -> new IllegalStateException("Neither `range` nor `to` specified!"))); } - public static RelativeRange create(int range) throws InvalidRangeParametersException { - return create(RELATIVE, range); + @JsonIgnore + public boolean isAllMessages() { + return range().orElse(-1) == 0; } - public static Builder builder() { - return new AutoValue_RelativeRange.Builder(); + public static RelativeRange create(int range) throws InvalidRangeParametersException { + return Builder.builder() + .range(range) + .build(); } @AutoValue.Builder public abstract static class Builder { - public abstract RelativeRange build(); + abstract RelativeRange autoBuild(); + @JsonProperty("type") public abstract Builder type(String type); + @JsonProperty("range") public abstract Builder range(int range); + abstract OptionalInt range(); - // TODO replace with custom build() - public Builder checkRange(int range) throws InvalidRangeParametersException { - if (range < 0) { - throw new InvalidRangeParametersException("Range must not be negative"); + @JsonProperty("from") + public abstract Builder from(int from); + abstract OptionalInt from(); + + @JsonProperty("to") + public abstract Builder to(int to); + abstract OptionalInt to(); + + public RelativeRange build() throws InvalidRangeParametersException { + if (range().isPresent() && (from().isPresent() || to().isPresent())) { + throw new InvalidRangeParametersException("Either `range` OR `from`/`to` must be specifed, not both!"); + } + + if (range().isPresent()) { + if (range().getAsInt() < 0) { + throw new InvalidRangeParametersException("Range must not be negative"); + } + } + + if ((from().isPresent() && !to().isPresent()) || (to().isPresent() && !from().isPresent())) { + throw new InvalidRangeParametersException("Both `from` and `to` must be specified!"); + } + + if ((from().isPresent() && to().isPresent()) && (to().getAsInt() > from().getAsInt())) { + throw new InvalidRangeParametersException("`from` must be greater than `to`!"); } - return range(range); + return autoBuild(); + } + + @JsonCreator + public static Builder builder() { + return new AutoValue_RelativeRange.Builder().type(RELATIVE); } }