@@ -13,6 +13,7 @@ private enum Operator {
1313 // Logical operators
1414 AND ("And" , WeaviateProtoBase .Filters .Operator .OPERATOR_AND ),
1515 OR ("Or" , WeaviateProtoBase .Filters .Operator .OPERATOR_OR ),
16+ NOT ("Noe" , WeaviateProtoBase .Filters .Operator .OPERATOR_NOT ),
1617
1718 // Comparison operators
1819 EQUAL ("Equal" , WeaviateProtoBase .Filters .Operator .OPERATOR_EQUAL ),
@@ -24,6 +25,7 @@ private enum Operator {
2425 LIKE ("Like" , WeaviateProtoBase .Filters .Operator .OPERATOR_LIKE ),
2526 CONTAINS_ANY ("ContainsAny" , WeaviateProtoBase .Filters .Operator .OPERATOR_CONTAINS_ANY ),
2627 CONTAINS_ALL ("ContainsAll" , WeaviateProtoBase .Filters .Operator .OPERATOR_CONTAINS_ALL ),
28+ CONTAINS_NONE ("ContainsNone" , WeaviateProtoBase .Filters .Operator .OPERATOR_CONTAINS_NONE ),
2729 WITHIN_GEO_RANGE ("WithinGeoRange" , WeaviateProtoBase .Filters .Operator .OPERATOR_WITHIN_GEO_RANGE );
2830
2931 /** String representation for better debug logs. */
@@ -62,35 +64,47 @@ private Where(Operator operator, List<WhereOperand> operands) {
6264
6365 @ Override
6466 public boolean isEmpty () {
65- // Guard against Where.and(Where.or(), Where.and()) situation.
67+ // Guard against Where.and(Where.or(), Where.and(), Where.not() ) situation.
6668 return operands .isEmpty ()
67- || operands .stream ().allMatch (operator -> operator .isEmpty ());
69+ || operands .stream ().allMatch (operator -> operator == null | operator .isEmpty ());
6870 }
6971
7072 @ Override
7173 public String toString () {
74+ if (operator == Operator .NOT ) {
75+ return "%s %s" .formatted (operator , operands .get (0 ));
76+ }
7277 var operandStrings = operands .stream ().map (Object ::toString ).toList ();
7378 return "Where(" + String .join (" " + operator .toString () + " " , operandStrings ) + ")" ;
7479 }
7580
7681 // Logical operators return a complete operand.
7782 // --------------------------------------------------------------------------
78- public static Where and (WhereOperand ... operands ) {
83+ public static Where and (final WhereOperand ... operands ) {
7984 return new Where (Operator .AND , operands );
8085 }
8186
82- public static Where and (List <WhereOperand > operands ) {
87+ public static Where and (final List <WhereOperand > operands ) {
8388 return new Where (Operator .AND , operands );
8489 }
8590
86- public static Where or (WhereOperand ... operands ) {
91+ public static Where or (final WhereOperand ... operands ) {
8792 return new Where (Operator .OR , operands );
8893 }
8994
90- public static Where or (List <WhereOperand > operands ) {
95+ public static Where or (final List <WhereOperand > operands ) {
9196 return new Where (Operator .OR , operands );
9297 }
9398
99+ public static Where not (final WhereOperand operand ) {
100+ return new Where (Operator .NOT , operand );
101+ }
102+
103+ /** Negate this expression. */
104+ public Where not () {
105+ return not (this );
106+ }
107+
94108 // Comparison operators return fluid builder.
95109 // --------------------------------------------------------------------------
96110
@@ -463,6 +477,32 @@ public Where containsAll(OffsetDateTime... values) {
463477 return new Where (Operator .CONTAINS_ALL , left , new DateArrayOperand (values ));
464478 }
465479
480+ // ContainsNone
481+ // ------------------------------------------------------------------------
482+ public Where containsNone (String value ) {
483+ return new Where (Operator .CONTAINS_NONE , left , new TextOperand (value ));
484+ }
485+
486+ public Where containsNone (String ... values ) {
487+ return new Where (Operator .CONTAINS_NONE , left , new TextArrayOperand (values ));
488+ }
489+
490+ public Where containsNone (Boolean ... values ) {
491+ return new Where (Operator .CONTAINS_NONE , left , new BooleanArrayOperand (values ));
492+ }
493+
494+ public Where containsNone (Long ... values ) {
495+ return new Where (Operator .CONTAINS_NONE , left , new IntegerArrayOperand (values ));
496+ }
497+
498+ public Where containsNone (Double ... values ) {
499+ return new Where (Operator .CONTAINS_NONE , left , new NumberArrayOperand (values ));
500+ }
501+
502+ public Where containsNone (OffsetDateTime ... values ) {
503+ return new Where (Operator .CONTAINS_NONE , left , new DateArrayOperand (values ));
504+ }
505+
466506 // WithinGeoRange
467507 // ------------------------------------------------------------------------
468508 public Where withinGeoRange (float lat , float lon , float maxDistance ) {
@@ -475,25 +515,19 @@ public void appendTo(WeaviateProtoBase.Filters.Builder where) {
475515 if (isEmpty ()) {
476516 return ;
477517 }
478- switch (operands .size ()) {
479- case 0 :
480- return ;
481- case 1 : // no need for operator
482- operands .get (0 ).appendTo (where );
483- return ;
484- default :
485- if (operator .equals (Operator .AND ) || operator .equals (Operator .OR )) {
486- operands .forEach (op -> {
487- Filters .Builder nested = Filters .newBuilder ();
488- op .appendTo (nested );
489- where .addFilters (nested );
490- });
491- } else {
492- // Comparison operators: eq, gt, lt, like, etc.
493- operands .forEach (op -> op .appendTo (where ));
494- }
495- }
518+
496519 operator .appendTo (where );
520+
521+ if (operator == Operator .AND || operator == Operator .OR || operator == Operator .NOT ) {
522+ operands .forEach (op -> {
523+ var nested = Filters .newBuilder ();
524+ op .appendTo (nested );
525+ where .addFilters (nested );
526+ });
527+ } else {
528+ // Comparison operators: eq, gt, lt, like, etc.
529+ operands .forEach (op -> op .appendTo (where ));
530+ }
497531 }
498532
499533 @ SuppressWarnings ("unchecked" )
@@ -522,13 +556,13 @@ static WhereOperand fromObject(Object value) {
522556 return new NumberArrayOperand (dblarr );
523557 } else if (value instanceof OffsetDateTime [] datearr ) {
524558 return new DateArrayOperand (datearr );
525- } else if (value instanceof List ) {
526- if ((( List <?>) value ) .isEmpty ()) {
559+ } else if (value instanceof List <?> list ) {
560+ if (list .isEmpty ()) {
527561 throw new IllegalArgumentException (
528562 "Filter with non-reifiable type (List<T>) cannot be empty, use an array instead" );
529563 }
530564
531- Object first = (( List <?>) value ) .get (0 );
565+ Object first = list .get (0 );
532566 if (first instanceof String ) {
533567 return new TextArrayOperand ((List <String >) value );
534568 } else if (first instanceof Boolean ) {
0 commit comments