Fix ghost joins in rsql with maps (#3088)
Signed-off-by: vasilchev <vasil.ilchev@bosch.com>
This commit is contained in:
@@ -155,10 +155,9 @@ public class SpecificationBuilder<T> {
|
||||
String.format("Operator %s is not supported for map fields with value null", op));
|
||||
};
|
||||
} else {
|
||||
final MapJoin<?, ?, ?> mapPath = (MapJoin<?, ?, ?>) pathResolver.getPath(attribute);
|
||||
return isNot(op)
|
||||
? compare(comparison, toMapValuePath(pathResolver.getJoinOnInner(attribute, split[1])))
|
||||
: cb.and(equal(mapPath.key(), split[1]), compare(comparison, toMapValuePath(mapPath)));
|
||||
// map entry with key not null (exist) - use left join per key, key/value filtered in where
|
||||
final MapJoin<?, ?, ?> mapJoin = pathResolver.getJoinForWhere(attribute, split[1]);
|
||||
return cb.and(equal(mapJoin.key(), split[1]), compare(comparison, toMapValuePath(mapJoin)));
|
||||
}
|
||||
} else if (attribute instanceof SetAttribute<?, ?> setAttribute) {
|
||||
if (split.length < 2 || ObjectUtils.isEmpty(split[1])) {
|
||||
@@ -437,8 +436,8 @@ public class SpecificationBuilder<T> {
|
||||
return getCollectionPathResolver(attribute.getName()).getJoinOn(value);
|
||||
}
|
||||
|
||||
private MapJoin<?, ?, ?> getJoinOnInner(final Attribute<?, ?> attribute, final Object value) {
|
||||
return getCollectionPathResolver(attribute.getName()).getJoinOnInner(value);
|
||||
private MapJoin<?, ?, ?> getJoinForWhere(final Attribute<?, ?> attribute, final Object mapKeyName) {
|
||||
return getCollectionPathResolver(attribute.getName()).getJoinForWhere(mapKeyName);
|
||||
}
|
||||
|
||||
private Map<String, Integer> getState() {
|
||||
@@ -463,7 +462,7 @@ public class SpecificationBuilder<T> {
|
||||
@Setter
|
||||
private int pos;
|
||||
private final Map<Object, MapJoin<?, ?, ?>> joinOnCache = new HashMap<>();
|
||||
private final Map<Object, MapJoin<?, ?, ?>> joinOnInnerCache = new HashMap<>();
|
||||
private final Map<Object, MapJoin<?, ?, ?>> joinForWhereCache = new HashMap<>();
|
||||
|
||||
private CollectionPathResolver(final String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
@@ -488,12 +487,9 @@ public class SpecificationBuilder<T> {
|
||||
});
|
||||
}
|
||||
|
||||
private MapJoin<?, ?, ?> getJoinOnInner(final Object value) {
|
||||
return joinOnInnerCache.computeIfAbsent(value, k -> {
|
||||
final MapJoin<?, ?, ?> mapPath = (MapJoin<?, ?, ?>) root.join(attributeName, JoinType.INNER);
|
||||
mapPath.on(equal(mapPath.key(), k));
|
||||
return mapPath;
|
||||
});
|
||||
private MapJoin<?, ?, ?> getJoinForWhere(final Object mapKeyName) {
|
||||
return joinForWhereCache.computeIfAbsent(mapKeyName, k ->
|
||||
(MapJoin<?, ?, ?>) root.join(attributeName, JoinType.LEFT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,10 +308,25 @@ class SpecificationBuilderTest {
|
||||
|
||||
assertThat(filter("subMap.x==*tx and subMap.y==rooty")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x==*tx and subMap.y!=rootx")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x==*tx or subMap.x==rooty"))
|
||||
.hasSize(5).containsExactlyInAnyOrder(root1, root2, root3, root4, root5);
|
||||
assertThat(filter("subMap.x==*tx or subMap.x!=rootx"))
|
||||
.hasSize(5).containsExactlyInAnyOrder(root1, root2, root3, root4, root5);
|
||||
assertThat(filter("subMap.x==*tx or subMap.x==rooty")).hasSize(5).containsExactlyInAnyOrder(root1, root2, root3, root4, root5);
|
||||
assertThat(filter("subMap.x==*tx or subMap.x!=rootx")).hasSize(5).containsExactlyInAnyOrder(root1, root2, root3, root4, root5);
|
||||
|
||||
assertThat(filter("subMap.x=out=rootx and subMap.y=out=rooty")).hasSize(1).containsExactlyInAnyOrder(root4);
|
||||
assertThat(filter("subMap.x!=rootx and subMap.y!=rooty")).hasSize(1).containsExactlyInAnyOrder(root4);
|
||||
assertThat(filter("subMap.x=out=(rootx, rooty) and subMap.y=out=(rootx, rooty)")).isEmpty();
|
||||
assertThat(filter("subMap.x=out=rootx and subMap.y=out=rooty and subMap.x=out=rooty")).isEmpty();
|
||||
assertThat(filter("subMap.x==rooty and subMap.y=out=rooty")).hasSize(1).containsExactlyInAnyOrder(root4);
|
||||
|
||||
assertThat(filter("subMap.x==rootx and subMap.y==rooty")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x==rootx and subMap.y=in=(rooty, rootz)")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x==rootx and subMap.y==rooty and subMap.x==rooty")).isEmpty();
|
||||
assertThat(filter("subMap.x==rooty and subMap.y==rootx")).hasSize(1).containsExactlyInAnyOrder(root4);
|
||||
|
||||
assertThat(filter("subMap.x=in=(rootx) and subMap.y=in=(rooty)")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x=in=(rootx,rooty) and subMap.y=in=(rootx,rooty)")).hasSize(4).containsExactlyInAnyOrder(root1, root2, root3, root4);
|
||||
assertThat(filter("subMap.x=in=(rootx) and subMap.y=in=(rooty) and subMap.x=in=(rooty)")).isEmpty();
|
||||
assertThat(filter("subMap.x=out=rooty and subMap.y=out=rootx")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
assertThat(filter("subMap.x=out=rooty and subMap.y!=rootx")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user