@@ -9,17 +9,30 @@ import (
99 "github.com/specterops/dawgs/cypher/models/pgsql/pgd"
1010)
1111
12- func newPGKindIDMatcher (scope * Scope , treeTranslator * ExpressionTreeTranslator , binding * BoundIdentifier , kindIDs []int16 ) error {
12+ func newPGKindIDMatcher (scope * Scope , treeTranslator * ExpressionTreeTranslator , binding * BoundIdentifier , kindIDs []int16 , isExclusive bool ) error {
1313 kindIDsLiteral := pgsql .NewLiteral (kindIDs , pgsql .Int2Array )
1414
1515 switch binding .DataType {
1616 case pgsql .NodeComposite , pgsql .ExpansionRootNode , pgsql .ExpansionTerminalNode :
1717 treeTranslator .PushOperand (pgd .Column (binding .Identifier , pgsql .ColumnKindIDs ))
1818 treeTranslator .PushOperand (kindIDsLiteral )
1919
20- return treeTranslator .CompleteBinaryExpression (scope , pgsql .OperatorPGArrayLHSContainsRHS )
20+ // In an exclusive kind match, if there are no kind IDs to be matched on,
21+ // the behavior of the contains (`@>`) operator will select all nodes, which drastically differs from
22+ // the overlap operator's behavior (matches nothing), so preserve the previous behavior.
23+ //
24+ // There shouldn't be a case in the Cypher frontend where a kind ID matcher is
25+ // created without any kind IDs to match on, but `query.Kind`/`query.KindIn` can create those
26+ // edge cases. We want any existing `query.Kind`/`query.KindIn` usages to match the previous behavior
27+ // expectations by using overlap/`&&`, which protects from the empty RHS problem.
28+ if isExclusive && len (kindIDs ) > 0 {
29+ return treeTranslator .CompleteBinaryExpression (scope , pgsql .OperatorPGArrayLHSContainsRHS )
30+ } else {
31+ return treeTranslator .CompleteBinaryExpression (scope , pgsql .OperatorPGArrayOverlap )
32+ }
2133
2234 case pgsql .EdgeComposite , pgsql .ExpansionEdge :
35+ // Edge kind checking is a strict equality, so the IsExclusive condition does not apply here.
2336 treeTranslator .PushOperand (pgsql.CompoundIdentifier {binding .Identifier , pgsql .ColumnKindID })
2437 treeTranslator .PushOperand (pgsql .NewAnyExpressionHinted (kindIDsLiteral ))
2538
@@ -39,6 +52,6 @@ func (s *Translator) translateKindMatcher(kindMatcher *cypher.KindMatcher) error
3952 } else if kindIDs , err := s .kindMapper .MapKinds (kindMatcher .Kinds ); err != nil {
4053 return fmt .Errorf ("failed to translate kinds: %w" , err )
4154 } else {
42- return newPGKindIDMatcher (s .scope , s .treeTranslator , binding , kindIDs )
55+ return newPGKindIDMatcher (s .scope , s .treeTranslator , binding , kindIDs , kindMatcher . IsExclusive )
4356 }
4457}
0 commit comments