added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / RLMPredicateUtil.mm
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2015 Realm Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #import "RLMPredicateUtil.hpp"
19
20 #include <realm/util/assert.hpp>
21
22 // NSConditionalExpressionType is new in OS X 10.11 and iOS 9.0
23 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
24 #define CONDITIONAL_EXPRESSION_DECLARED (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
25 #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
26 #define CONDITIONAL_EXPRESSION_DECLARED (__IPHONE_OS_VERSION_MIN_REQUIRED >= 90000)
27 #else
28 #define CONDITIONAL_EXPRESSION_DECLARED 0
29 #endif
30
31 #if !CONDITIONAL_EXPRESSION_DECLARED
32
33 #define NSConditionalExpressionType 20
34
35 @interface NSExpression (NewIn1011And90)
36 + (NSExpression *)expressionForConditional:(NSPredicate *)predicate trueExpression:(NSExpression *)trueExpression falseExpression:(NSExpression *)falseExpression;
37 - (NSExpression *)trueExpression;
38 - (NSExpression *)falseExpression;
39 @end
40
41 #endif
42
43 namespace {
44
45 struct PredicateExpressionTransformer {
46     PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { }
47
48     NSExpression *visit(NSExpression *expression) const;
49     NSPredicate *visit(NSPredicate *predicate) const;
50
51     ExpressionVisitor m_visitor;
52 };
53
54 NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const {
55     expression = m_visitor(expression);
56
57     switch (expression.expressionType) {
58         case NSFunctionExpressionType: {
59             NSMutableArray *arguments = [NSMutableArray array];
60             for (NSExpression *argument in expression.arguments) {
61                 [arguments addObject:visit(argument)];
62             }
63             if (expression.operand) {
64                 return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments];
65             } else {
66                 return [NSExpression expressionForFunction:expression.function arguments:arguments];
67             }
68         }
69
70         case NSUnionSetExpressionType:
71             return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
72         case NSIntersectSetExpressionType:
73             return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
74         case NSMinusSetExpressionType:
75             return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
76
77         case NSSubqueryExpressionType: {
78             NSExpression *collection = expression.collection;
79             // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries.
80             REALM_ASSERT([collection isKindOfClass:[NSExpression class]]);
81             return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)];
82         }
83
84         case NSAggregateExpressionType: {
85             NSMutableArray *subexpressions = [NSMutableArray array];
86             for (NSExpression *subexpression in expression.collection) {
87                 [subexpressions addObject:visit(subexpression)];
88             }
89             return [NSExpression expressionForAggregate:subexpressions];
90         }
91
92         case NSConditionalExpressionType:
93 #pragma clang diagnostic push
94 #pragma clang diagnostic ignored "-Wpartial-availability"
95             return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)];
96 #pragma clang diagnostic pop
97
98         default:
99             // The remaining expression types do not contain nested expressions or predicates.
100             return expression;
101     }
102 }
103
104 NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const {
105     if ([predicate isKindOfClass:[NSCompoundPredicate class]]) {
106         NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate;
107         NSMutableArray *subpredicates = [NSMutableArray array];
108         for (NSPredicate *subpredicate in compoundPredicate.subpredicates) {
109             [subpredicates addObject:visit(subpredicate)];
110         }
111         return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates];
112     }
113     if ([predicate isKindOfClass:[NSComparisonPredicate class]]) {
114         NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate;
115         NSExpression *leftExpression = visit(comparisonPredicate.leftExpression);
116         NSExpression *rightExpression = visit(comparisonPredicate.rightExpression);
117         return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options];
118     }
119     return predicate;
120 }
121
122 } // anonymous namespace
123
124 NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) {
125     PredicateExpressionTransformer transformer(visitor);
126     return transformer.visit(predicate);
127 }