RLMPredicateUtil.mm 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. #import "RLMPredicateUtil.hpp"
  18. #include <realm/util/assert.hpp>
  19. // NSConditionalExpressionType is new in OS X 10.11 and iOS 9.0
  20. #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
  21. #define CONDITIONAL_EXPRESSION_DECLARED (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
  22. #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  23. #define CONDITIONAL_EXPRESSION_DECLARED (__IPHONE_OS_VERSION_MIN_REQUIRED >= 90000)
  24. #else
  25. #define CONDITIONAL_EXPRESSION_DECLARED 0
  26. #endif
  27. #if !CONDITIONAL_EXPRESSION_DECLARED
  28. #define NSConditionalExpressionType 20
  29. @interface NSExpression (NewIn1011And90)
  30. + (NSExpression *)expressionForConditional:(NSPredicate *)predicate trueExpression:(NSExpression *)trueExpression falseExpression:(NSExpression *)falseExpression;
  31. - (NSExpression *)trueExpression;
  32. - (NSExpression *)falseExpression;
  33. @end
  34. #endif
  35. namespace {
  36. struct PredicateExpressionTransformer {
  37. PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { }
  38. NSExpression *visit(NSExpression *expression) const;
  39. NSPredicate *visit(NSPredicate *predicate) const;
  40. ExpressionVisitor m_visitor;
  41. };
  42. NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const {
  43. expression = m_visitor(expression);
  44. switch (expression.expressionType) {
  45. case NSFunctionExpressionType: {
  46. NSMutableArray *arguments = [NSMutableArray array];
  47. for (NSExpression *argument in expression.arguments) {
  48. [arguments addObject:visit(argument)];
  49. }
  50. if (expression.operand) {
  51. return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments];
  52. } else {
  53. return [NSExpression expressionForFunction:expression.function arguments:arguments];
  54. }
  55. }
  56. case NSUnionSetExpressionType:
  57. return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
  58. case NSIntersectSetExpressionType:
  59. return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
  60. case NSMinusSetExpressionType:
  61. return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)];
  62. case NSSubqueryExpressionType: {
  63. NSExpression *collection = expression.collection;
  64. // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries.
  65. REALM_ASSERT([collection isKindOfClass:[NSExpression class]]);
  66. return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)];
  67. }
  68. case NSAggregateExpressionType: {
  69. NSMutableArray *subexpressions = [NSMutableArray array];
  70. for (NSExpression *subexpression in expression.collection) {
  71. [subexpressions addObject:visit(subexpression)];
  72. }
  73. return [NSExpression expressionForAggregate:subexpressions];
  74. }
  75. case NSConditionalExpressionType:
  76. #pragma clang diagnostic push
  77. #pragma clang diagnostic ignored "-Wpartial-availability"
  78. return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)];
  79. #pragma clang diagnostic pop
  80. default:
  81. // The remaining expression types do not contain nested expressions or predicates.
  82. return expression;
  83. }
  84. }
  85. NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const {
  86. if ([predicate isKindOfClass:[NSCompoundPredicate class]]) {
  87. NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate;
  88. NSMutableArray *subpredicates = [NSMutableArray array];
  89. for (NSPredicate *subpredicate in compoundPredicate.subpredicates) {
  90. [subpredicates addObject:visit(subpredicate)];
  91. }
  92. return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates];
  93. }
  94. if ([predicate isKindOfClass:[NSComparisonPredicate class]]) {
  95. NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate;
  96. NSExpression *leftExpression = visit(comparisonPredicate.leftExpression);
  97. NSExpression *rightExpression = visit(comparisonPredicate.rightExpression);
  98. return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options];
  99. }
  100. return predicate;
  101. }
  102. } // anonymous namespace
  103. NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) {
  104. PredicateExpressionTransformer transformer(visitor);
  105. return transformer.visit(predicate);
  106. }