1/*
2  Copyright (C) 2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include "NSPredicate+EO.h"
23#include "EOQualifier+CoreData.h"
24#include "common.h"
25
26@implementation NSPredicate(EOCoreData)
27
28- (NSPredicate *)asPredicate {
29  return self;
30}
31- (NSExpression *)asExpression {
32  return nil;
33}
34
35@end /* NSPredicate(EOCoreData) */
36
37
38@implementation NSCompoundPredicate(EOCoreData)
39
40- (EOQualifier *)asQualifier {
41  /*
42     Compound predicates join other predicates, they do not deal with
43     expressions.
44  */
45  NSMutableArray *sq;
46  NSArray     *sp;
47  unsigned    i, count;
48  Class       clazz;
49  BOOL        isNot = NO;
50  EOQualifier *q;
51
52  sp    = [self subpredicates];
53  count = [sp count];
54
55  switch ([self compoundPredicateType]) {
56  case NSNotPredicateType:
57    isNot = YES;
58    clazz = [EONotQualifier class];
59    break;
60  case NSAndPredicateType:
61    clazz = [EOAndQualifier class];
62    break;
63  case NSOrPredicateType:
64    clazz = [EOOrQualifier class];
65    break;
66  default:
67    NSLog(@"ERROR(%s): unknown compound predicate type: %@",
68	  __PRETTY_FUNCTION__, self);
69    return nil;
70  }
71
72  if (count == 0)
73    return [[[clazz alloc] init] autorelease];
74
75  if (count == 1) {
76    q = [sp objectAtIndex:0];
77    return (isNot)
78      ? [[[EONotQualifier alloc] initWithQualifier:q] autorelease]
79      : q;
80  }
81
82  sq = [[NSMutableArray alloc] initWithCapacity:count];
83
84  for (i = 0; i < count; i++) {
85    q = [EOQualifier qualifierForPredicate:[sp objectAtIndex:i]];
86    if (q == nil) {
87      q = [sp objectAtIndex:i];
88      NSLog(@"ERROR(%s): could not convert predicate to qualifier: %@",
89	    __PRETTY_FUNCTION__, q);
90    }
91
92    if (isNot)
93      q = [[EONotQualifier alloc] initWithQualifier:q];
94
95    [sq addObject:q];
96    if (isNot) [q release];
97
98    q = nil;
99  }
100
101  q = [[(isNot ? [EOAndQualifier class] : clazz) alloc] initWithQualifier:q];
102  [sq release];
103  return [q autorelease];
104}
105
106@end /* NSCompoundPredicate(EOCoreData) */
107
108
109@implementation NSComparisonPredicate(EOCoreData)
110
111- (EOQualifier *)asQualifier {
112  NSExpression *lhs, *rhs;
113
114  lhs = [self leftExpression];
115  rhs = [self rightExpression];
116
117  // TODO: need to check predicate modifiers
118  // TODO: add support for variables
119
120  if ([rhs expressionType] == NSKeyPathExpressionType) {
121    if ([lhs expressionType] == NSConstantValueExpressionType)
122      return [EOKeyValueQualifier qualifierForComparisonPredicate:self];
123
124    if ([lhs expressionType] == NSKeyPathExpressionType)
125      return [EOKeyComparisonQualifier qualifierForComparisonPredicate:self];
126  }
127
128  NSLog(@"ERROR(%s): cannot map NSComparisonPredicate to EOQualifier: %@",
129	__PRETTY_FUNCTION__, self);
130  return (id)self;
131}
132
133/* key/value archiving */
134
135- (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver {
136  int                           opt;
137  NSPredicateOperatorType       ptype;
138  NSComparisonPredicateModifier mod;
139  NSExpression *left, *right;
140  NSString     *selName, *s;
141
142  /* left / right - TODO: need to check 'official' keys fo rthat */
143
144  left = [_unarchiver decodeObjectForKey:@"left"];
145  if (left != nil && ![left isKindOfClass:[NSExpression class]])
146    left = [NSExpression expressionForConstantValue:left];
147
148  right = [_unarchiver decodeObjectForKey:@"right"];
149  if (right != nil && ![right isKindOfClass:[NSExpression class]])
150    right = [NSExpression expressionForConstantValue:right];
151
152  /* custom selector */
153
154  if ((selName = [_unarchiver decodeObjectForKey:@"selectorName"]) != nil) {
155    if (![selName hasSuffix:@":"])
156      selName = [selName stringByAppendingString:@":"];
157  }
158  else
159    selName = [_unarchiver decodeObjectForKey:@"selector"];
160  if ([selName length] > 0) {
161    return [self initWithLeftExpression:left rightExpression:right
162		 customSelector:selName ? NSSelectorFromString(selName):NULL];
163  }
164
165  /* modifier */
166
167  if ((s = [_unarchiver decodeObjectForKey:@"modifier"]) != nil) {
168    if ([s isEqualToString:@"direct"])   mod = NSDirectPredicateModifier;
169    else if ([s isEqualToString:@"all"]) mod = NSAllPredicateModifier;
170    else if ([s isEqualToString:@"any"]) mod = NSAnyPredicateModifier;
171    else {
172      NSLog(@"WARNING(%s): could not decode modifier (trying int): %@!",
173	    __PRETTY_FUNCTION__, s);
174      mod = [s intValue];
175    }
176  }
177  else
178    mod = NSDirectPredicateModifier;
179
180  /* type */
181
182  if ((s = [_unarchiver decodeObjectForKey:@"type"]) != nil) {
183    if ([s isEqualToString:@"<"])
184      ptype = NSLessThanPredicateOperatorType;
185    else if ([s isEqualToString:@"=<"])
186      ptype = NSLessThanOrEqualToPredicateOperatorType;
187    else if ([s isEqualToString:@">"])
188      ptype = NSGreaterThanPredicateOperatorType;
189    else if ([s isEqualToString:@">="])
190      ptype = NSGreaterThanOrEqualToPredicateOperatorType;
191    else if ([s isEqualToString:@"=="])
192      ptype = NSEqualToPredicateOperatorType;
193    else if ([s isEqualToString:@"!="])
194      ptype = NSNotEqualToPredicateOperatorType;
195    else if ([s isEqualToString:@"like"])
196      ptype = NSLikePredicateOperatorType;
197    else if ([s isEqualToString:@"contains"])
198      ptype = NSInPredicateOperatorType;
199    else if ([s isEqualToString:@"beginswith"])
200      ptype = NSBeginsWithPredicateOperatorType;
201    else if ([s isEqualToString:@"endswith"])
202      ptype = NSEndsWithPredicateOperatorType;
203    else if ([s isEqualToString:@"matches"])
204      ptype = NSMatchesPredicateOperatorType;
205    else {
206      NSLog(@"WARNING(%s): could not decode type (trying int): %@!",
207	    __PRETTY_FUNCTION__, s);
208      ptype = [s intValue];
209    }
210  }
211  else
212    ptype = NSEqualToPredicateOperatorType;
213
214  /* options */
215
216  // TODO: use bit-compare and a set?
217  if ((s = [_unarchiver decodeObjectForKey:@"options"]) != nil) {
218    if ([s isEqualToString:@"caseInsensitive"])
219      opt = NSCaseInsensitivePredicateOption;
220    else if ([s isEqualToString:@"diacritic"])
221      opt = NSDiacriticInsensitivePredicateOption;
222    else {
223      NSLog(@"WARNING(%s): could not decode options (trying int): %@!",
224	    __PRETTY_FUNCTION__, s);
225      opt = [s intValue];
226    }
227  }
228  else
229    opt = 0;
230
231  /* create and return */
232
233  return [self initWithLeftExpression:left rightExpression:right
234	       modifier:mod type:ptype options:opt];
235}
236
237- (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver {
238  NSString *s;
239
240  [_archiver encodeObject:[self leftExpression]  forKey:@"left"];
241  [_archiver encodeObject:[self rightExpression] forKey:@"right"];
242
243  /* type */
244
245  switch ([self predicateOperatorType]) {
246  case NSCustomSelectorPredicateOperatorType:
247    [_archiver encodeObject:NSStringFromSelector([self customSelector])
248	       forKey:@"selector"];
249    return; /* no more info */
250
251  case NSLessThanPredicateOperatorType:             s = @"<";        break;
252  case NSLessThanOrEqualToPredicateOperatorType:    s = @"=<";       break;
253  case NSGreaterThanPredicateOperatorType:          s = @">";        break;
254  case NSGreaterThanOrEqualToPredicateOperatorType: s = @">=";       break;
255  case NSEqualToPredicateOperatorType:              s = @"==";       break;
256  case NSNotEqualToPredicateOperatorType:           s = @"!=";       break;
257  case NSLikePredicateOperatorType:                 s = @"like";     break;
258  case NSInPredicateOperatorType:                   s = @"contains"; break;
259  case NSBeginsWithPredicateOperatorType:           s = @"beginswith"; break;
260  case NSEndsWithPredicateOperatorType:             s = @"endswith"; break;
261  case NSMatchesPredicateOperatorType:              s = @"matches";  break;
262
263  default:
264    s = [NSString stringWithFormat:@"%i", [self predicateOperatorType]];
265    break;
266  }
267  if (s != nil) [_archiver encodeObject:s forKey:@"type"];
268
269  /* modifier */
270
271  switch ([self comparisonPredicateModifier]) {
272  case NSDirectPredicateModifier: s = nil;    break;
273  case NSAllPredicateModifier:    s = @"all"; break;
274  case NSAnyPredicateModifier:    s = @"any"; break;
275  default:
276    s = [NSString stringWithFormat:@"%i",
277		  [self comparisonPredicateModifier]];
278    break;
279  }
280  if (s != nil) [_archiver encodeObject:s forKey:@"modifier"];
281
282  /* options */
283
284  // TODO: use bit-compare and a set?
285
286  if ([self options] == NSCaseInsensitivePredicateOption)
287    [_archiver encodeObject:@"caseInsensitive" forKey:@"options"];
288  else if ([self options] == NSDiacriticInsensitivePredicateOption)
289    [_archiver encodeObject:@"diacritic" forKey:@"options"];
290}
291
292@end /* NSComparisonPredicate(EOCoreData) */
293