Skip to content

Commit

Permalink
add filter, sort and exists support for feature definition field
Browse files Browse the repository at this point in the history
Signed-off-by: Dominik Guggemos <dominik.guggemos@bosch.io>
  • Loading branch information
dguggemos committed Jul 20, 2022
1 parent 44efc56 commit cfab89d
Show file tree
Hide file tree
Showing 13 changed files with 238 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.rql.query.expression;

/**
* Field expression for feature definition with a given feature id.
*
* @since 3.0.0
*/
public interface FeatureDefinitionExpression extends SortFieldExpression, FilterFieldExpression, ExistsFieldExpression {

/**
* Creates an expression for existence of a feature definition.
*
* @param featureId the feature id.
* @return the created FeatureExpression
* @throws NullPointerException if {@code featureId} is {@code null}.
*/
static FeatureDefinitionExpression of(final String featureId) {
return new FeatureDefinitionExpressionImpl(featureId);
}

/**
* @return the feature id.
*/
String getFeatureId();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2017 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.rql.query.expression;

import static java.util.Objects.requireNonNull;

import java.util.Objects;

import javax.annotation.concurrent.Immutable;

import org.eclipse.ditto.rql.query.expression.visitors.ExistsFieldExpressionVisitor;
import org.eclipse.ditto.rql.query.expression.visitors.FieldExpressionVisitor;
import org.eclipse.ditto.rql.query.expression.visitors.FilterFieldExpressionVisitor;
import org.eclipse.ditto.rql.query.expression.visitors.SortFieldExpressionVisitor;

/**
* Immutable implementation of {@link FeatureDefinitionExpression}.
*/
@Immutable
final class FeatureDefinitionExpressionImpl implements FeatureDefinitionExpression {

private final String featureId;

FeatureDefinitionExpressionImpl(final String featureId) {
this.featureId = requireNonNull(featureId);
}

@Override
public <T> T acceptExistsVisitor(final ExistsFieldExpressionVisitor<T> visitor) {
return visitor.visitFeatureDefinition(featureId);
}

@Override
public <T> T accept(final FieldExpressionVisitor<T> visitor) {
return visitor.visitFeatureDefinition(featureId);
}

@Override
public <T> T acceptFilterVisitor(final FilterFieldExpressionVisitor<T> visitor) {
return visitor.visitFeatureDefinition(featureId);
}

@Override
public <T> T acceptSortVisitor(final SortFieldExpressionVisitor<T> visitor) {
return visitor.visitFeatureDefinition(featureId);
}

@Override
public String getFeatureId() {
return featureId;
}

@SuppressWarnings("squid:MethodCyclomaticComplexity")
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final FeatureDefinitionExpressionImpl that = (FeatureDefinitionExpressionImpl) o;
return Objects.equals(featureId, that.featureId);
}

@SuppressWarnings("squid:S109")
@Override
public int hashCode() {
return Objects.hash(featureId);
}

@Override
public String toString() {
return getClass().getSimpleName() + " [" +
"featureId=" + featureId +
"]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ public static final class FeatureField {
private static final Pattern FIELD_NAME_FEATURE_PATTERN2 =
Pattern.compile("^features/(?<featureId>[^/]++)");

private static final Pattern FIELD_NAME_FEATURE_DEFINITION_PATTERN =
Pattern.compile("^features/(?<featureId>[^/]++)/definition/?");

private static final String FEATURE_ID = "featureId";

private final boolean matches;
Expand All @@ -157,6 +160,7 @@ public static final class FeatureField {
private final boolean isProperties;
private final String desiredProperty;
private final boolean isDesiredProperties;
private final boolean isDefinition;

private FeatureField(final CharSequence fieldName) {
Matcher matcher = FIELD_NAME_FEATURE_PATTERN1.matcher(fieldName);
Expand All @@ -166,6 +170,7 @@ private FeatureField(final CharSequence fieldName) {
isProperties = false;
property = matcher.group("property");
isDesiredProperties = false;
isDefinition = false;
desiredProperty = null;
} else {

Expand All @@ -176,6 +181,7 @@ private FeatureField(final CharSequence fieldName) {
isProperties = false;
property = null;
isDesiredProperties = false;
isDefinition = false;
desiredProperty = matcher.group("desiredProperty");
} else {

Expand All @@ -186,6 +192,7 @@ private FeatureField(final CharSequence fieldName) {
isProperties = true;
property = null;
isDesiredProperties = false;
isDefinition = false;
desiredProperty = null;
} else {

Expand All @@ -196,25 +203,40 @@ private FeatureField(final CharSequence fieldName) {
isProperties = false;
property = null;
isDesiredProperties = true;
isDefinition = false;
desiredProperty = null;
} else {

matcher = FIELD_NAME_FEATURE_PATTERN2.matcher(fieldName);
matcher = FIELD_NAME_FEATURE_DEFINITION_PATTERN.matcher(fieldName);
if (matcher.matches()) {
matches = true;
featureId = matcher.group(FEATURE_ID);
isProperties = false;
property = null;
isDesiredProperties = false;
isDefinition = true;
desiredProperty = null;
} else {

matches = false;
featureId = null;
isProperties = false;
property = null;
isDesiredProperties = false;
desiredProperty = null;
matcher = FIELD_NAME_FEATURE_PATTERN2.matcher(fieldName);
if (matcher.matches()) {
matches = true;
featureId = matcher.group(FEATURE_ID);
isProperties = false;
property = null;
isDesiredProperties = false;
isDefinition = false;
desiredProperty = null;
} else {

matches = false;
featureId = null;
isProperties = false;
property = null;
isDesiredProperties = false;
isDefinition = false;
desiredProperty = null;
}
}
}
}
Expand Down Expand Up @@ -261,6 +283,9 @@ public boolean isDesiredProperties() {
return isDesiredProperties;
}

public boolean isDefinition() {
return isDefinition;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ public FilterFieldExpression filterBy(final String propertyNameWithOptionalLeadi

final Supplier<FilterFieldExpression> defaultSupplier = () -> (FilterFieldExpression) common(propertyName);
return FieldExpressionUtil.parseFeatureField(requireNonNull(propertyName))
.<FilterFieldExpression>flatMap(f ->
f.getProperty().isPresent()
? f.getProperty().flatMap(property ->
// we have a feature id and a property path
f.getFeatureId().map(id -> new FeatureIdPropertyExpressionImpl(id, property))
)
: f.getDesiredProperty().flatMap(desiredProperty ->
f.getFeatureId()
.map(id -> new FeatureIdDesiredPropertyExpressionImpl(id, desiredProperty))
)
.<FilterFieldExpression>flatMap(f -> {
if (f.isDefinition()) {
return f.getFeatureId().map(FeatureDefinitionExpressionImpl::new);
} else {
return f.getProperty().isPresent()
? f.getProperty().flatMap(property ->
// we have a feature id and a property path
f.getFeatureId().map(id -> new FeatureIdPropertyExpressionImpl(id, property))
)
: f.getDesiredProperty().flatMap(desiredProperty ->
f.getFeatureId()
.map(id -> new FeatureIdDesiredPropertyExpressionImpl(id, desiredProperty))
);
}
}
)
.orElseGet(defaultSupplier);
}
Expand All @@ -62,29 +67,23 @@ public ExistsFieldExpression existsBy(final String propertyNameWithOptionalLeadi

return FieldExpressionUtil.parseFeatureField(propertyName)
.flatMap(f -> f.getFeatureId()
.map(id ->
f.getProperty().<ExistsFieldExpression>map(

// property
property -> new FeatureIdPropertyExpressionImpl(id, property))

.map(id -> f.getProperty().<ExistsFieldExpression>map(
// property
property -> new FeatureIdPropertyExpressionImpl(id, property))
// desiredProperty
.orElse(f.getDesiredProperty().<ExistsFieldExpression>map(
desiredProperty -> new FeatureIdDesiredPropertyExpressionImpl(id,
desiredProperty))
.orElse(f.getDesiredProperty().<ExistsFieldExpression>map(desiredProperty -> new FeatureIdDesiredPropertyExpressionImpl(id, desiredProperty))
.orElseGet(() -> {
if (f.isProperties()) {

// we have a feature ID and the properties path,
// but no property
return new FeatureIdPropertiesExpressionImpl(id);
} else if (f.isDesiredProperties()) {

// we have a feature ID and the desired properties path,
// but no desired property
return new FeatureIdDesiredPropertiesExpressionImpl(id);
} else if (f.isDefinition()) {
return new FeatureDefinitionExpressionImpl(id);
} else {

// we have a feature ID but no property path
return new FeatureExpressionImpl(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public interface ExistsFieldExpressionVisitor<T> extends SortFieldExpressionVisi

T visitFeature(String featureId);

T visitFeatureDefinition(String featureId);

T visitFeatureProperties(CharSequence featureId);

T visitFeatureDesiredProperties(CharSequence featureId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ public interface SortFieldExpressionVisitor<T> {

T visitFeatureIdProperty(String featureId, String property);

T visitFeatureDefinition(String featureId);

T visitFeatureIdDesiredProperty(CharSequence featureId, CharSequence desiredProperty);

T visitSimple(String fieldName);

}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ public Predicate<Thing> visitFeature(final String featureId) {
.orElse(false);
}

@Override
public Predicate<Thing> visitFeatureDefinition(final String featureId) {
return thing -> thing.getFeatures()
.flatMap(features -> features.getFeature(featureId))
.map(feature -> feature.getDefinition().isPresent())
.orElse(false);
}

@Override
public Predicate<Thing> visitFeatureProperties(final CharSequence featureId) {
return thing -> thing.getFeatures()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public Predicate<Thing> visitAttribute(final String key) {
return predicateFunction.apply("/attributes/" + key);
}

@Override
public Predicate<Thing> visitFeatureDefinition(final String featureId) {
return predicateFunction.apply("/features/" + featureId + "/definition");
}

@Override
public Predicate<Thing> visitFeatureIdProperty(final String featureId, final String property) {
return predicateFunction.apply("/features/" + featureId + "/properties/" + property);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public final class ThingsFieldExpressionFactoryImplTest {
"features/" + KNOWN_FEATURE_ID + "/properties/" + KNOWN_STRING;

private static final String KNOWN_FEATURE_DESIRED_PROPERTY_WITH_ID =
"features/" + KNOWN_FEATURE_ID + "/desiredProperties/" + KNOWN_STRING + "_desired";
"features/" + KNOWN_FEATURE_ID + "/definition";

private static final String KNOWN_METADATA = "_metadata/" + KNOWN_FEATURE_PROPERTY_WITH_ID;

Expand Down Expand Up @@ -81,6 +81,13 @@ public void filterByWithFeatureDesiredPropertyWithId() {
assertThat(fieldExpression).isEqualTo(expected);
}

@Test
public void filterByWithFeatureDefinitionWithId() {
final FieldExpression fieldExpression = ef.filterBy(KNOWN_FEATURE_DESIRED_PROPERTY_WITH_ID);
final FilterFieldExpression expected = new FeatureDefinitionExpressionImpl(KNOWN_FEATURE_ID);
assertThat(fieldExpression).isEqualTo(expected);
}

@Test(expected = IllegalArgumentException.class)
public void filterByWithFeature() {
ef.filterBy(KNOWN_FEATURE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public final class PersistenceConstants {
*/
public static final String FIELD_PROPERTIES = "properties";

/**
* Field name for feature definition.
*/
public static final String FIELD_DEFINITION = "definition";

/**
* Part of the path between feature ID and property key.
*/
Expand Down
Loading

0 comments on commit cfab89d

Please sign in to comment.