mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-21 01:40:41 +00:00
Implemented subquery expressions.
Added missing getters in CPExpression. Added a type: argument to FunctionExpression initializer used by subclasses to init super with their own type. Fixed evaluation with bindings dictionary in CPExpression_variable. Allow values in bindings to be a constant or an expression (per cocoa). Tests: added tests for subqueryExpressions, for variableExpression evaluation where the value in the bindings dictionary can be either a constant or another expression. Parsing a simple variable expression works (e.g. '$x = 12'), parsing a variable in a combined path (e.g. '$x.path = 12' won't yet.
This commit is contained in:
@@ -478,17 +478,8 @@ var CPComparisonPredicateModifier,
|
||||
|
||||
- (BOOL)evaluateWithObject:(id)object substitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
var left = _left,
|
||||
right = _right;
|
||||
|
||||
if (variables != nil)
|
||||
{
|
||||
left = [left _expressionWithSubstitutionVariables:variables];
|
||||
right = [right _expressionWithSubstitutionVariables:variables];
|
||||
}
|
||||
|
||||
var leftValue = [left expressionValueWithObject:object context:nil],
|
||||
rightValue = [right expressionValueWithObject:object context:nil];
|
||||
var leftValue = [_left expressionValueWithObject:object context:variables],
|
||||
rightValue = [_right expressionValueWithObject:object context:variables];
|
||||
|
||||
if (_modifier == CPDirectPredicateModifier)
|
||||
return [self _evaluateValue:leftValue rightValue:rightValue];
|
||||
|
||||
@@ -227,13 +227,11 @@ CPMinusSetExpressionType = 9;
|
||||
return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(function_name) arguments:parameters];
|
||||
}
|
||||
|
||||
|
||||
+ (CPExpression)expressionForSubquery:(CPExpression)expression usingIteratorVariable:(CPString)variable predicate:(id)predicate
|
||||
+ (CPExpression)expressionForSubquery:(CPExpression)expression usingIteratorVariable:(CPString)variable predicate:(CPPredicate)predicate
|
||||
{
|
||||
return nil; // UNIMPLEMENTED
|
||||
return [[CPExpression_subquery alloc] initWithExpression:expression usingIteratorVariable:variable predicate:predicate];
|
||||
}
|
||||
|
||||
|
||||
// Getting Information About an Expression
|
||||
/*!
|
||||
Returns the expression type for the receiver.
|
||||
@@ -252,7 +250,7 @@ CPMinusSetExpressionType = 9;
|
||||
*/
|
||||
- (id)constantValue
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPConstantValueExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -263,7 +261,7 @@ CPMinusSetExpressionType = 9;
|
||||
*/
|
||||
- (CPString)variable
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPVariableExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -274,7 +272,7 @@ CPMinusSetExpressionType = 9;
|
||||
*/
|
||||
- (CPString)keyPath
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPKeyPathExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -285,7 +283,7 @@ CPMinusSetExpressionType = 9;
|
||||
*/
|
||||
- (CPString)function
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPFunctionExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -296,21 +294,70 @@ CPMinusSetExpressionType = 9;
|
||||
*/
|
||||
- (CPArray)arguments
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPFunctionExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the collection of expressions in an aggregate expression, or the collection element of a subquery expression.
|
||||
@return Returns the collection of expressions in an aggregate expression, or the collection element of a subquery expression.
|
||||
@return The collection of expressions in an aggregate expression, or the collection element of a subquery expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (id)collection
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException reason:@"self is not of CPAggregateExpressionType"];
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the predicate in a subquery expression.
|
||||
@return The predicate in a subquery expression..
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPPredicate)predicate
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the operand for the receiver.
|
||||
@return The operand for the receiver—that is, the object on which the selector will be invoked.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)operand
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the left expression of a set expression.
|
||||
@return The left expression of a set expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)leftExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the right expression of a set expression.
|
||||
@return The right expression of a set expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)rightExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@import "CPExpression_constant.j"
|
||||
@@ -320,3 +367,4 @@ CPMinusSetExpressionType = 9;
|
||||
@import "CPExpression_function.j"
|
||||
@import "CPExpression_aggregate.j"
|
||||
@import "CPExpression_set.j"
|
||||
@import "CPExpression_subquery.j"
|
||||
|
||||
@@ -89,4 +89,4 @@ var CPCollectionKey = @"CPCollection";
|
||||
[coder encodeObject:_aggregate forKey:CPCollectionKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self == object)
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object constantValue] isEqual:[self constantValue]])
|
||||
@@ -31,16 +31,11 @@
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:object context:(CPDictionary)context
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
if ([_value isKindOfClass:[CPString class]])
|
||||
|
||||
@@ -22,14 +22,19 @@
|
||||
return [self initWithTarget:operand selector:aSelector arguments:parameters];
|
||||
}
|
||||
|
||||
- (id)initWithTarget:(CPExpression)targetExpression selector:aSelector arguments:parameters
|
||||
- (id)initWithTarget:(CPExpression)operand selector:(SEL)aSelector arguments:(CPArray)parameters
|
||||
{
|
||||
[super initWithExpressionType:CPFunctionExpressionType];
|
||||
return [self initWithTarget:operand selector:aSelector arguments:parameters type:CPFunctionExpressionType];
|
||||
}
|
||||
|
||||
- (id)initWithTarget:(CPExpression)operand selector:(SEL)aSelector arguments:(CPArray)parameters type:(int)type
|
||||
{
|
||||
[super initWithExpressionType:type];
|
||||
|
||||
// Cocoa doc: "This method throws an exception immediately if the selector is unknown"
|
||||
// but targetExpression's value (selector's target) may be resolved only at runtime.
|
||||
// but operand's value (the target) may be resolved only at runtime.
|
||||
_selector = aSelector;
|
||||
_operand = targetExpression;
|
||||
_operand = operand;
|
||||
_arguments = parameters;
|
||||
_argc = [parameters count];
|
||||
|
||||
@@ -98,7 +103,7 @@
|
||||
{
|
||||
var array = [CPArray array],
|
||||
i;
|
||||
|
||||
// should we also allow variables for target and selectors ?
|
||||
for (i = 0; i < _argc; i++)
|
||||
[array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]];
|
||||
|
||||
@@ -109,17 +114,19 @@
|
||||
|
||||
var CPSelectorNameKey = @"CPSelectorName",
|
||||
CPArgumentsKey = @"CPArguments",
|
||||
CPOperandKey = @"CPOperand";
|
||||
CPOperandKey = @"CPOperand",
|
||||
CPExpressionTypeKey = @"CPExpressionType";
|
||||
|
||||
@implementation CPExpression_function (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
var target = [coder decodeObjectForKey:CPOperandKey],
|
||||
var type = [coder decodeIntForKey:CPExpressionTypeKey],
|
||||
operand = [coder decodeObjectForKey:CPOperandKey],
|
||||
selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]),
|
||||
arguments = [coder decodeObjectForKey:CPArgumentsKey];
|
||||
parameters = [coder decodeObjectForKey:CPArgumentsKey];
|
||||
|
||||
return [self initWithTarget:target selector:selector arguments:arguments];
|
||||
return [self initWithTarget:operand selector:selector arguments:parameters type:type];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
@@ -127,6 +134,7 @@ var CPSelectorNameKey = @"CPSelectorName",
|
||||
[coder encodeObject:[self _function] forKey:CPSelectorNameKey];
|
||||
[coder encodeObject:_arguments forKey:CPArgumentsKey];
|
||||
[coder encodeObject:_operand forKey:CPOperandKey];
|
||||
[coder encodeInt:_type forKey:CPExpressionTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,11 +17,19 @@
|
||||
{
|
||||
var arg = [CPExpression expressionForConstantValue:keyPath];
|
||||
// Cocoa: if it's a direct path selector is valueForKey:
|
||||
self = [super initWithTarget:operand selector:@selector(valueForKeyPath:) arguments:[arg]];
|
||||
self = [super initWithTarget:operand selector:@selector(valueForKeyPath:) arguments:[arg] type:CPKeyPathExpressionType];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object === self)
|
||||
return YES;
|
||||
|
||||
return ([object keyPath] == [self keyPath]); //If it appears that parsing generates nested keypaths with different targets and same keyPath, comparing -keyPath won't work.
|
||||
}
|
||||
|
||||
- (CPExpression)pathExpression
|
||||
{
|
||||
return [[self arguments] objectAtIndex:0];
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPCoder.j>
|
||||
|
||||
var defaultInstance = nil;
|
||||
@implementation CPExpression_self : CPExpression
|
||||
{
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (defaultInstance == nil)
|
||||
{
|
||||
[super initWithExpressionType:CPEvaluatedObjectExpressionType];
|
||||
defaultInstance = self;
|
||||
}
|
||||
|
||||
return defaultInstance;
|
||||
[super initWithExpressionType:CPEvaluatedObjectExpressionType];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
@@ -31,7 +26,7 @@ var defaultInstance = nil;
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
return (object === self);
|
||||
return (_type == CPEvaluatedObjectExpressionType);
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
@@ -39,11 +34,6 @@ var defaultInstance = nil;
|
||||
return object;
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return @"SELF";
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables
|
||||
{
|
||||
// UNIMPLEMENTED
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
@import "CPExpression.j"
|
||||
|
||||
@implementation CPExpression_subquery : CPExpression
|
||||
{
|
||||
CPExpression _collection;
|
||||
CPExpression _variableExpression;
|
||||
CPPredicate _subpredicate;
|
||||
}
|
||||
|
||||
- (id)initWithExpression:(CPExpression)collection usingIteratorVariable:(CPString)variable predicate:(CPPredicate)subpredicate
|
||||
{
|
||||
[super initWithExpressionType:CPSubqueryExpressionType];
|
||||
|
||||
_subpredicate = subpredicate;
|
||||
_collection = collection;
|
||||
_variableExpression = [CPExpression expressionForVariable:variable];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(id)context
|
||||
{
|
||||
var collection = [_collection expressionValueWithObject:object context:context],
|
||||
count = [collection count],
|
||||
result = [CPArray array],
|
||||
|
||||
bindings = [CPDictionary dictionaryWithObject:[CPExpression expressionForEvaluatedObject] forKey:[self variable]];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = [collection objectAtIndex:i];
|
||||
if ([_subpredicate evaluateWithObject:item substitutionVariables:bindings])
|
||||
[result addObject:item];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object;
|
||||
{
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (![_collection isEqual:[object collection]] || ![_subpredicate isEqual:[object predicate]])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)collection
|
||||
{
|
||||
return _collection;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [[CPExpression_subquery alloc] initWithExpression:[_collection copy] usingIteratorExpression:[_variableExpression copy] predicate:[_subpredicate copy]];
|
||||
}
|
||||
|
||||
- (id)predicate
|
||||
{
|
||||
return _subpredicate;
|
||||
}
|
||||
|
||||
- (id)predicateFormat
|
||||
{
|
||||
return @"SUBQUERY(" + [_collection description] + ", " + [_variableExpression description] + ", " + [_subpredicate predicateFormat] + ")";
|
||||
}
|
||||
|
||||
- (id)variable
|
||||
{
|
||||
return [_variableExpression variable];
|
||||
}
|
||||
|
||||
- (id)variableExpression
|
||||
{
|
||||
return _variableExpression;
|
||||
}
|
||||
@end
|
||||
|
||||
var CPExpressionKey = @"CPExpression",
|
||||
CPSubpredicateKey = @"CPSubpredicate",
|
||||
CPVariableKey = @"CPVariable";
|
||||
|
||||
@implementation CPExpression_subquery (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)coder
|
||||
{
|
||||
var collection = [coder decodeObjectForKey:CPExpressionKey],
|
||||
subpredicate = [coder decodeObjectForKey:CPSubpredicateKey],
|
||||
variable = [coder decodeObjectForKey:CPVariableKey];
|
||||
|
||||
return [self initWithExpression:collection usingIteratorVariable:variable predicate:subpredicate];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)coder
|
||||
{
|
||||
[coder encodeObject:_collection forKey:CPExpressionKey];
|
||||
[coder encodeObject:_subpredicate forKey:CPSubpredicateKey];
|
||||
[coder encodeObject:[variableExpression variable] forKey:CPVariableKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
[super initWithExpressionType:CPVariableExpressionType];
|
||||
_variable = [variable copy];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
{
|
||||
if (self == object)
|
||||
return YES;
|
||||
|
||||
|
||||
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object variable] isEqualToString:[self variable]])
|
||||
return NO;
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
|
||||
- (id)expressionValueWithObject:object context:(CPDictionary)context
|
||||
{
|
||||
return [context objectForKey:_variable];
|
||||
var expression = [self _expressionWithSubstitutionVariables:context];
|
||||
|
||||
return [expression expressionValueWithObject:object context:context];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
@@ -44,12 +46,14 @@
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
var aconstant = [variables objectForKey:_variable];
|
||||
|
||||
if (aconstant != nil)
|
||||
return [CPExpression expressionForConstantValue:aconstant];
|
||||
|
||||
return self;
|
||||
var value = [variables objectForKey:_variable];
|
||||
if (value == nil)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Can't get value for '" + _variable + "' in bindings" + variables];
|
||||
|
||||
if ([value isKindOfClass:[CPExpression class]])
|
||||
return value;
|
||||
|
||||
return [CPExpression expressionForConstantValue:value];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
[self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"];
|
||||
|
||||
var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]];
|
||||
// [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"];
|
||||
[self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"];
|
||||
|
||||
var set = [CPExpression expressionForConstantValue:[CPSet setWithObjects:@"a",@"b",@"c"]];
|
||||
var array = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]];
|
||||
@@ -112,12 +112,34 @@
|
||||
|
||||
- (void)testVariableExpressionEvaluation
|
||||
{
|
||||
var variable_exp = [CPExpression expressionForVariable:@"variable"];
|
||||
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:variable_exp modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0];
|
||||
// Replace with constant
|
||||
var expression = [CPExpression expressionForVariable:@"variable"],
|
||||
bindings = [CPDictionary dictionaryWithObject:20 forKey:@"variable"],
|
||||
eval = [expression expressionValueWithObject:@"variable" context:bindings];
|
||||
[self assertTrue:(eval == 20) message:"'"+ eval + "' should be 20"];
|
||||
|
||||
var variables = [CPDictionary dictionaryWithObject:20 forKey:@"variable"];
|
||||
// Replace with constant expression
|
||||
bindings = [CPDictionary dictionaryWithObject:[CPExpression expressionForConstantValue:10] forKey:@"variable"];
|
||||
eval = [expression expressionValueWithObject:nil context:bindings];
|
||||
[self assertTrue:(eval == 10) message:"'"+ eval + "' should be 10"];
|
||||
|
||||
[self assertTrue:[pred evaluateWithObject:dict substitutionVariables:variables] message:"'"+ [pred description] + "' should be true"];
|
||||
// Replace with keypath expression
|
||||
bindings = [CPDictionary dictionaryWithObject:[CPExpression expressionForKeyPath:@"Record1.Age"] forKey:@"variable"];
|
||||
eval = [expression expressionValueWithObject:dict context:bindings];
|
||||
[self assertTrue:(eval == 34) message:"'"+ eval + "' should be 34"];
|
||||
}
|
||||
|
||||
- (void)testSubqueryExpressionEvaluation
|
||||
{
|
||||
var collection = [CPExpression expressionForKeyPath:@"Record1.Children"],
|
||||
iteratorVariable = @"x",
|
||||
predicate = [CPPredicate predicateWithFormat:@"$x BEGINSWITH 'Kid'"];
|
||||
|
||||
var expression = [CPExpression expressionForSubquery:collection usingIteratorVariable:iteratorVariable predicate:predicate];
|
||||
|
||||
var eval = [expression expressionValueWithObject:dict context:nil];
|
||||
var expected = [CPArray arrayWithObjects:"Kid1", "Kid2"];
|
||||
[self assertTrue:([eval isEqual:expected]) message:"'"+ [expression predicateFormat] + "' result is "+ eval + "but should be " + expected];
|
||||
}
|
||||
|
||||
- (void)testOptions
|
||||
@@ -281,8 +303,19 @@
|
||||
predicate = [CPPredicate predicateWithFormat: @"a BETWEEN {%f,%f}", 20, 40];
|
||||
[self assertTrue:([predicate predicateOperatorType] == CPBetweenPredicateOperatorType) message:[predicate description] + " operator should be a CPBetweenPredicateOperatorType"];
|
||||
|
||||
// TEST Empty string
|
||||
predicate = [CPPredicate predicateWithFormat: @"a CONTAINS \"\""];
|
||||
[self assertNotNull:predicate message:[predicate description] + " should not be nil"];
|
||||
|
||||
// TEST variable
|
||||
predicate = [CPPredicate predicateWithFormat: @"$x CONTAINS \"\""];
|
||||
[self assertTrue:[[predicate leftExpression] expressionType] == CPVariableExpressionType message:"Left Expression should be a CPVariableExpressionType"];
|
||||
/*
|
||||
Variable in multiple paths will fail. Left exp should be FUNCTION(keyPathExp"keypath", valueForKey:, variableExp"variable")
|
||||
predicate = [CPPredicate predicateWithFormat: @"keypath.$variable CONTAINS \"\""];
|
||||
var type = [[predicate leftExpression] expressionType];
|
||||
[self assertTrue: type == CPFunctionExpressionType message:"Left Expression should be a CPFunctionExpressionType is " + type];
|
||||
*/
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user