mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-13 02:08:55 +00:00
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:
1 parent
49c8a02b5f
commit
275f89a340
3 files changed
+33
-84
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user