protected function manyFilter(DataQuery $query, $inclusive)
    {
        $this->model = $query->applyRelation($this->relation);
        $caseSensitive = $this->getCaseSensitive();

        // Check values for null
        $field = $this->getDbName();
        $values = $this->getValue();
        if (empty($values)) {
            throw new \InvalidArgumentException("Cannot filter {$field} against an empty set");
        }
        $hasNull = in_array(null, $values, true);
        if ($hasNull) {
            $values = array_filter($values, function ($value) {
                return $value !== null;
            });
        }

        $connective = '';
        if (empty($values)) {
            $predicate = '';
        } elseif ($caseSensitive === null) {
            // For queries using the default collation (no explicit case) we can use the WHERE .. NOT IN .. syntax,
            // providing simpler SQL than many WHERE .. AND .. fragments.
            $column = $this->getDbName();
            $placeholders = DB::placeholders($values);
            if ($inclusive) {
                $predicate = "$column IN ($placeholders)";
            } else {
                $predicate = "$column NOT IN ($placeholders)";
            }
        } else {
            // Generate reusable comparison clause
            $comparisonClause = DB::get_conn()->comparisonClause(
                $this->getDbName(),
                null,
                true, // exact?
                !$inclusive, // negate?
                $this->getCaseSensitive(),
                true
            );
            $count = count($values);
            if ($count > 1) {
                $connective = $inclusive ? ' OR ' : ' AND ';
                $conditions = array_fill(0, $count, $comparisonClause);
                $predicate = implode($connective, $conditions);
            } else {
                $predicate = $comparisonClause;
            }
        }

        // Always check for null when doing exclusive checks (either AND IS NOT NULL / OR IS NULL)
        // or when including the null value explicitly (OR IS NULL)
        if ($hasNull || !$inclusive) {
            // If excluding values which don't include null, or including
            // values which include null, we should do an `OR IS NULL`.
            // Otherwise we are excluding values that do include null, so `AND IS NOT NULL`.
            // Simplified from (!$inclusive && !$hasNull) || ($inclusive && $hasNull);
            $isNull = !$hasNull || $inclusive;
            $nullCondition = DB::get_conn()->nullCheckClause($field, $isNull);

            // Determine merge strategy
            if (empty($predicate)) {
                $predicate = $nullCondition;
            } else {
                // Merge null condition with predicate
                if ($isNull) {
                    $nullCondition = " OR {$nullCondition}";
                } else {
                    $nullCondition = " AND {$nullCondition}";
                }
                // If current predicate connective doesn't match the same as the null connective
                // make sure to group the prior condition
                if ($connective && (($connective === ' OR ') !== $isNull)) {
                    $predicate = "({$predicate})";
                }
                $predicate .= $nullCondition;
            }
        }

        $clause = [$predicate => $values];

        return $this->aggregate ?
            $this->applyAggregate($query, $clause) :
            $query->where($clause);
    }