Newer
Older
bremer-ios-app / Pods / Realm / Realm / RLMPredicateUtil.mm
yhornisse on 10 Sep 2023 4 KB Initial Commit
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "RLMPredicateUtil.hpp"

#include <realm/util/assert.hpp>

namespace {

struct PredicateExpressionTransformer {
    PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { }

    NSExpression *visit(NSExpression *expression) const;
    NSPredicate *visit(NSPredicate *predicate) const;

    ExpressionVisitor m_visitor;
};

NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const {
    expression = m_visitor(expression);

    switch (expression.expressionType) {
        case NSFunctionExpressionType: {
            NSMutableArray *arguments = [NSMutableArray array];
            for (NSExpression *argument in expression.arguments) {
                [arguments addObject:visit(argument)];
            }
            if (expression.operand) {
                return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments];
            } else {
                return [NSExpression expressionForFunction:expression.function arguments:arguments];
            }
        }

        case NSUnionSetExpressionType:
            return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
        case NSIntersectSetExpressionType:
            return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
        case NSMinusSetExpressionType:
            return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];

        case NSSubqueryExpressionType: {
            NSExpression *collection = expression.collection;
            // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries.
            REALM_ASSERT([collection isKindOfClass:[NSExpression class]]);
            return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)];
        }

        case NSAggregateExpressionType: {
            NSMutableArray *subexpressions = [NSMutableArray array];
            for (NSExpression *subexpression in expression.collection) {
                [subexpressions addObject:visit(subexpression)];
            }
            return [NSExpression expressionForAggregate:subexpressions];
        }

        case NSConditionalExpressionType:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
            return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)];
#pragma clang diagnostic pop

        default:
            // The remaining expression types do not contain nested expressions or predicates.
            return expression;
    }
}

NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const {
    if ([predicate isKindOfClass:[NSCompoundPredicate class]]) {
        NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate;
        NSMutableArray *subpredicates = [NSMutableArray array];
        for (NSPredicate *subpredicate in compoundPredicate.subpredicates) {
            [subpredicates addObject:visit(subpredicate)];
        }
        return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates];
    }
    if ([predicate isKindOfClass:[NSComparisonPredicate class]]) {
        NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate;
        NSExpression *leftExpression = visit(comparisonPredicate.leftExpression);
        NSExpression *rightExpression = visit(comparisonPredicate.rightExpression);
        return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options];
    }
    return predicate;
}

} // anonymous namespace

NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) {
    PredicateExpressionTransformer transformer(visitor);
    return transformer.visit(predicate);
}