Refactor RSQL serach fields related classes (#1834)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -18,7 +18,7 @@ import java.util.List;
|
|||||||
* Sort and search fields for actions.
|
* Sort and search fields for actions.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum ActionFields implements FieldNameProvider, FieldValueConverter<ActionFields> {
|
public enum ActionFields implements RsqlQueryField, FieldValueConverter<ActionFields> {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
STATUS("active"),
|
STATUS("active"),
|
||||||
@@ -26,29 +26,29 @@ public enum ActionFields implements FieldNameProvider, FieldValueConverter<Actio
|
|||||||
LASTSTATUSCODE("lastActionStatusCode"),
|
LASTSTATUSCODE("lastActionStatusCode"),
|
||||||
WEIGHT("weight"),
|
WEIGHT("weight"),
|
||||||
TARGET("target",
|
TARGET("target",
|
||||||
TargetFields.ID.getFieldName(), TargetFields.NAME.getFieldName(),
|
TargetFields.ID.getJpaEntityFieldName(), TargetFields.NAME.getJpaEntityFieldName(),
|
||||||
TargetFields.UPDATESTATUS.getFieldName(), TargetFields.IPADDRESS.getFieldName()),
|
TargetFields.UPDATESTATUS.getJpaEntityFieldName(), TargetFields.IPADDRESS.getJpaEntityFieldName()),
|
||||||
DISTRIBUTIONSET("distributionSet",
|
DISTRIBUTIONSET("distributionSet",
|
||||||
DistributionSetFields.ID.getFieldName(),
|
DistributionSetFields.ID.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.NAME.getFieldName(), DistributionSetFields.VERSION.getFieldName(),
|
DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.TYPE.getFieldName()),
|
DistributionSetFields.TYPE.getJpaEntityFieldName()),
|
||||||
ROLLOUT("rollout", RolloutFields.ID.getFieldName(), RolloutFields.NAME.getFieldName()),
|
ROLLOUT("rollout", RolloutFields.ID.getJpaEntityFieldName(), RolloutFields.NAME.getJpaEntityFieldName()),
|
||||||
ROLLOUTGROUP("rolloutGroup", RolloutGroupFields.ID.getFieldName(), RolloutGroupFields.NAME.getFieldName()),
|
ROLLOUTGROUP("rolloutGroup", RolloutGroupFields.ID.getJpaEntityFieldName(), RolloutGroupFields.NAME.getJpaEntityFieldName()),
|
||||||
EXTERNALREF("externalRef");
|
EXTERNALREF("externalRef");
|
||||||
|
|
||||||
private static final String ACTIVE = "pending";
|
private static final String ACTIVE = "pending";
|
||||||
private static final String INACTIVE = "finished";
|
private static final String INACTIVE = "finished";
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
ActionFields(final String fieldName) {
|
ActionFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
this.subEntityAttributes = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionFields(final String fieldName, final String... subEntityAttributes) {
|
ActionFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import lombok.Getter;
|
|||||||
* Sort and search fields for action status.
|
* Sort and search fields for action status.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum ActionStatusFields implements FieldNameProvider {
|
public enum ActionStatusFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
REPORTEDAT("createdAt");
|
REPORTEDAT("createdAt");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
ActionStatusFields(final String fieldName) {
|
ActionStatusFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ import java.util.Optional;
|
|||||||
* REST API e.g. for sorting etc.
|
* REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum DistributionSetFields implements FieldNameProvider {
|
public enum DistributionSetFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
TYPE("type.key"),
|
TYPE("type.key"),
|
||||||
@@ -32,29 +32,29 @@ public enum DistributionSetFields implements FieldNameProvider {
|
|||||||
LASTMODIFIEDAT("lastModifiedAt"),
|
LASTMODIFIEDAT("lastModifiedAt"),
|
||||||
VERSION("version"),
|
VERSION("version"),
|
||||||
COMPLETE("complete"),
|
COMPLETE("complete"),
|
||||||
MODULE("modules", SoftwareModuleFields.ID.getFieldName(), SoftwareModuleFields.NAME.getFieldName()),
|
MODULE("modules", SoftwareModuleFields.ID.getJpaEntityFieldName(), SoftwareModuleFields.NAME.getJpaEntityFieldName()),
|
||||||
TAG("tags.name"),
|
TAG("tags.name"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
||||||
VALID("valid");
|
VALID("valid");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final Entry<String, String> subEntityMapTuple;
|
private final Entry<String, String> subEntityMapTuple;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
DistributionSetFields(final String fieldName) {
|
DistributionSetFields(final String jpaEntityFieldName) {
|
||||||
this(fieldName, null, Collections.emptyList());
|
this(jpaEntityFieldName, null, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String fieldName, final String... subEntityAttributes) {
|
DistributionSetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this(fieldName, null, List.of(subEntityAttributes));
|
this(jpaEntityFieldName, null, List.of(subEntityAttributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String fieldName, final Entry<String, String> subEntityMapTuple) {
|
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
||||||
this(fieldName, subEntityMapTuple, Collections.emptyList());
|
this(jpaEntityFieldName, subEntityMapTuple, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String fieldName, final Entry<String, String> subEntityMapTuple, List<String> subEntityAttributes) {
|
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple, List<String> subEntityAttributes) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityMapTuple = subEntityMapTuple;
|
||||||
this.subEntityAttributes = subEntityAttributes;
|
this.subEntityAttributes = subEntityAttributes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ import lombok.Getter;
|
|||||||
* Sort fields for DistributionSetMetadata.
|
* Sort fields for DistributionSetMetadata.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum DistributionSetMetadataFields implements FieldNameProvider {
|
public enum DistributionSetMetadataFields implements RsqlQueryField {
|
||||||
|
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
VALUE("value");
|
VALUE("value");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
DistributionSetMetadataFields(final String fieldName) {
|
DistributionSetMetadataFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String identifierFieldName() {
|
public String identifierFieldName() {
|
||||||
return KEY.getFieldName();
|
return KEY.getJpaEntityFieldName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,25 +21,25 @@ import java.util.List;
|
|||||||
* filtering over distribution set fields also.
|
* filtering over distribution set fields also.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum DistributionSetTagFields implements FieldNameProvider {
|
public enum DistributionSetTagFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID(TagFields.ID.getFieldName()),
|
ID(TagFields.ID.getJpaEntityFieldName()),
|
||||||
NAME(TagFields.NAME.getFieldName()),
|
NAME(TagFields.NAME.getJpaEntityFieldName()),
|
||||||
DESCRIPTION(TagFields.DESCRIPTION.getFieldName()),
|
DESCRIPTION(TagFields.DESCRIPTION.getJpaEntityFieldName()),
|
||||||
COLOUR(TagFields.COLOUR.getFieldName()),
|
COLOUR(TagFields.COLOUR.getJpaEntityFieldName()),
|
||||||
DISTRIBUTIONSET("assignedToDistributionSet",
|
DISTRIBUTIONSET("assignedToDistributionSet",
|
||||||
DistributionSetFields.ID.getFieldName(), DistributionSetFields.NAME.getFieldName());
|
DistributionSetFields.ID.getJpaEntityFieldName(), DistributionSetFields.NAME.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
DistributionSetTagFields(final String fieldName) {
|
DistributionSetTagFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
this.subEntityAttributes = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetTagFields(final String fieldName, final String... subEntityAttributes) {
|
DistributionSetTagFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,16 +16,16 @@ import lombok.Getter;
|
|||||||
* the REST API e.g. for sorting etc.
|
* the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum DistributionSetTypeFields implements FieldNameProvider {
|
public enum DistributionSetTypeFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description");
|
DESCRIPTION("description");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
DistributionSetTypeFields(final String fieldName) {
|
DistributionSetTypeFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,26 +18,26 @@ import java.util.List;
|
|||||||
* Describing the fields of the Rollout model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the Rollout model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum RolloutFields implements FieldNameProvider {
|
public enum RolloutFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
STATUS("status"),
|
STATUS("status"),
|
||||||
DISTRIBUTIONSET("distributionSet", DistributionSetFields.ID.getFieldName(),
|
DISTRIBUTIONSET("distributionSet", DistributionSetFields.ID.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.NAME.getFieldName(), DistributionSetFields.VERSION.getFieldName(),
|
DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.TYPE.getFieldName());
|
DistributionSetFields.TYPE.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
RolloutFields(final String fieldName) {
|
RolloutFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
this.subEntityAttributes = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
RolloutFields(final String fieldName, final String... subEntityAttributes) {
|
RolloutFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,15 +15,15 @@ import lombok.Getter;
|
|||||||
* Describing the fields of the RolloutGroup model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the RolloutGroup model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum RolloutGroupFields implements FieldNameProvider {
|
public enum RolloutGroupFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description");
|
DESCRIPTION("description");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
RolloutGroupFields(final String fieldName) {
|
RolloutGroupFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,13 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for declaring the name of the field described in the database
|
* An RSQL query field interface extended by all the fields that could be used in RSQL queries.
|
||||||
* which is used as string representation of the field, e.g. for sorting the
|
|
||||||
* fields over REST.
|
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
public interface RsqlQueryField {
|
||||||
public interface FieldNameProvider {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Separator for the sub attributes
|
* Separator for the sub attributes
|
||||||
@@ -32,10 +30,10 @@ public interface FieldNameProvider {
|
|||||||
String SUB_ATTRIBUTE_SPLIT_REGEX = "\\" + SUB_ATTRIBUTE_SEPARATOR;
|
String SUB_ATTRIBUTE_SPLIT_REGEX = "\\" + SUB_ATTRIBUTE_SEPARATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the string representation of the underlying persistence field
|
* @return the string representation of the underlying persistence field name e.g. in case of sorting.
|
||||||
* name e.g. in case of sorting. Never {@code null}.
|
|
||||||
*/
|
*/
|
||||||
String getFieldName();
|
@NotNull
|
||||||
|
String getJpaEntityFieldName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sub attributes
|
* Returns the sub attributes
|
||||||
@@ -48,7 +46,7 @@ public interface FieldNameProvider {
|
|||||||
final String[] subAttributes = propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX, 2);
|
final String[] subAttributes = propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX, 2);
|
||||||
// [0] field name | [1] key name (could miss, e.g. for target attributes)
|
// [0] field name | [1] key name (could miss, e.g. for target attributes)
|
||||||
final String mapKeyName = subAttributes.length == 2 ? subAttributes[1] : null;
|
final String mapKeyName = subAttributes.length == 2 ? subAttributes[1] : null;
|
||||||
return ObjectUtils.isEmpty(mapKeyName) ? new String[] { getFieldName() } : new String[] { getFieldName(), mapKeyName };
|
return ObjectUtils.isEmpty(mapKeyName) ? new String[] { getJpaEntityFieldName() } : new String[] { getJpaEntityFieldName(), mapKeyName };
|
||||||
} else {
|
} else {
|
||||||
return propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX);
|
return propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX);
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ import java.util.Optional;
|
|||||||
* Describing the fields of the SoftwareModule model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the SoftwareModule model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum SoftwareModuleFields implements FieldNameProvider {
|
public enum SoftwareModuleFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
TYPE("type.key"),
|
TYPE("type.key"),
|
||||||
@@ -28,15 +28,15 @@ public enum SoftwareModuleFields implements FieldNameProvider {
|
|||||||
VERSION("version"),
|
VERSION("version"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value"));
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value"));
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private Entry<String, String> subEntityMapTuple;
|
private Entry<String, String> subEntityMapTuple;
|
||||||
|
|
||||||
SoftwareModuleFields(final String fieldName) {
|
SoftwareModuleFields(final String jpaEntityFieldName) {
|
||||||
this(fieldName, null);
|
this(jpaEntityFieldName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoftwareModuleFields(final String fieldName, final Entry<String, String> subEntityMapTuple) {
|
SoftwareModuleFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityMapTuple = subEntityMapTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,20 +15,20 @@ import lombok.Getter;
|
|||||||
* Sort fields for SoftwareModuleMetadata.
|
* Sort fields for SoftwareModuleMetadata.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum SoftwareModuleMetadataFields implements FieldNameProvider {
|
public enum SoftwareModuleMetadataFields implements RsqlQueryField {
|
||||||
|
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
VALUE("value"),
|
VALUE("value"),
|
||||||
TARGETVISIBLE("targetVisible");
|
TARGETVISIBLE("targetVisible");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
SoftwareModuleMetadataFields(final String fieldName) {
|
SoftwareModuleMetadataFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String identifierFieldName() {
|
public String identifierFieldName() {
|
||||||
return KEY.getFieldName();
|
return KEY.getJpaEntityFieldName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import lombok.Getter;
|
|||||||
* Describing the fields of the SoftwareModuleType model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the SoftwareModuleType model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum SoftwareModuleTypeFields implements FieldNameProvider {
|
public enum SoftwareModuleTypeFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
@@ -23,9 +23,9 @@ public enum SoftwareModuleTypeFields implements FieldNameProvider {
|
|||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
MAXASSIGNMENTS("maxAssignments");
|
MAXASSIGNMENTS("maxAssignments");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
SoftwareModuleTypeFields(final String fieldName) {
|
SoftwareModuleTypeFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ import lombok.Getter;
|
|||||||
* Describing the fields of the Tag model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the Tag model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TagFields implements FieldNameProvider {
|
public enum TagFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
COLOUR("colour");
|
COLOUR("colour");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
TagFields(final String fieldName) {
|
TagFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.Optional;
|
|||||||
* e.g. for sorting etc.
|
* e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TargetFields implements FieldNameProvider {
|
public enum TargetFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("controllerId"),
|
ID("controllerId"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
@@ -38,26 +38,26 @@ public enum TargetFields implements FieldNameProvider {
|
|||||||
TAG("tags.name"),
|
TAG("tags.name"),
|
||||||
LASTCONTROLLERREQUESTAT("lastTargetQuery"),
|
LASTCONTROLLERREQUESTAT("lastTargetQuery"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
||||||
TARGETTYPE("targetType", TargetTypeFields.KEY.getFieldName(), TargetTypeFields.NAME.getFieldName());
|
TARGETTYPE("targetType", TargetTypeFields.KEY.getJpaEntityFieldName(), TargetTypeFields.NAME.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
private final Entry<String, String> subEntityMapTuple;
|
private final Entry<String, String> subEntityMapTuple;
|
||||||
|
|
||||||
TargetFields(final String fieldName) {
|
TargetFields(final String jpaEntityFieldName) {
|
||||||
this(fieldName, Collections.emptyList(), null);
|
this(jpaEntityFieldName, Collections.emptyList(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetFields(final String fieldName, final String... subEntityAttributes) {
|
TargetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this(fieldName, List.of(subEntityAttributes), null);
|
this(jpaEntityFieldName, List.of(subEntityAttributes), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetFields(final String fieldName, final Entry<String, String> subEntityMapTuple) {
|
TargetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
||||||
this(fieldName, Collections.emptyList(), subEntityMapTuple);
|
this(jpaEntityFieldName, Collections.emptyList(), subEntityMapTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetFields(final String fieldName, final List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
TargetFields(final String jpaEntityFieldName, final List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = subEntityAttributes;
|
this.subEntityAttributes = subEntityAttributes;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityMapTuple = subEntityMapTuple;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,25 @@ import java.util.List;
|
|||||||
* Describing the fields of the Target model which can be used in the REST API e.g. for sorting etc.
|
* Describing the fields of the Target model which can be used in the REST API e.g. for sorting etc.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TargetFilterQueryFields implements FieldNameProvider {
|
public enum TargetFilterQueryFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
AUTOASSIGNDISTRIBUTIONSET("autoAssignDistributionSet", "name", "version");
|
AUTOASSIGNDISTRIBUTIONSET("autoAssignDistributionSet", "name", "version");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
private List<String> subEntityAttributes;
|
private List<String> subEntityAttributes;
|
||||||
|
|
||||||
TargetFilterQueryFields(final String fieldName) {
|
TargetFilterQueryFields(final String jpaEntityFieldName) {
|
||||||
this(fieldName, Collections.emptyList());
|
this(jpaEntityFieldName, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetFilterQueryFields(final String fieldName, final String... subEntityAttribues) {
|
TargetFilterQueryFields(final String jpaEntityFieldName, final String... subEntityAttribues) {
|
||||||
this(fieldName, List.of(subEntityAttribues));
|
this(jpaEntityFieldName, List.of(subEntityAttribues));
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetFilterQueryFields(final String fieldName, final List<String> subEntityAttribues) {
|
TargetFilterQueryFields(final String jpaEntityFieldName, final List<String> subEntityAttribues) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = subEntityAttribues;
|
this.subEntityAttributes = subEntityAttribues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ import lombok.Getter;
|
|||||||
* Sort fields for TargetMetadata.
|
* Sort fields for TargetMetadata.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TargetMetadataFields implements FieldNameProvider {
|
public enum TargetMetadataFields implements RsqlQueryField {
|
||||||
|
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
VALUE("value");
|
VALUE("value");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
TargetMetadataFields(final String fieldName) {
|
TargetMetadataFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String identifierFieldName() {
|
public String identifierFieldName() {
|
||||||
return KEY.getFieldName();
|
return KEY.getJpaEntityFieldName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ import lombok.Getter;
|
|||||||
* Additionally, here were added fields for Target in order filtering over target fields also.
|
* Additionally, here were added fields for Target in order filtering over target fields also.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TargetTagFields implements FieldNameProvider {
|
public enum TargetTagFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID(TagFields.ID.getFieldName()),
|
ID(TagFields.ID.getJpaEntityFieldName()),
|
||||||
NAME(TagFields.NAME.getFieldName()),
|
NAME(TagFields.NAME.getJpaEntityFieldName()),
|
||||||
DESCRIPTION(TagFields.DESCRIPTION.getFieldName()),
|
DESCRIPTION(TagFields.DESCRIPTION.getJpaEntityFieldName()),
|
||||||
COLOUR(TagFields.COLOUR.getFieldName());
|
COLOUR(TagFields.COLOUR.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
TargetTagFields(final String fieldName) {
|
TargetTagFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,16 +15,16 @@ import lombok.Getter;
|
|||||||
* Describing the fields of the TargetType model which can be used in the REST API
|
* Describing the fields of the TargetType model which can be used in the REST API
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum TargetTypeFields implements FieldNameProvider {
|
public enum TargetTypeFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
KEY("key"),
|
KEY("key"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description");
|
DESCRIPTION("description");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String jpaEntityFieldName;
|
||||||
|
|
||||||
TargetTypeFields(final String fieldName) {
|
TargetTypeFields(final String jpaEntityFieldName) {
|
||||||
this.fieldName = fieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,16 +27,16 @@ public class FileNameFieldsTest {
|
|||||||
public void repositoryManagementMethodsArePreAuthorizedAnnotated() {
|
public void repositoryManagementMethodsArePreAuthorizedAnnotated() {
|
||||||
final String packageName = getClass().getPackage().getName();
|
final String packageName = getClass().getPackage().getName();
|
||||||
try (final ScanResult scanResult = new ClassGraph().acceptPackages(packageName).scan()) {
|
try (final ScanResult scanResult = new ClassGraph().acceptPackages(packageName).scan()) {
|
||||||
final List<? extends Class<? extends FieldNameProvider>> matchingClasses = scanResult.getAllClasses()
|
final List<? extends Class<? extends RsqlQueryField>> matchingClasses = scanResult.getAllClasses()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(classInPackage -> classInPackage.implementsInterface(FieldNameProvider.class))
|
.filter(classInPackage -> classInPackage.implementsInterface(RsqlQueryField.class))
|
||||||
.map(ClassInfo::loadClass)
|
.map(ClassInfo::loadClass)
|
||||||
.map(clazz -> (Class<? extends FieldNameProvider>) clazz)
|
.map(clazz -> (Class<? extends RsqlQueryField>) clazz)
|
||||||
.toList();
|
.toList();
|
||||||
assertThat(matchingClasses).isNotEmpty();
|
assertThat(matchingClasses).isNotEmpty();
|
||||||
matchingClasses.forEach(providerClass -> {
|
matchingClasses.forEach(providerClass -> {
|
||||||
assertThat(providerClass.getEnumConstants()).isNotEmpty();
|
assertThat(providerClass.getEnumConstants()).isNotEmpty();
|
||||||
for (final FieldNameProvider provider : providerClass.getEnumConstants()) {
|
for (final RsqlQueryField provider : providerClass.getEnumConstants()) {
|
||||||
if (provider.isMap() && !provider.getSubEntityAttributes().isEmpty()) {
|
if (provider.isMap() && !provider.getSubEntityAttributes().isEmpty()) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
"Currently sub-entity attributes for maps are not supported, alternatively you could use the key/value tuple, defined by SimpleImmutableEntry class");
|
"Currently sub-entity attributes for maps are not supported, alternatively you could use the key/value tuple, defined by SimpleImmutableEntry class");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.rsql;
|
package org.eclipse.hawkbit.repository.rsql;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.ast.Node;
|
import cz.jirutka.rsql.parser.ast.Node;
|
||||||
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||||
@@ -23,16 +23,16 @@ public interface RsqlVisitorFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a {@link RSQLVisitor} instance for validating RSQL queries based
|
* Provides a {@link RSQLVisitor} instance for validating RSQL queries based
|
||||||
* on the given {@link FieldNameProvider}.
|
* on the given {@link RsqlQueryField}.
|
||||||
*
|
*
|
||||||
* @param <A>
|
* @param <A>
|
||||||
* The type of the {@link FieldNameProvider}.
|
* The type of the {@link RsqlQueryField}.
|
||||||
* @param fieldNameProvider
|
* @param fieldNameProvider
|
||||||
* providing accessing to the relevant field names.
|
* providing accessing to the relevant field names.
|
||||||
*
|
*
|
||||||
* @return An {@link RSQLVisitor} to validate the {@link Node}s of an RSQL
|
* @return An {@link RSQLVisitor} to validate the {@link Node}s of an RSQL
|
||||||
* query.
|
* query.
|
||||||
*/
|
*/
|
||||||
<A extends Enum<A> & FieldNameProvider> RSQLVisitor<Void, String> validationRsqlVisitor(Class<A> fieldNameProvider);
|
<A extends Enum<A> & RsqlQueryField> RSQLVisitor<Void, String> validationRsqlVisitor(Class<A> fieldNameProvider);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,70 +15,83 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldNameProvider> {
|
public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
||||||
|
|
||||||
private final Class<A> fieldNameProvider;
|
private final Class<A> fieldNameProvider;
|
||||||
|
|
||||||
protected AbstractFieldNameRSQLVisitor(final Class<A> fieldNameProvider) {
|
@Value
|
||||||
|
public class RsqlField {
|
||||||
|
|
||||||
|
A enumValue;
|
||||||
|
String[] subAttributes;
|
||||||
|
|
||||||
|
private RsqlField(final A enumValue, final String[] subAttributes) {
|
||||||
|
this.enumValue = enumValue;
|
||||||
|
this.subAttributes = subAttributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractRSQLVisitor(final Class<A> fieldNameProvider) {
|
||||||
this.fieldNameProvider = fieldNameProvider;
|
this.fieldNameProvider = fieldNameProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected A getFieldEnumByName(final ComparisonNode node) {
|
protected RsqlField getRsqlField(final ComparisonNode node) {
|
||||||
final String[] graph = node.getSelector().split(FieldNameProvider.SUB_ATTRIBUTE_SPLIT_REGEX);
|
final String[] graph = node.getSelector().split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
|
||||||
final String enumName = graph.length == 0 ? node.getSelector() : graph[0];
|
final String enumName = graph.length == 0 ? node.getSelector() : graph[0];
|
||||||
log.debug("get field identifier by name {} of enum type {}", enumName, fieldNameProvider);
|
log.debug("get field identifier by name {} of enum type {}", enumName, fieldNameProvider);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Enum.valueOf(fieldNameProvider, enumName.toUpperCase());
|
final A enumValue = Enum.valueOf(fieldNameProvider, enumName.toUpperCase());
|
||||||
|
final String[] subAttributes = enumValue.getSubAttributes(node.getSelector());
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if (enumValue.isMap()) {
|
||||||
|
// enum.key
|
||||||
|
if (subAttributes.length != 2) {
|
||||||
|
throw new RSQLParameterUnsupportedFieldException(
|
||||||
|
"The syntax of the given map search parameter field {" + node.getSelector() + "} is wrong. Syntax is: <enum name>.<key name>");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// sub entity need minimum 1 dot
|
||||||
|
if (!enumValue.getSubEntityAttributes().isEmpty() && subAttributes.length < 2) {
|
||||||
|
throw createRSQLParameterUnsupportedException(node, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build property and validate sub attributes
|
||||||
|
final StringBuilder fieldNameBuilder = new StringBuilder(enumValue.getJpaEntityFieldName());
|
||||||
|
for (int i = 1; i < subAttributes.length; i++) {
|
||||||
|
final String propertyField = getFormattedSubEntityAttribute(enumValue, subAttributes[i]);
|
||||||
|
|
||||||
|
if (!enumValue.containsSubEntityAttribute(propertyField)) {
|
||||||
|
if (i != subAttributes.length - 1 || !enumValue.isMap()) {
|
||||||
|
throw createRSQLParameterUnsupportedException(node, null);
|
||||||
|
} // otherwise - the key of map is not in the sub entity attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldNameBuilder.append(RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR).append(propertyField);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RsqlField(enumValue, enumValue.getSubAttributes(fieldNameBuilder.toString()));
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
throw createRSQLParameterUnsupportedException(node, e);
|
throw createRSQLParameterUnsupportedException(node, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getAndValidatePropertyFieldName(final A propertyEnum, final ComparisonNode node) {
|
|
||||||
final String[] subAttributes = propertyEnum.getSubAttributes(node.getSelector());
|
|
||||||
|
|
||||||
if (propertyEnum.isMap()) {
|
|
||||||
// enum.key
|
|
||||||
if (subAttributes.length != 2) {
|
|
||||||
throw new RSQLParameterUnsupportedFieldException(
|
|
||||||
"The syntax of the given map search parameter field {" + node.getSelector() + "} is wrong. Syntax is: <enum name>.<key name>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// sub entity need minimum 1 dot
|
|
||||||
if (!propertyEnum.getSubEntityAttributes().isEmpty() && subAttributes.length < 2) {
|
|
||||||
throw createRSQLParameterUnsupportedException(node, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder fieldNameBuilder = new StringBuilder(propertyEnum.getFieldName());
|
|
||||||
for (int i = 1; i < subAttributes.length; i++) {
|
|
||||||
final String propertyField = getFormattedSubEntityAttribute(propertyEnum, subAttributes[i]);
|
|
||||||
|
|
||||||
if (!propertyEnum.containsSubEntityAttribute(propertyField)) {
|
|
||||||
if (i != subAttributes.length - 1 || !propertyEnum.isMap()) {
|
|
||||||
throw createRSQLParameterUnsupportedException(node, null);
|
|
||||||
} // otherwise - the key of map is not in the sub entity attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldNameBuilder.append(FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR).append(propertyField);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldNameBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node current processing node
|
* @param node current processing node
|
||||||
* @param rootException in case there is a cause otherwise {@code null}
|
* @param rootException in case there is a cause otherwise {@code null}
|
||||||
* @return Exception with prepared message extracted from the comparison node.
|
* @return Exception with prepared message extracted from the comparison node.
|
||||||
*/
|
*/
|
||||||
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(
|
private RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(
|
||||||
@NotNull final ComparisonNode node,
|
@NotNull final ComparisonNode node,
|
||||||
final Exception rootException) {
|
final Exception rootException) {
|
||||||
return new RSQLParameterUnsupportedFieldException(String.format(
|
return new RSQLParameterUnsupportedFieldException(String.format(
|
||||||
@@ -97,7 +110,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
|||||||
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {
|
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {
|
||||||
final String enumFieldName = enumField.name().toLowerCase();
|
final String enumFieldName = enumField.name().toLowerCase();
|
||||||
if (enumField.isMap()) {
|
if (enumField.isMap()) {
|
||||||
return enumFieldName + FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR + "keyName";
|
return enumFieldName + RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR + "keyName";
|
||||||
} else {
|
} else {
|
||||||
return enumFieldName;
|
return enumFieldName;
|
||||||
}
|
}
|
||||||
@@ -107,7 +120,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
|||||||
.filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> {
|
.filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> {
|
||||||
final List<String> subEntity = enumField
|
final List<String> subEntity = enumField
|
||||||
.getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase()
|
.getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase()
|
||||||
+ FieldNameProvider.SUB_ATTRIBUTE_SEPARATOR + fieldName)
|
+ RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR + fieldName)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return subEntity.stream();
|
return subEntity.stream();
|
||||||
@@ -9,19 +9,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
|
import org.eclipse.hawkbit.repository.rsql.RsqlVisitorFactory;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory providing {@link RSQLVisitor} instances which validate the nodes
|
* Factory providing {@link RSQLVisitor} instances which validate the nodes
|
||||||
* based on a given {@link FieldNameProvider}.
|
* based on a given {@link RsqlQueryField}.
|
||||||
*/
|
*/
|
||||||
public class DefaultRsqlVisitorFactory implements RsqlVisitorFactory {
|
public class DefaultRsqlVisitorFactory implements RsqlVisitorFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A extends Enum<A> & FieldNameProvider> RSQLVisitor<Void, String> validationRsqlVisitor(
|
public <A extends Enum<A> & RsqlQueryField> RSQLVisitor<Void, String> validationRsqlVisitor(
|
||||||
final Class<A> fieldNameProvider) {
|
final Class<A> fieldNameProvider) {
|
||||||
return new FieldValidationRsqlVisitor<>(fieldNameProvider);
|
return new FieldValidationRsqlVisitor<>(fieldNameProvider);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.ast.AndNode;
|
import cz.jirutka.rsql.parser.ast.AndNode;
|
||||||
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
||||||
@@ -19,19 +19,19 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link RSQLVisitor} implementation which validates the nodes (fields) based
|
* {@link RSQLVisitor} implementation which validates the nodes (fields) based
|
||||||
* on a given {@link FieldNameProvider} for a given entity type.
|
* on a given {@link RsqlQueryField} for a given entity type.
|
||||||
*
|
*
|
||||||
* @param <A>
|
* @param <A>
|
||||||
* The type the {@link FieldNameProvider} refers to.
|
* The type the {@link RsqlQueryField} refers to.
|
||||||
*/
|
*/
|
||||||
public class FieldValidationRsqlVisitor<A extends Enum<A> & FieldNameProvider> extends AbstractFieldNameRSQLVisitor<A>
|
public class FieldValidationRsqlVisitor<A extends Enum<A> & RsqlQueryField> extends AbstractRSQLVisitor<A>
|
||||||
implements RSQLVisitor<Void, String> {
|
implements RSQLVisitor<Void, String> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the visitor and initializes it.
|
* Constructs the visitor and initializes it.
|
||||||
*
|
*
|
||||||
* @param fieldNameProvider
|
* @param fieldNameProvider
|
||||||
* The {@link FieldNameProvider} to use for validation.
|
* The {@link RsqlQueryField} to use for validation.
|
||||||
*/
|
*/
|
||||||
public FieldValidationRsqlVisitor(final Class<A> fieldNameProvider) {
|
public FieldValidationRsqlVisitor(final Class<A> fieldNameProvider) {
|
||||||
super(fieldNameProvider);
|
super(fieldNameProvider);
|
||||||
@@ -49,8 +49,8 @@ public class FieldValidationRsqlVisitor<A extends Enum<A> & FieldNameProvider> e
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(final ComparisonNode node, final String param) {
|
public Void visit(final ComparisonNode node, final String param) {
|
||||||
final A fieldName = getFieldEnumByName(node);
|
// get AND validates
|
||||||
getAndValidatePropertyFieldName(fieldName, node);
|
getRsqlField(node);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import cz.jirutka.rsql.parser.ast.OrNode;
|
|||||||
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.FieldValueConverter;
|
import org.eclipse.hawkbit.repository.FieldValueConverter;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
@@ -66,7 +66,7 @@ import org.springframework.util.ObjectUtils;
|
|||||||
*/
|
*/
|
||||||
@Deprecated(forRemoval = true)
|
@Deprecated(forRemoval = true)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> extends AbstractFieldNameRSQLVisitor<A>
|
public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends AbstractRSQLVisitor<A>
|
||||||
implements RSQLVisitor<List<Predicate>, String> {
|
implements RSQLVisitor<List<Predicate>, String> {
|
||||||
|
|
||||||
public static final Character LIKE_WILDCARD = '*';
|
public static final Character LIKE_WILDCARD = '*';
|
||||||
@@ -171,13 +171,12 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
* @param enumField
|
* @param enumField
|
||||||
* field from a FieldNameProvider to resolve on the persistence
|
* field from a FieldNameProvider to resolve on the persistence
|
||||||
* layer
|
* layer
|
||||||
* @param finalProperty
|
* @param rsqlField RSQL field
|
||||||
* dot notated field path
|
|
||||||
* @return the Path for a field
|
* @return the Path for a field
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
|
private Path<Object> getFieldPath(final A enumField, final RsqlField rsqlField) {
|
||||||
return (Path<Object>) getFieldPath(root, enumField.getSubAttributes(finalProperty), enumField.isMap(),
|
return (Path<Object>) getFieldPath(root, rsqlField.getSubAttributes(), enumField.isMap(),
|
||||||
this::getJoinFieldPath).orElseThrow(
|
this::getJoinFieldPath).orElseThrow(
|
||||||
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
|
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
|
||||||
}
|
}
|
||||||
@@ -218,20 +217,19 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||||
@SuppressWarnings({ "squid:S2095" })
|
@SuppressWarnings({ "squid:S2095" })
|
||||||
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
||||||
final A fieldName = getFieldEnumByName(node);
|
final RsqlField rsqlField = getRsqlField(node);
|
||||||
final String finalProperty = getAndValidatePropertyFieldName(fieldName, node);
|
|
||||||
|
|
||||||
final List<String> values = node.getArguments();
|
final List<String> values = node.getArguments();
|
||||||
final List<Object> transformedValues = new ArrayList<>();
|
final List<Object> transformedValues = new ArrayList<>();
|
||||||
final Path<Object> fieldPath = getFieldPath(fieldName, finalProperty);
|
final Path<Object> fieldPath = getFieldPath(rsqlField.getEnumValue(), rsqlField);
|
||||||
|
|
||||||
for (final String value : values) {
|
for (final String value : values) {
|
||||||
transformedValues.add(convertValueIfNecessary(node, fieldName, value, fieldPath));
|
transformedValues.add(convertValueIfNecessary(node, rsqlField.getEnumValue(), value, fieldPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||||
|
|
||||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, fieldName, finalProperty);
|
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, rsqlField);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areJoinsNeeded(final ComparisonNode node) {
|
private static boolean areJoinsNeeded(final ComparisonNode node) {
|
||||||
@@ -307,8 +305,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||||
final List<String> values, final List<Object> transformedValues, final A enumField,
|
final List<String> values, final List<Object> transformedValues, final RsqlField rsqlField) {
|
||||||
final String finalProperty) {
|
|
||||||
|
|
||||||
String value = values.get(0);
|
String value = values.get(0);
|
||||||
// if lookup is available, replace macros ...
|
// if lookup is available, replace macros ...
|
||||||
@@ -316,16 +313,16 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
value = virtualPropertyReplacer.replace(value);
|
value = virtualPropertyReplacer.replace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, enumField);
|
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, rsqlField.getEnumValue());
|
||||||
|
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(enumField, fieldPath),
|
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(rsqlField.getEnumValue(), fieldPath),
|
||||||
transformedValues, value, finalProperty, enumField);
|
transformedValues, value, rsqlField);
|
||||||
|
|
||||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||||
final List<Object> transformedValues, final String value, final String finalProperty, final A enumField) {
|
final List<Object> transformedValues, final String value, final RsqlField rsqlField) {
|
||||||
|
|
||||||
// only 'equal' and 'notEqual' can handle transformed value like
|
// only 'equal' and 'notEqual' can handle transformed value like
|
||||||
// enums. The JPA API cannot handle object types for greaterThan etc
|
// enums. The JPA API cannot handle object types for greaterThan etc
|
||||||
@@ -337,7 +334,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
case "==":
|
case "==":
|
||||||
return getEqualToPredicate(transformedValue, fieldPath);
|
return getEqualToPredicate(transformedValue, fieldPath);
|
||||||
case "!=":
|
case "!=":
|
||||||
return getNotEqualToPredicate(transformedValue, fieldPath, finalProperty, enumField);
|
return getNotEqualToPredicate(transformedValue, fieldPath, rsqlField);
|
||||||
case "=gt=":
|
case "=gt=":
|
||||||
return cb.greaterThan(pathOfString(fieldPath), value);
|
return cb.greaterThan(pathOfString(fieldPath), value);
|
||||||
case "=ge=":
|
case "=ge=":
|
||||||
@@ -349,7 +346,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
case "=in=":
|
case "=in=":
|
||||||
return in(pathOfString(fieldPath), transformedValues);
|
return in(pathOfString(fieldPath), transformedValues);
|
||||||
case "=out=":
|
case "=out=":
|
||||||
return getOutPredicate(transformedValues, finalProperty, enumField, fieldPath);
|
return getOutPredicate(transformedValues, rsqlField, fieldPath);
|
||||||
default:
|
default:
|
||||||
throw new RSQLParameterSyntaxException(
|
throw new RSQLParameterSyntaxException(
|
||||||
"operator symbol {" + operator + "} is either not supported or not implemented");
|
"operator symbol {" + operator + "} is either not supported or not implemented");
|
||||||
@@ -357,18 +354,18 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getOutPredicate(
|
private Predicate getOutPredicate(
|
||||||
final List<Object> transformedValues, final String finalProperty,
|
final List<Object> transformedValues,
|
||||||
final A enumField, final Path<Object> fieldPath) {
|
final RsqlField rsqlField, final Path<Object> fieldPath) {
|
||||||
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
final String[] fieldNames = rsqlField.getSubAttributes();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
||||||
final Path<String> pathOfString = pathOfString(fieldPath);
|
final Path<String> pathOfString = pathOfString(fieldPath);
|
||||||
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOuterJoinsIfNotNeeded();
|
clearOuterJoinsIfNotNeeded();
|
||||||
|
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, expressionToCompare -> in(expressionToCompare, transformedValues));
|
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
||||||
@@ -422,7 +419,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
||||||
final String finalProperty, final A enumField) {
|
final RsqlField rsqlField) {
|
||||||
|
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNotNull(pathOfString(fieldPath));
|
return cb.isNotNull(pathOfString(fieldPath));
|
||||||
@@ -433,9 +430,9 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
final String[] fieldNames = rsqlField.getSubAttributes();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return cb.or(cb.isNull(pathOfString(fieldPath)), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
return cb.or(cb.isNull(pathOfString(fieldPath)), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
@@ -446,9 +443,9 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
|||||||
clearOuterJoinsIfNotNeeded();
|
clearOuterJoinsIfNotNeeded();
|
||||||
|
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, expressionToCompare -> like(expressionToCompare, toSQL(transformedValueStr)));
|
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> like(expressionToCompare, toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, expressionToCompare -> equal(expressionToCompare, transformedValueStr));
|
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> equal(expressionToCompare, transformedValueStr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import jakarta.persistence.metamodel.SingularAttribute;
|
|||||||
import jakarta.persistence.metamodel.Type;
|
import jakarta.persistence.metamodel.Type;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.FieldValueConverter;
|
import org.eclipse.hawkbit.repository.FieldValueConverter;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
@@ -57,8 +57,8 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @param <T> the entity type referenced by the root
|
* @param <T> the entity type referenced by the root
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
||||||
extends AbstractFieldNameRSQLVisitor<A> implements RSQLVisitor<List<Predicate>, String> {
|
extends AbstractRSQLVisitor<A> implements RSQLVisitor<List<Predicate>, String> {
|
||||||
|
|
||||||
public static final Character LIKE_WILDCARD = '*';
|
public static final Character LIKE_WILDCARD = '*';
|
||||||
private static final char ESCAPE_CHAR = '\\';
|
private static final char ESCAPE_CHAR = '\\';
|
||||||
@@ -110,31 +110,30 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
||||||
final A fieldName = getFieldEnumByName(node);
|
final RsqlField rsqlField = getRsqlField(node);
|
||||||
final String finalProperty = getAndValidatePropertyFieldName(fieldName, node);
|
|
||||||
|
|
||||||
final List<String> values = node.getArguments();
|
final List<String> values = node.getArguments();
|
||||||
final List<Object> transformedValues = new ArrayList<>();
|
final List<Object> transformedValues = new ArrayList<>();
|
||||||
final Path<Object> fieldPath = getFieldPath(root, fieldName.getSubAttributes(finalProperty), fieldName.isMap());
|
final Path<Object> fieldPath = getFieldPath(root, rsqlField);
|
||||||
|
|
||||||
for (final String value : values) {
|
for (final String value : values) {
|
||||||
transformedValues.add(convertValueIfNecessary(node, fieldName, fieldPath, value));
|
transformedValues.add(convertValueIfNecessary(node, rsqlField.getEnumValue(), fieldPath, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||||
|
|
||||||
return mapToPredicate(node, fieldName, finalProperty, fieldPath, node.getArguments(), transformedValues);
|
return mapToPredicate(node, rsqlField, fieldPath, node.getArguments(), transformedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final A enumField, final String finalProperty,
|
private List<Predicate> mapToPredicate(final ComparisonNode node, final RsqlField rsqlField,
|
||||||
final Path<Object> fieldPath,
|
final Path<Object> fieldPath,
|
||||||
final List<String> values, final List<Object> transformedValues) {
|
final List<String> values, final List<Object> transformedValues) {
|
||||||
// if lookup is available, replace macros ...
|
// if lookup is available, replace macros ...
|
||||||
final String value = virtualPropertyReplacer == null ? values.get(0) : virtualPropertyReplacer.replace(values.get(0));
|
final String value = virtualPropertyReplacer == null ? values.get(0) : virtualPropertyReplacer.replace(values.get(0));
|
||||||
|
|
||||||
final Predicate mapPredicate = mapToMapPredicate(node, enumField, fieldPath);
|
final Predicate mapPredicate = mapToMapPredicate(node, rsqlField.getEnumValue(), fieldPath);
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, enumField, finalProperty,
|
final Predicate valuePredicate = addOperatorPredicate(node, rsqlField,
|
||||||
getValueFieldPath(enumField, fieldPath), transformedValues, value);
|
getValueFieldPath(rsqlField.getEnumValue(), fieldPath), transformedValues, value);
|
||||||
|
|
||||||
return Collections.singletonList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return Collections.singletonList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
@@ -165,7 +164,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
"SimpleImmutableEntry are allowed. Neither of those could be found!"));
|
"SimpleImmutableEntry are allowed. Neither of those could be found!"));
|
||||||
return equal(fieldPath.get(keyFieldName), keyValue);
|
return equal(fieldPath.get(keyFieldName), keyValue);
|
||||||
}
|
}
|
||||||
private Predicate addOperatorPredicate(final ComparisonNode node, final A enumField, final String finalProperty,
|
private Predicate addOperatorPredicate(final ComparisonNode node, final RsqlField rsqlField,
|
||||||
final Path<Object> fieldPath, final List<Object> transformedValues, final String value) {
|
final Path<Object> fieldPath, final List<Object> transformedValues, final String value) {
|
||||||
// only 'equal' and 'notEqual' can handle transformed value like enums.
|
// only 'equal' and 'notEqual' can handle transformed value like enums.
|
||||||
// The JPA API cannot handle object types for greaterThan etc. methods.
|
// The JPA API cannot handle object types for greaterThan etc. methods.
|
||||||
@@ -173,13 +172,13 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
final String operator = node.getOperator().getSymbol();
|
final String operator = node.getOperator().getSymbol();
|
||||||
return switch (operator) {
|
return switch (operator) {
|
||||||
case "==" -> getEqualToPredicate(fieldPath, transformedValue);
|
case "==" -> getEqualToPredicate(fieldPath, transformedValue);
|
||||||
case "!=" -> getNotEqualToPredicate(enumField, finalProperty, fieldPath, transformedValue);
|
case "!=" -> getNotEqualToPredicate(rsqlField, fieldPath, transformedValue);
|
||||||
case "=gt=" -> cb.greaterThan(pathOfString(fieldPath), value);
|
case "=gt=" -> cb.greaterThan(pathOfString(fieldPath), value);
|
||||||
case "=ge=" -> cb.greaterThanOrEqualTo(pathOfString(fieldPath), value);
|
case "=ge=" -> cb.greaterThanOrEqualTo(pathOfString(fieldPath), value);
|
||||||
case "=lt=" -> cb.lessThan(pathOfString(fieldPath), value);
|
case "=lt=" -> cb.lessThan(pathOfString(fieldPath), value);
|
||||||
case "=le=" -> cb.lessThanOrEqualTo(pathOfString(fieldPath), value);
|
case "=le=" -> cb.lessThanOrEqualTo(pathOfString(fieldPath), value);
|
||||||
case "=in=" -> in(pathOfString(fieldPath), transformedValues);
|
case "=in=" -> in(pathOfString(fieldPath), transformedValues);
|
||||||
case "=out=" -> getOutPredicate(enumField, finalProperty, fieldPath, transformedValues);
|
case "=out=" -> getOutPredicate(rsqlField, fieldPath, transformedValues);
|
||||||
default -> throw new RSQLParameterSyntaxException(
|
default -> throw new RSQLParameterSyntaxException(
|
||||||
"Operator symbol {" + operator + "} is either not supported or not implemented");
|
"Operator symbol {" + operator + "} is either not supported or not implemented");
|
||||||
};
|
};
|
||||||
@@ -204,7 +203,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
return cb.equal(fieldPath, transformedValue);
|
return cb.equal(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getNotEqualToPredicate(final A enumField, final String finalProperty,
|
private Predicate getNotEqualToPredicate(final RsqlField rsqlField,
|
||||||
final Path<Object> fieldPath, final Object transformedValue) {
|
final Path<Object> fieldPath, final Object transformedValue) {
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNotNull(fieldPath);
|
return cb.isNotNull(fieldPath);
|
||||||
@@ -215,9 +214,9 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
return cb.and(cb.isNotNull(fieldPath), cb.notEqual(pathOfString(fieldPath), ""));
|
return cb.and(cb.isNotNull(fieldPath), cb.notEqual(pathOfString(fieldPath), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
final String[] fieldNames = rsqlField.getSubAttributes();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return cb.or(cb.isNull(fieldPath), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
return cb.or(cb.isNull(fieldPath), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
@@ -226,7 +225,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
return toNotExistsSubQueryPredicate(enumField, fieldNames, expressionToCompare ->
|
return toNotExistsSubQueryPredicate(rsqlField, expressionToCompare ->
|
||||||
isPattern(transformedValueStr) ? // a pattern, use like
|
isPattern(transformedValueStr) ? // a pattern, use like
|
||||||
like(expressionToCompare, toSQL(transformedValueStr)) :
|
like(expressionToCompare, toSQL(transformedValueStr)) :
|
||||||
equal(expressionToCompare, transformedValueStr));
|
equal(expressionToCompare, transformedValueStr));
|
||||||
@@ -235,23 +234,22 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getOutPredicate(final A enumField, final String finalProperty, final Path<Object> fieldPath,
|
private Predicate getOutPredicate(final RsqlField rsqlField, final Path<Object> fieldPath,
|
||||||
final List<Object> transformedValues) {
|
final List<Object> transformedValues) {
|
||||||
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
final String[] subAttributes = rsqlField.getSubAttributes();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
if (isSimpleField(subAttributes, rsqlField.getEnumValue().isMap())) {
|
||||||
return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues)));
|
return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
return toNotExistsSubQueryPredicate(enumField, fieldNames,
|
return toNotExistsSubQueryPredicate(rsqlField, expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
expressionToCompare -> in(expressionToCompare, transformedValues));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Object> getFieldPath(
|
private Path<Object> getFieldPath(final Root<?> root, final RsqlField rsqlField) {
|
||||||
final Root<?> root, final String[] split, final boolean isMapKeyField) {
|
final String[] split = rsqlField.getSubAttributes();
|
||||||
Path<Object> fieldPath = null;
|
Path<Object> fieldPath = null;
|
||||||
for (int i = 0, end = isMapKeyField ? split.length - 1 : split.length; i < end; i++) {
|
for (int i = 0, end = rsqlField.getEnumValue().isMap() ? split.length - 1 : split.length; i < end; i++) {
|
||||||
final String fieldNameSplit = split[i];
|
final String fieldNameSplit = split[i];
|
||||||
fieldPath = fieldPath == null ? getPath(root, fieldNameSplit) : fieldPath.get(fieldNameSplit);
|
fieldPath = fieldPath == null ? getPath(root, fieldNameSplit) : fieldPath.get(fieldNameSplit);
|
||||||
}
|
}
|
||||||
@@ -360,14 +358,14 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
private Predicate toNotExistsSubQueryPredicate(final A enumField, final String[] fieldNames, final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
private Predicate toNotExistsSubQueryPredicate(final RsqlField rsqlField, final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
||||||
final Class<?> javaType = root.getJavaType();
|
final Class<?> javaType = root.getJavaType();
|
||||||
final Subquery<?> subquery = query.subquery(javaType);
|
final Subquery<?> subquery = query.subquery(javaType);
|
||||||
final Root subqueryRoot = subquery.from(javaType);
|
final Root subqueryRoot = subquery.from(javaType);
|
||||||
final Predicate equalPredicate = cb.equal(root.get(enumField.identifierFieldName()),
|
final Predicate equalPredicate = cb.equal(root.get(rsqlField.getEnumValue().identifierFieldName()),
|
||||||
subqueryRoot.get(enumField.identifierFieldName()));
|
subqueryRoot.get(rsqlField.getEnumValue().identifierFieldName()));
|
||||||
final Expression<String> expressionToCompare = getExpressionToCompare(enumField,
|
final Expression<String> expressionToCompare = getExpressionToCompare(rsqlField.getEnumValue(),
|
||||||
getFieldPath(subqueryRoot, fieldNames, enumField.isMap()));
|
getFieldPath(subqueryRoot, rsqlField));
|
||||||
final Predicate subQueryPredicate = subQueryPredicateProvider.apply(expressionToCompare);
|
final Predicate subQueryPredicate = subQueryPredicateProvider.apply(expressionToCompare);
|
||||||
subquery.select(subqueryRoot).where(cb.and(equalPredicate, subQueryPredicate));
|
subquery.select(subqueryRoot).where(cb.and(equalPredicate, subQueryPredicate));
|
||||||
return cb.not(cb.exists(subquery));
|
return cb.not(cb.exists(subquery));
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import lombok.AccessLevel;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.text.StrLookup;
|
import org.apache.commons.lang3.text.StrLookup;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||||
@@ -82,7 +82,7 @@ public final class RSQLUtility {
|
|||||||
* given RSQL query.
|
* given RSQL query.
|
||||||
*
|
*
|
||||||
* @param rsql the rsql query to be parsed
|
* @param rsql the rsql query to be parsed
|
||||||
* @param fieldNameProvider the enum class type which implements the {@link FieldNameProvider}
|
* @param fieldNameProvider the enum class type which implements the {@link RsqlQueryField}
|
||||||
* @param virtualPropertyReplacer holds the logic how the known macros have to be resolved; may be <code>null</code>
|
* @param virtualPropertyReplacer holds the logic how the known macros have to be resolved; may be <code>null</code>
|
||||||
* @param database database in use
|
* @param database database in use
|
||||||
*
|
*
|
||||||
@@ -91,7 +91,7 @@ public final class RSQLUtility {
|
|||||||
* given {@code fieldNameProvider}
|
* given {@code fieldNameProvider}
|
||||||
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
|
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
|
||||||
*/
|
*/
|
||||||
public static <A extends Enum<A> & FieldNameProvider, T> Specification<T> buildRsqlSpecification(
|
public static <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification(
|
||||||
final String rsql, final Class<A> fieldNameProvider,
|
final String rsql, final Class<A> fieldNameProvider,
|
||||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||||
return new RSQLSpecification<>(rsql, fieldNameProvider, virtualPropertyReplacer, database);
|
return new RSQLSpecification<>(rsql, fieldNameProvider, virtualPropertyReplacer, database);
|
||||||
@@ -106,7 +106,7 @@ public final class RSQLUtility {
|
|||||||
* @throws RSQLParserException if RSQL syntax is invalid
|
* @throws RSQLParserException if RSQL syntax is invalid
|
||||||
* @throws RSQLParameterUnsupportedFieldException if RSQL key is not allowed
|
* @throws RSQLParameterUnsupportedFieldException if RSQL key is not allowed
|
||||||
*/
|
*/
|
||||||
public static <A extends Enum<A> & FieldNameProvider> void validateRsqlFor(
|
public static <A extends Enum<A> & RsqlQueryField> void validateRsqlFor(
|
||||||
final String rsql, final Class<A> fieldNameProvider) {
|
final String rsql, final Class<A> fieldNameProvider) {
|
||||||
final RSQLVisitor<Void, String> visitor =
|
final RSQLVisitor<Void, String> visitor =
|
||||||
RsqlConfigHolder.getInstance().getRsqlVisitorFactory().validationRsqlVisitor(fieldNameProvider);
|
RsqlConfigHolder.getInstance().getRsqlVisitorFactory().validationRsqlVisitor(fieldNameProvider);
|
||||||
@@ -127,7 +127,7 @@ public final class RSQLUtility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class RSQLSpecification<A extends Enum<A> & FieldNameProvider, T> implements Specification<T> {
|
private static final class RSQLSpecification<A extends Enum<A> & RsqlQueryField, T> implements Specification<T> {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -1196,7 +1196,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
+ "from target/controller. Expected behaviour is that in case of OK finished update the target will go to "
|
+ "from target/controller. Expected behaviour is that in case of OK finished update the target will go to "
|
||||||
+ "IN_SYNC status and installed DS is set to the assigned DS entry.")
|
+ "IN_SYNC status and installed DS is set to the assigned DS entry.")
|
||||||
void assignDistributionSetAndAddFinishedActionStatus() {
|
void assignDistributionSetAndAddFinishedActionStatus() {
|
||||||
final PageRequest pageRequest = PageRequest.of(0, 100, Direction.ASC, ActionStatusFields.ID.getFieldName());
|
final PageRequest pageRequest = PageRequest.of(0, 100, Direction.ASC, ActionStatusFields.ID.getJpaEntityFieldName());
|
||||||
|
|
||||||
final DeploymentResult deployResWithDsA = prepareComplexRepo("undep-A-T", 2, "dep-A-T", 4, 1, "dsA");
|
final DeploymentResult deployResWithDsA = prepareComplexRepo("undep-A-T", 2, "dep-A-T", 4, 1, "dsA");
|
||||||
final DeploymentResult deployResWithDsB = prepareComplexRepo("undep-B-T", 3, "dep-B-T", 5, 1, "dsB");
|
final DeploymentResult deployResWithDsB = prepareComplexRepo("undep-B-T", 3, "dep-B-T", 5, 1, "dsB");
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import jakarta.persistence.criteria.CriteriaBuilder;
|
|||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||||
@@ -39,11 +39,11 @@ public class RSQLToSQL {
|
|||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T, A extends Enum<A> & FieldNameProvider> String toSQL(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
public <T, A extends Enum<A> & RsqlQueryField> String toSQL(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||||
return createDbQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor).getSQLString();
|
return createDbQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor).getSQLString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T, A extends Enum<A> & FieldNameProvider> DatabaseQuery createDbQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
public <T, A extends Enum<A> & RsqlQueryField> DatabaseQuery createDbQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||||
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor);
|
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor);
|
||||||
final TypedQuery<?> typedQuery = entityManager.createQuery(query);
|
final TypedQuery<?> typedQuery = entityManager.createQuery(query);
|
||||||
// executes the query - otherwise the SQL string is not generated
|
// executes the query - otherwise the SQL string is not generated
|
||||||
@@ -52,7 +52,7 @@ public class RSQLToSQL {
|
|||||||
return typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
|
return typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T, A extends Enum<A> & FieldNameProvider> CriteriaQuery<T> createQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
private <T, A extends Enum<A> & RsqlQueryField> CriteriaQuery<T> createQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||||
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
|
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
|
||||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||||
return query.where(
|
return query.where(
|
||||||
@@ -65,7 +65,7 @@ public class RSQLToSQL {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T, A extends Enum<A> & FieldNameProvider> Predicate toPredicate(
|
private <T, A extends Enum<A> & RsqlQueryField> Predicate toPredicate(
|
||||||
final String rsql,
|
final String rsql,
|
||||||
final Class<A> fieldsClass, final VirtualPropertyReplacer virtualPropertyReplacer,
|
final Class<A> fieldsClass, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||||
final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
|
final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
|||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.TargetFields;
|
import org.eclipse.hawkbit.repository.TargetFields;
|
||||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||||
@@ -52,7 +52,7 @@ public class RSQLToSQLTest {
|
|||||||
print(JpaTarget.class, TargetFields.class, "(tag!=TAG1 or tag !=TAG2)");
|
print(JpaTarget.class, TargetFields.class, "(tag!=TAG1 or tag !=TAG2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T, A extends Enum<A> & FieldNameProvider> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
|
private <T, A extends Enum<A> & RsqlQueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
|
||||||
System.out.println(rsql);
|
System.out.println(rsql);
|
||||||
System.out.println("\tlegacy:\n" +
|
System.out.println("\tlegacy:\n" +
|
||||||
"\t\t" + rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, true));
|
"\t\t" + rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, true));
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import jakarta.persistence.metamodel.EntityType;
|
|||||||
import jakarta.persistence.metamodel.SingularAttribute;
|
import jakarta.persistence.metamodel.SingularAttribute;
|
||||||
import jakarta.persistence.metamodel.Type;
|
import jakarta.persistence.metamodel.Type;
|
||||||
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||||
import org.eclipse.hawkbit.repository.TargetFields;
|
import org.eclipse.hawkbit.repository.TargetFields;
|
||||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||||
@@ -554,7 +554,7 @@ public class RSQLUtilityTest {
|
|||||||
return (Path<Y>) path;
|
return (Path<Y>) path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TestFieldEnum implements FieldNameProvider {
|
private enum TestFieldEnum implements RsqlQueryField {
|
||||||
TESTFIELD("testfield"), TESTFIELD_WITH_SUB_ENTITIES("testfieldWithSubEntities", "subentity11", "subentity22");
|
TESTFIELD("testfield"), TESTFIELD_WITH_SUB_ENTITIES("testfieldWithSubEntities", "subentity11", "subentity22");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String fieldName;
|
||||||
@@ -570,7 +570,7 @@ public class RSQLUtilityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFieldName() {
|
public String getJpaEntityFieldName() {
|
||||||
return this.fieldName;
|
return this.fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public final class MgmtTargetMapper {
|
|||||||
.withRel(MgmtRestConstants.TARGET_V1_ATTRIBUTES).expand());
|
.withRel(MgmtRestConstants.TARGET_V1_ATTRIBUTES).expand());
|
||||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionHistory(response.getControllerId(), 0,
|
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionHistory(response.getControllerId(), 0,
|
||||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||||
ActionFields.ID.getFieldName() + ":" + SortDirection.DESC, null))
|
ActionFields.ID.getJpaEntityFieldName() + ":" + SortDirection.DESC, null))
|
||||||
.withRel(MgmtRestConstants.TARGET_V1_ACTIONS).expand());
|
.withRel(MgmtRestConstants.TARGET_V1_ACTIONS).expand());
|
||||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
|
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
|
||||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||||
@@ -316,7 +316,7 @@ public final class MgmtTargetMapper {
|
|||||||
|
|
||||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0,
|
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0,
|
||||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||||
ActionStatusFields.ID.getFieldName() + ":" + SortDirection.DESC))
|
ActionStatusFields.ID.getJpaEntityFieldName() + ":" + SortDirection.DESC))
|
||||||
.withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS).expand());
|
.withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS).expand());
|
||||||
|
|
||||||
final Rollout rollout = action.getRollout();
|
final Rollout rollout = action.getRollout();
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeTargetSortParam(final String sortParam) {
|
static Sort sanitizeTargetSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, TargetFields.CONTROLLERID.getFieldName());
|
return Sort.by(Direction.ASC, TargetFields.CONTROLLERID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeTargetTypeSortParam(final String sortParam) {
|
static Sort sanitizeTargetTypeSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, TargetTypeFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, TargetTypeFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(TargetTypeFields.class, sortParam));
|
return Sort.by(SortUtility.parse(TargetTypeFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeTagSortParam(final String sortParam) {
|
static Sort sanitizeTagSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, TagFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, TagFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(TagFields.class, sortParam));
|
return Sort.by(SortUtility.parse(TagFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeTargetFilterQuerySortParam(final String sortParam) {
|
static Sort sanitizeTargetFilterQuerySortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, TargetFilterQueryFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, TargetFilterQueryFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(TargetFilterQueryFields.class, sortParam));
|
return Sort.by(SortUtility.parse(TargetFilterQueryFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeSoftwareModuleSortParam(final String sortParam) {
|
static Sort sanitizeSoftwareModuleSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, SoftwareModuleFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, SoftwareModuleFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(SoftwareModuleFields.class, sortParam));
|
return Sort.by(SortUtility.parse(SoftwareModuleFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeSoftwareModuleTypeSortParam(final String sortParam) {
|
static Sort sanitizeSoftwareModuleTypeSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, SoftwareModuleTypeFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, SoftwareModuleTypeFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(SoftwareModuleTypeFields.class, sortParam));
|
return Sort.by(SortUtility.parse(SoftwareModuleTypeFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeDistributionSetSortParam(final String sortParam) {
|
static Sort sanitizeDistributionSetSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, DistributionSetFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, DistributionSetFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(DistributionSetFields.class, sortParam));
|
return Sort.by(SortUtility.parse(DistributionSetFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeDistributionSetTypeSortParam(final String sortParam) {
|
static Sort sanitizeDistributionSetTypeSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, DistributionSetTypeFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, DistributionSetTypeFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(DistributionSetTypeFields.class, sortParam));
|
return Sort.by(SortUtility.parse(DistributionSetTypeFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ public final class PagingUtility {
|
|||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default sort is DESC in case of action to match behavior
|
// default sort is DESC in case of action to match behavior
|
||||||
// of management UI (last entry on top)
|
// of management UI (last entry on top)
|
||||||
return Sort.by(Direction.DESC, ActionFields.ID.getFieldName());
|
return Sort.by(Direction.DESC, ActionFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(ActionFields.class, sortParam));
|
return Sort.by(SortUtility.parse(ActionFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ public final class PagingUtility {
|
|||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default sort is DESC in case of action status to match behavior
|
// default sort is DESC in case of action status to match behavior
|
||||||
// of management UI (last entry on top)
|
// of management UI (last entry on top)
|
||||||
return Sort.by(Direction.DESC, ActionStatusFields.ID.getFieldName());
|
return Sort.by(Direction.DESC, ActionStatusFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(ActionStatusFields.class, sortParam));
|
return Sort.by(SortUtility.parse(ActionStatusFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeDistributionSetMetadataSortParam(final String sortParam) {
|
static Sort sanitizeDistributionSetMetadataSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, DistributionSetMetadataFields.KEY.getFieldName());
|
return Sort.by(Direction.ASC, DistributionSetMetadataFields.KEY.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(DistributionSetMetadataFields.class, sortParam));
|
return Sort.by(SortUtility.parse(DistributionSetMetadataFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeSoftwareModuleMetadataSortParam(final String sortParam) {
|
static Sort sanitizeSoftwareModuleMetadataSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, SoftwareModuleMetadataFields.KEY.getFieldName());
|
return Sort.by(Direction.ASC, SoftwareModuleMetadataFields.KEY.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(SoftwareModuleMetadataFields.class, sortParam));
|
return Sort.by(SortUtility.parse(SoftwareModuleMetadataFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeRolloutSortParam(final String sortParam) {
|
static Sort sanitizeRolloutSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, RolloutFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, RolloutFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(RolloutFields.class, sortParam));
|
return Sort.by(SortUtility.parse(RolloutFields.class, sortParam));
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ public final class PagingUtility {
|
|||||||
static Sort sanitizeRolloutGroupSortParam(final String sortParam) {
|
static Sort sanitizeRolloutGroupSortParam(final String sortParam) {
|
||||||
if (sortParam == null) {
|
if (sortParam == null) {
|
||||||
// default
|
// default
|
||||||
return Sort.by(Direction.ASC, RolloutGroupFields.ID.getFieldName());
|
return Sort.by(Direction.ASC, RolloutGroupFields.ID.getJpaEntityFieldName());
|
||||||
}
|
}
|
||||||
return Sort.by(SortUtility.parse(RolloutGroupFields.class, sortParam));
|
return Sort.by(SortUtility.parse(RolloutGroupFields.class, sortParam));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest {
|
|||||||
assertThat(actions).hasSize(2);
|
assertThat(actions).hasSize(2);
|
||||||
updateActionStatus(actions.get(0), Status.FINISHED, null, "test");
|
updateActionStatus(actions.get(0), Status.FINISHED, null, "test");
|
||||||
|
|
||||||
final PageRequest pageRequest = PageRequest.of(0, 1000, Direction.ASC, ActionFields.ID.getFieldName());
|
final PageRequest pageRequest = PageRequest.of(0, 1000, Direction.ASC, ActionFields.ID.getJpaEntityFieldName());
|
||||||
final Action action = deploymentManagement.findActionsByTarget(knownTargetId, pageRequest).getContent().get(0);
|
final Action action = deploymentManagement.findActionsByTarget(knownTargetId, pageRequest).getContent().get(0);
|
||||||
|
|
||||||
final ActionStatus status = deploymentManagement.findActionStatusByAction(PAGE, action.getId()).getContent()
|
final ActionStatus status = deploymentManagement.findActionStatusByAction(PAGE, action.getId()).getContent()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||||
import org.eclipse.hawkbit.rest.exception.SortParameterSyntaxErrorException;
|
import org.eclipse.hawkbit.rest.exception.SortParameterSyntaxErrorException;
|
||||||
import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedDirectionException;
|
import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedDirectionException;
|
||||||
import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.rest.exception.SortParameterUnsupportedFieldException;
|
||||||
@@ -53,11 +53,11 @@ public final class SortUtility {
|
|||||||
* should be related to.
|
* should be related to.
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the type of the enumeration which must be derived from
|
* the type of the enumeration which must be derived from
|
||||||
* {@link FieldNameProvider}
|
* {@link RsqlQueryField}
|
||||||
* @param sortString
|
* @param sortString
|
||||||
* the string representation of the query parameters. Might be
|
* the string representation of the query parameters. Might be
|
||||||
* {@code null} or an empty string.
|
* {@code null} or an empty string.
|
||||||
* @return a list which holds the {@link FieldNameProvider} and the specific
|
* @return a list which holds the {@link RsqlQueryField} and the specific
|
||||||
* {@link Direction} for them as a tuple. Never {@code null}. In
|
* {@link Direction} for them as a tuple. Never {@code null}. In
|
||||||
* case of no sorting parameters an empty map will be returned.
|
* case of no sorting parameters an empty map will be returned.
|
||||||
* @throws SortParameterSyntaxErrorException
|
* @throws SortParameterSyntaxErrorException
|
||||||
@@ -67,7 +67,7 @@ public final class SortUtility {
|
|||||||
* @throws SortParameterUnsupportedDirectionException
|
* @throws SortParameterUnsupportedDirectionException
|
||||||
* if the given direction is not "ASC" or "DESC"
|
* if the given direction is not "ASC" or "DESC"
|
||||||
*/
|
*/
|
||||||
public static <T extends Enum<T> & FieldNameProvider> List<Order> parse(final Class<T> enumType,
|
public static <T extends Enum<T> & RsqlQueryField> List<Order> parse(final Class<T> enumType,
|
||||||
final String sortString) throws SortParameterSyntaxErrorException {
|
final String sortString) throws SortParameterSyntaxErrorException {
|
||||||
final List<Order> parsedSortings = new ArrayList<>();
|
final List<Order> parsedSortings = new ArrayList<>();
|
||||||
// scan the sort tuples e.g. field:direction
|
// scan the sort tuples e.g. field:direction
|
||||||
@@ -84,7 +84,7 @@ public final class SortUtility {
|
|||||||
final T identifier = getAttributeIdentifierByName(enumType, fieldName);
|
final T identifier = getAttributeIdentifierByName(enumType, fieldName);
|
||||||
|
|
||||||
final Direction sortDirection = getDirection(sortDirectionStr);
|
final Direction sortDirection = getDirection(sortDirectionStr);
|
||||||
parsedSortings.add(new Order(sortDirection, identifier.getFieldName()));
|
parsedSortings.add(new Order(sortDirection, identifier.getJpaEntityFieldName()));
|
||||||
} else {
|
} else {
|
||||||
throw new SortParameterSyntaxErrorException();
|
throw new SortParameterSyntaxErrorException();
|
||||||
}
|
}
|
||||||
@@ -103,12 +103,12 @@ public final class SortUtility {
|
|||||||
* the name of the enum
|
* the name of the enum
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the type of the enumeration which must be derived from
|
* the type of the enumeration which must be derived from
|
||||||
* {@link FieldNameProvider}
|
* {@link RsqlQueryField}
|
||||||
* @return the corresponding enum
|
* @return the corresponding enum
|
||||||
* @throws SortParameterUnsupportedFieldException
|
* @throws SortParameterUnsupportedFieldException
|
||||||
* if there is no matching enum for the specified name
|
* if there is no matching enum for the specified name
|
||||||
*/
|
*/
|
||||||
private static <T extends Enum<T> & FieldNameProvider> T getAttributeIdentifierByName(final Class<T> enumType,
|
private static <T extends Enum<T> & RsqlQueryField> T getAttributeIdentifierByName(final Class<T> enumType,
|
||||||
final String name) {
|
final String name) {
|
||||||
try {
|
try {
|
||||||
return Enum.valueOf(enumType, name.toUpperCase());
|
return Enum.valueOf(enumType, name.toUpperCase());
|
||||||
|
|||||||
Reference in New Issue
Block a user