diff --git a/criteria/common/test/org/immutables/criteria/personmodel/AbstractPersonTest.java b/criteria/common/test/org/immutables/criteria/personmodel/AbstractPersonTest.java index 5bf52cd44..15bbaface 100644 --- a/criteria/common/test/org/immutables/criteria/personmodel/AbstractPersonTest.java +++ b/criteria/common/test/org/immutables/criteria/personmodel/AbstractPersonTest.java @@ -277,7 +277,10 @@ public void basic() { check(person.fullName.is("John") .age.is(22)).hasSize(1); check(person.fullName.is("_MISSING_")).empty(); + check(person.fullName.in(Collections.emptyList())).empty(); + check(person.fullName.in(Collections.singleton("John"))).hasSize(1); check(person.fullName.in("John", "test2")).hasSize(1); + check(person.fullName.notIn(Collections.singleton("John"))).empty(); check(person.fullName.notIn("John", "test2")).empty(); // true / false diff --git a/criteria/common/test/org/immutables/criteria/typemodel/StringTemplate.java b/criteria/common/test/org/immutables/criteria/typemodel/StringTemplate.java index dc6a9f7aa..4292ee270 100644 --- a/criteria/common/test/org/immutables/criteria/typemodel/StringTemplate.java +++ b/criteria/common/test/org/immutables/criteria/typemodel/StringTemplate.java @@ -212,6 +212,31 @@ protected void optional() { values(string.optional.is("")).isEmpty(); } + /** + * cases for {@code foo in [1]} or {@code foo not in [1]}. + * When list has just one element + */ + @Test + void inNotIn_singleElement() { + repository.insert(generator.get().withId("id1").withValue("value1")); + repository.insert(generator.get().withId("id2").withValue("")); + + // for id + ids(string.id.in(Collections.emptyList())).isEmpty(); + ids(string.id.in(Collections.singleton("id1"))).isOf("id1"); + ids(string.id.notIn(Collections.singleton("id1"))).isOf("id2"); + ids(string.id.notIn(Collections.singleton("id2"))).isOf("id1"); + ids(string.id.notIn(Collections.emptyList())).hasContentInAnyOrder("id1", "id2"); + + // for value + ids(string.value.in(Collections.emptyList())).isEmpty(); + ids(string.value.in(Collections.singleton("value1"))).isOf("id1"); + ids(string.value.notIn(Collections.singleton("value1"))).isOf("id2"); + ids(string.value.notIn(Collections.singleton(""))).isOf("id1"); + ids(string.value.notIn(Collections.emptyList())).hasContentInAnyOrder("id1", "id2"); + + } + /** * validate {@code one() / oneOrNone() / exists()} methods */ diff --git a/criteria/mongo/src/org/immutables/criteria/mongo/FindVisitor.java b/criteria/mongo/src/org/immutables/criteria/mongo/FindVisitor.java index 234d1a420..ac7206a73 100644 --- a/criteria/mongo/src/org/immutables/criteria/mongo/FindVisitor.java +++ b/criteria/mongo/src/org/immutables/criteria/mongo/FindVisitor.java @@ -123,6 +123,12 @@ private Bson binaryCall(Call call) { if (op == Operators.IN || op == Operators.NOT_IN) { final List values = Visitors.toConstant(call.arguments().get(1)).values(); Preconditions.checkNotNull(values, "not expected to be null for %s", op); + if (values.size() == 1) { + // optimization: convert IN, NIN (where argument is a list with single element) into EQ / NE + Operators newOperator = op == Operators.IN ? Operators.EQUAL : Operators.NOT_EQUAL; + Call newCall = Expressions.call(newOperator, call.arguments().get(0), Expressions.constant(values.get(0))); + return binaryCall(newCall); + } return op == Operators.IN ? Filters.in(field, values) : Filters.nin(field, values); }