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));
|
String.format("Operator %s is not supported for map fields with value null", op));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
final MapJoin<?, ?, ?> mapPath = (MapJoin<?, ?, ?>) pathResolver.getPath(attribute);
|
// map entry with key not null (exist) - use left join per key, key/value filtered in where
|
||||||
return isNot(op)
|
final MapJoin<?, ?, ?> mapJoin = pathResolver.getJoinForWhere(attribute, split[1]);
|
||||||
? compare(comparison, toMapValuePath(pathResolver.getJoinOnInner(attribute, split[1])))
|
return cb.and(equal(mapJoin.key(), split[1]), compare(comparison, toMapValuePath(mapJoin)));
|
||||||
: cb.and(equal(mapPath.key(), split[1]), compare(comparison, toMapValuePath(mapPath)));
|
|
||||||
}
|
}
|
||||||
} else if (attribute instanceof SetAttribute<?, ?> setAttribute) {
|
} else if (attribute instanceof SetAttribute<?, ?> setAttribute) {
|
||||||
if (split.length < 2 || ObjectUtils.isEmpty(split[1])) {
|
if (split.length < 2 || ObjectUtils.isEmpty(split[1])) {
|
||||||
@@ -437,8 +436,8 @@ public class SpecificationBuilder<T> {
|
|||||||
return getCollectionPathResolver(attribute.getName()).getJoinOn(value);
|
return getCollectionPathResolver(attribute.getName()).getJoinOn(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapJoin<?, ?, ?> getJoinOnInner(final Attribute<?, ?> attribute, final Object value) {
|
private MapJoin<?, ?, ?> getJoinForWhere(final Attribute<?, ?> attribute, final Object mapKeyName) {
|
||||||
return getCollectionPathResolver(attribute.getName()).getJoinOnInner(value);
|
return getCollectionPathResolver(attribute.getName()).getJoinForWhere(mapKeyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Integer> getState() {
|
private Map<String, Integer> getState() {
|
||||||
@@ -463,7 +462,7 @@ public class SpecificationBuilder<T> {
|
|||||||
@Setter
|
@Setter
|
||||||
private int pos;
|
private int pos;
|
||||||
private final Map<Object, MapJoin<?, ?, ?>> joinOnCache = new HashMap<>();
|
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) {
|
private CollectionPathResolver(final String attributeName) {
|
||||||
this.attributeName = attributeName;
|
this.attributeName = attributeName;
|
||||||
@@ -488,12 +487,9 @@ public class SpecificationBuilder<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapJoin<?, ?, ?> getJoinOnInner(final Object value) {
|
private MapJoin<?, ?, ?> getJoinForWhere(final Object mapKeyName) {
|
||||||
return joinOnInnerCache.computeIfAbsent(value, k -> {
|
return joinForWhereCache.computeIfAbsent(mapKeyName, k ->
|
||||||
final MapJoin<?, ?, ?> mapPath = (MapJoin<?, ?, ?>) root.join(attributeName, JoinType.INNER);
|
(MapJoin<?, ?, ?>) root.join(attributeName, JoinType.LEFT));
|
||||||
mapPath.on(equal(mapPath.key(), k));
|
|
||||||
return mapPath;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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==rooty")).hasSize(1).containsExactlyInAnyOrder(root1);
|
||||||
assertThat(filter("subMap.x==*tx and subMap.y!=rootx")).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"))
|
assertThat(filter("subMap.x==*tx or subMap.x==rooty")).hasSize(5).containsExactlyInAnyOrder(root1, root2, root3, root4, root5);
|
||||||
.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!=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
|
@Test
|
||||||
|
|||||||
@@ -114,6 +114,10 @@ class RsqlToSqlTest {
|
|||||||
"((attribute.key1==00 or attribute.key1==01) and (attribute.key2==02 or attribute.key2==01) and attribute.key3==03 and updateStatus!=pending)");
|
"((attribute.key1==00 or attribute.key1==01) and (attribute.key2==02 or attribute.key2==01) and attribute.key3==03 and updateStatus!=pending)");
|
||||||
print(JpaTarget.class, TargetFields.class,
|
print(JpaTarget.class, TargetFields.class,
|
||||||
"((attribute.key1==00 or attribute.key1==01) and (attribute.key2==02 or attribute.key2==01) and attribute.key3==01 and updateStatus!=pending)");
|
"((attribute.key1==00 or attribute.key1==01) and (attribute.key2==02 or attribute.key2==01) and attribute.key3==01 and updateStatus!=pending)");
|
||||||
|
print(JpaTarget.class, TargetFields.class, "attribute.sw_1_version=in=('test1','test2') and attribute.sw_2_version=in=('test3','test4') and attribute.sw_3_version=in=('test5','test6')");
|
||||||
|
print(JpaTarget.class, TargetFields.class, "attribute.sw_1_version=out=('test1','test2') and attribute.sw_2_version=out=('test3','test4') and attribute.sw_3_version=out=('test5','test6')");
|
||||||
|
print(JpaTarget.class, TargetFields.class, "metadata.key1=in=(value1,value2) and metadata.key2=out=(value3,value4) and metadata.key3=out=(value3,value4)");
|
||||||
|
print(JpaTarget.class, TargetFields.class, "metadata.key1=out=(value1,value2) and metadata.key2=out=(value3,value4) and metadata.key3=out=(value3,value4)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user