//////////////////////////////////////////////////////////////////////////// // // 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); }