CPPredicate: parsing 'BETWEEN' or 'CONTAINS' keywords now generates predicates with their corresponding operators. Some code style.

CPComparisonPredicate: fixed typo in 'between' operator evaluation, simplified 'contains' and 'in'  evaluation.
Added tests in CPPredicateTest for theses fixes.
This commit is contained in:
cacaodev committed 2010-10-22 22:13:57 +02:00
1 parent 49c8a02b5f
commit 275f89a340
3 files changed
+33 -84

No files matched your search

+9 -36
View File
@@ -441,43 +441,19 @@ var CPPredicateOperatorType;
if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch;
return ([lhs compare:rhs options:string_compare_options range:range] == CPOrderedSame);
case CPInPredicateOperatorType:
// Handle special case where rhs is a collection and lhs an element of it.
if (![rhs isKindOfClass: [CPString class]])
{
if (![rhs respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The right hand side for an IN operator must be a collection"];
var e = [rhs objectEnumerator],
value;
while (value = [e nextObject])
if ([value isEqual:lhs])
return YES;
return NO;
}
if (_options & CPCaseInsensitivePredicateOption)
string_compare_options |= CPCaseInsensitiveSearch;
if (_options & CPDiacriticInsensitivePredicateOption)
string_compare_options |= CPDiacriticInsensitiveSearch;
return ([rhs rangeOfString:lhs options:string_compare_options].location != CPNotFound);
case CPCustomSelectorPredicateOperatorType:
return [lhs performSelector:_customSelector withObject:rhs];
case CPInPredicateOperatorType:
var a = lhs; // swap
lhs = rhs;
rhs = a;
case CPContainsPredicateOperatorType:
if (![lhs isKindOfClass: [CPString class]])
if (![lhs isKindOfClass:[CPString class]])
{
if (![lhs respondsToSelector: @selector(objectEnumerator)])
[CPException raise:CPInvalidArgumentException reason:@"The left hand side for a CONTAINS operator must be a collection or a string"];
[CPException raise:CPInvalidArgumentException reason:@"The left/right hand side for a CONTAINS/IN operator must be a collection or a string"];
var e = [lhs objectEnumerator],
value;
while (value = [e nextObject])
if ([value isEqual:rhs])
return YES;
return NO;
return [lhs containsObject:rhs];
}
if (_options & CPCaseInsensitivePredicateOption)
@@ -487,13 +463,10 @@ var CPPredicateOperatorType;
return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound);
case CPBetweenPredicateOperatorType:
if ([lhs count] < 2)
if ([rhs count] < 2)
[CPException raise:CPInvalidArgumentException reason:@"The right hand side for a BETWEEN operator must contain 2 objects"];
var lower = [rhs objectAtIndex:0],
upper = [rhs objectAtIndex:1];
return ([lhs compare:lower] == CPOrderedDescending && [lhs compare:upper] == CPOrderedAscending);
return ([lhs compare:rhs[0]] == CPOrderedDescending && [lhs compare:rhs[1]] == CPOrderedAscending);
default:
return NO;
}
+14 -48
View File
@@ -37,7 +37,7 @@
@param … A comma-separated list of arguments to substitute into format.
@return A new predicate formed by creating a new string with format and parsing the result.
*/
+ (CPPredicate)predicateWithFormat:(CPString) format, ...
+ (CPPredicate)predicateWithFormat:(CPString)format, ...
{
if (!format)
[CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"];
@@ -238,7 +238,7 @@ function(newValue)\
unsigned _retrieved;
}
- (id) initWithString:(CPString)format args:(CPArray)args
- (id)initWithString:(CPString)format args:(CPArray)args
{
self = [super initWithString:format];
if (self != nil)
@@ -248,7 +248,7 @@ function(newValue)\
return self;
}
- (id) nextArg
- (id)nextArg
{
return [_args nextObject];
}
@@ -274,7 +274,7 @@ function(newValue)\
return NO;
}
- (CPPredicate) parse
- (CPPredicate)parse
{
var r = nil;
@@ -296,12 +296,12 @@ function(newValue)\
return r;
}
- (CPPredicate) parsePredicate
- (CPPredicate)parsePredicate
{
return [self parseAnd];
}
- (CPPredicate) parseAnd
- (CPPredicate)parseAnd
{
var l = [self parseOr];
@@ -333,7 +333,7 @@ function(newValue)\
return l;
}
- (CPPredicate) parseNot
- (CPPredicate)parseNot
{
if ([self scanString:@"(" intoString:NULL])
{
@@ -361,7 +361,7 @@ function(newValue)\
return [self parseComparison];
}
- (CPPredicate) parseOr
- (CPPredicate)parseOr
{
var l = [self parseNot];
while ([self scanPredicateKeyword:@"OR"] || [self scanPredicateKeyword:@"||"])
@@ -392,7 +392,7 @@ function(newValue)\
return l;
}
- (CPPredicate) parseComparison
- (CPPredicate)parseComparison
{
var modifier = CPDirectPredicateModifier,
type = 0,
@@ -400,8 +400,7 @@ function(newValue)\
left,
right,
p,
negate = NO,
swap = NO;
negate = NO;
if ([self scanPredicateKeyword:@"ANY"])
{
@@ -469,36 +468,11 @@ function(newValue)\
}
else if ([self scanPredicateKeyword:@"CONTAINS"])
{
type = CPInPredicateOperatorType;
swap = YES;
type = CPContainsPredicateOperatorType;
}
else if ([self scanPredicateKeyword:@"BETWEEN"])
{
var exp = [self parseSimpleExpression],
a = [exp constantValue],
lower, upper,
lexp, uexp,
lp, up;
if (![a isKindOfClass:[CPArray class]])
[CPException raise:CPInvalidArgumentException reason:@"BETWEEN operator requires array argument"];
lower = [a objectAtIndex:0];
upper = [a objectAtIndex:1];
lexp = [CPExpression expressionForConstantValue:lower];
uexp = [CPExpression expressionForConstantValue:upper];
lp = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:lexp
modifier:modifier
type:CPGreaterThanPredicateOperatorType
options:opts];
up = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:uexp
modifier:modifier
type:CPLessThanPredicateOperatorType
options:opts];
return [CPCompoundPredicate andPredicateWithSubpredicates:
[CPArray arrayWithObjects:lp, up]];
type = CPBetweenPredicateOperatorType;
}
else
[CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]];
@@ -518,14 +492,6 @@ function(newValue)\
right = [self parseExpression];
if (swap == YES)
{
var tmp = left;
left = right;
right = tmp;
}
p = [CPComparisonPredicate predicateWithLeftExpression:left
rightExpression:right
modifier:modifier
@@ -535,12 +501,12 @@ function(newValue)\
return negate ? [CPCompoundPredicate notPredicateWithSubpredicate:p]:p;
}
- (CPExpression) parseExpression
- (CPExpression)parseExpression
{
return [self parseBinaryExpression];
}
- (CPExpression) parseSimpleExpression
- (CPExpression)parseSimpleExpression
{
var identifier,
location,
+10
View File
@@ -209,8 +209,18 @@
predicate = [CPPredicate predicateWithFormat: @"%@ IN %K", @"Kid1", @"Record1.Children"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat: @"%K CONTAINS %@", @"Record1.Children", @"Kid1"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// TEST Operator type
predicate = [CPPredicate predicateWithFormat: @"a CONTAINS[c] \"b\""];
[self assertTrue:([predicate predicateOperatorType] == CPContainsPredicateOperatorType) message:[predicate description] + " operator should be a CPContainsPredicateOperatorType"];
predicate = [CPPredicate predicateWithFormat: @"a BETWEEN {%f,%f}", 20, 40];
[self assertTrue:([predicate predicateOperatorType] == CPBetweenPredicateOperatorType) message:[predicate description] + " operator should be a CPBetweenPredicateOperatorType"];
}
@end