From f7f8b78795c372ee43fa9ccbc15e90584ab247d2 Mon Sep 17 00:00:00 2001 From: helge Date: Thu, 4 Aug 2005 00:39:18 +0000 Subject: [PATCH] work on CD/EOF translation git-svn-id: http://svn.opengroupware.org/SOPE/trunk@963 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-core/EOCoreData/ChangeLog | 14 ++ sope-core/EOCoreData/EOCompoundQualifiers.m | 66 +++++++ sope-core/EOCoreData/EOCoreData.h | 3 + sope-core/EOCoreData/EOCoreDataSource.h | 13 +- sope-core/EOCoreData/EOCoreDataSource.m | 181 +++++++++++++++++- .../EOFetchSpecification+CoreData.m | 62 +++++- .../EOKeyComparisonQualifier+CoreData.m | 66 +++++++ .../EOCoreData/EOKeyValueQualifier+CoreData.m | 67 +++++++ sope-core/EOCoreData/EOQualifier+CoreData.h | 55 +++++- sope-core/EOCoreData/EOQualifier+CoreData.m | 158 ++++++++++++++- .../EOCoreData/EOSortOrdering+CoreData.h | 5 + .../EOCoreData/EOSortOrdering+CoreData.m | 68 ++++++- sope-core/EOCoreData/GNUmakefile | 15 +- sope-core/EOCoreData/NSExpression+EO.h | 43 +++++ sope-core/EOCoreData/NSExpression+EO.m | 34 ++++ sope-core/EOCoreData/NSPredicate+EO.h | 44 +++++ sope-core/EOCoreData/NSPredicate+EO.m | 133 +++++++++++++ sope-core/EOCoreData/Version | 2 +- sope-core/EOCoreData/common.h | 13 ++ 19 files changed, 1009 insertions(+), 33 deletions(-) create mode 100644 sope-core/EOCoreData/EOCompoundQualifiers.m create mode 100644 sope-core/EOCoreData/EOKeyComparisonQualifier+CoreData.m create mode 100644 sope-core/EOCoreData/EOKeyValueQualifier+CoreData.m create mode 100644 sope-core/EOCoreData/NSExpression+EO.h create mode 100644 sope-core/EOCoreData/NSExpression+EO.m create mode 100644 sope-core/EOCoreData/NSPredicate+EO.h create mode 100644 sope-core/EOCoreData/NSPredicate+EO.m diff --git a/sope-core/EOCoreData/ChangeLog b/sope-core/EOCoreData/ChangeLog index 4339c75d..d11fd545 100644 --- a/sope-core/EOCoreData/ChangeLog +++ b/sope-core/EOCoreData/ChangeLog @@ -1,5 +1,19 @@ 2005-08-03 Helge Hess + * v4.5.2 + + * EOFetchSpecification+CoreData.m: implemented -initWithFetchRequest: + + * EOCoreDataSource.m: added key/value archiving, added ability to + retrieve the entity from the fetch specification, added support for + qualifier bindings (v4.5.2) + + * EOSortOrdering+CoreData.m: implemented conversion methods + + * EOQualifier+CoreData.m: implemented conversion methods + + * moved NS* categories to own files + * v4.5.1 * moved in implementation prototypes from CoreDataBlog diff --git a/sope-core/EOCoreData/EOCompoundQualifiers.m b/sope-core/EOCoreData/EOCompoundQualifiers.m new file mode 100644 index 00000000..ffb07918 --- /dev/null +++ b/sope-core/EOCoreData/EOCompoundQualifiers.m @@ -0,0 +1,66 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "EOQualifier+CoreData.h" +#include "NSPredicate+EO.h" +#include "NSExpression+EO.h" +#include "common.h" + +@implementation EOAndQualifier(CoreData) + +- (NSCompoundPredicateType)compoundPredicateType { + return NSAndPredicateType; +} + +- (NSPredicate *)asPredicate { + NSLog(@"TODO(%s): implement me for class %@!", __PRETTY_FUNCTION__, + NSStringFromClass([self class])); + return nil; +} + +@end /* EOAndQualifier(CoreData) */ + +@implementation EOOrQualifier(CoreData) + +- (NSCompoundPredicateType)compoundPredicateType { + return NSOrPredicateType; +} + +- (NSPredicate *)asPredicate { + NSLog(@"TODO(%s): implement me for class %@!", __PRETTY_FUNCTION__, + NSStringFromClass([self class])); + return nil; +} + +@end /* EOOrQualifier(CoreData) */ + +@implementation EONotQualifier(CoreData) + +- (NSCompoundPredicateType)compoundPredicateType { + return NSNotPredicateType; +} + +- (NSPredicate *)asPredicate { + return [NSCompoundPredicate notPredicateWithSubpredicate: + [[self qualifier] asPredicate]]; +} + +@end /* EONotQualifier(CoreData) */ diff --git a/sope-core/EOCoreData/EOCoreData.h b/sope-core/EOCoreData/EOCoreData.h index e9396be9..2a806e25 100644 --- a/sope-core/EOCoreData/EOCoreData.h +++ b/sope-core/EOCoreData/EOCoreData.h @@ -27,4 +27,7 @@ #include #include +#include +#include + #endif /* __EOCoreData_H__ */ diff --git a/sope-core/EOCoreData/EOCoreDataSource.h b/sope-core/EOCoreData/EOCoreDataSource.h index 0e9b1bee..124f3057 100644 --- a/sope-core/EOCoreData/EOCoreDataSource.h +++ b/sope-core/EOCoreData/EOCoreDataSource.h @@ -29,10 +29,12 @@ This wraps a NSManagedObjectContext in an EODataSource. It corresponds to the EODatabaseDataSource available in EOF. + + Note: if you use -setFetchRequest: all the EO related methods will be reset! */ @class NSArray, NSDictionary; -@class NSManagedObjectContext, NSEntityDescription; +@class NSManagedObjectContext, NSEntityDescription, NSFetchRequest; @class EOQualifier, EOFetchSpecification; @interface EOCoreDataSource : EODataSource @@ -42,9 +44,11 @@ EOFetchSpecification *fetchSpecification; EOQualifier *auxiliaryQualifier; NSDictionary *qualifierBindings; + NSFetchRequest *fetchRequest; struct { int isFetchEnabled:1; - int reserved:31; + int isEntityFromFetchSpec:1; + int reserved:30; } ecdFlags; } @@ -67,6 +71,11 @@ - (void)setQualifierBindings:(NSDictionary *)_bindings; - (NSDictionary *)qualifierBindings; +/* directly access a CoreData fetch request */ + +- (void)setFetchRequest:(NSFetchRequest *)_fr; +- (NSFetchRequest *)fetchRequest; + /* accessors */ - (NSEntityDescription *)entity; diff --git a/sope-core/EOCoreData/EOCoreDataSource.m b/sope-core/EOCoreData/EOCoreDataSource.m index 8e502850..8d328eec 100644 --- a/sope-core/EOCoreData/EOCoreDataSource.m +++ b/sope-core/EOCoreData/EOCoreDataSource.m @@ -21,6 +21,7 @@ #include "EOCoreDataSource.h" #include "EOFetchSpecification+CoreData.h" +#include "EOQualifier+CoreData.h" #include "common.h" static NSString *EODataSourceDidChangeNotification = @@ -32,13 +33,14 @@ static NSString *EODataSourceDidChangeNotification = entity:(NSEntityDescription *)_entity { if ((self = [super init]) != nil) { - if (_moc == nil || _entity == nil) { - NSLog(@"ERROR(%s): missing object-context or entity parameter!", + if (_moc == nil) { + NSLog(@"ERROR(%s): missing object-context parameter!", __PRETTY_FUNCTION__); [self release]; return nil; } + self->ecdFlags.isFetchEnabled = 1; self->managedObjectContext = [_moc retain]; self->entity = [_entity retain]; } @@ -72,13 +74,35 @@ static NSString *EODataSourceDidChangeNotification = /* fetch-spec */ +- (void)_resetFetchRequest { + [self->fetchRequest release]; self->fetchRequest = nil; +} + - (void)setFetchSpecification:(EOFetchSpecification *)_fspec { + BOOL isSameEntity; + if ([self->fetchSpecification isEqual:_fspec]) return; + if ([_fspec isKindOfClass:[NSFetchRequest class]]) { + /* be tolerant, we ain't no Java ... */ + [self setFetchRequest:(NSFetchRequest *)_fspec]; + return; + } + + isSameEntity = + [[self->fetchSpecification entityName] isEqual:[_fspec entityName]]; + [self->fetchSpecification autorelease]; self->fetchSpecification = [_fspec copy]; + /* reset derived entities */ + if (self->ecdFlags.isEntityFromFetchSpec && !isSameEntity) { + self->ecdFlags.isEntityFromFetchSpec = 0; + } + + [self _resetFetchRequest]; + [self postDataSourceChangedNotification]; } @@ -108,18 +132,31 @@ static NSString *EODataSourceDidChangeNotification = } /* apply bindings */ - + if ((bindings = [self qualifierBindings]) != nil ) { -#warning IMPLEMENT ME! + EOQualifier *q; + + if ((q = [fs qualifier]) != nil) { + q = [q qualifierWithBindings:[self qualifierBindings] + requiresAllVariables:YES]; + [fs setQualifier:q]; + } } + /* finished */ return fs; } - (void)setAuxiliaryQualifier:(EOQualifier *)_qualifier { + if ([_qualifier isKindOfClass:[NSPredicate class]]) /* be tolerant */ + _qualifier = [EOQualifier qualifierForPredicate:(NSPredicate *)_qualifier]; + if ([self->auxiliaryQualifier isEqual:_qualifier]) return; + + ASSIGNCOPY(self->auxiliaryQualifier, _qualifier); + [self _resetFetchRequest]; [self postDataSourceChangedNotification]; } - (EOQualifier *)auxiliaryQualifier { @@ -145,21 +182,68 @@ static NSString *EODataSourceDidChangeNotification = - (void)setQualifierBindings:(NSDictionary *)_bindings { ASSIGN(self->qualifierBindings, _bindings); + + [self _resetFetchRequest]; + [self postDataSourceChangedNotification]; } - (NSDictionary *)qualifierBindings { return self->qualifierBindings; } - (void)setIsFetchEnabled:(BOOL)_flag { - self->ecdFlags.isFetchEnabled = _flag ? 1 : 0; + int f; + + f = _flag ? 1 : 0; + if (self->ecdFlags.isFetchEnabled == f) + return; + + self->ecdFlags.isFetchEnabled = f; + + [self postDataSourceChangedNotification]; } - (BOOL)isFetchEnabled { return self->ecdFlags.isFetchEnabled ? YES : NO; } +/* directly access a CoreData fetch request */ + +- (void)setFetchRequest:(NSFetchRequest *)_fr { + if (_fr == self->fetchRequest) + return; + + /* reset EO objects */ + [self->fetchSpecification release]; self->fetchSpecification = nil; + [self->auxiliaryQualifier release]; self->auxiliaryQualifier = nil; + [self->qualifierBindings release]; self->qualifierBindings = nil; + + /* use entity of fetch-request */ + if ([_fr entity] != nil) { + ASSIGN(self->entity, [_fr entity]); + self->ecdFlags.isEntityFromFetchSpec = 1; + } + + ASSIGN(self->fetchRequest, _fr); +} +- (NSFetchRequest *)fetchRequest { + return self->fetchRequest; +} + /* accessors */ - (NSEntityDescription *)entity { + if (self->entity == nil && !self->ecdFlags.isEntityFromFetchSpec) { + NSManagedObjectContext *moc; + NSString *n; + + self->ecdFlags.isEntityFromFetchSpec = 1; /* also used for caching fails */ + + moc = [self managedObjectContext]; + n = [[self fetchSpecification] entityName]; + if (moc != nil && n != nil) { + self->entity = [[NSEntityDescription entityForName:n + inManagedObjectContext:moc] retain]; + } + } return self->entity; } - (NSManagedObjectContext *)managedObjectContext { @@ -170,18 +254,25 @@ static NSString *EODataSourceDidChangeNotification = - (NSArray *)fetchObjects { EOFetchSpecification *fs; - NSFetchRequest *fr; NSError *error = nil; NSArray *results; if (![self isFetchEnabled]) return [NSArray array]; - fs = [self fetchSpecificationForFetch]; - fr = [fs fetchRequestWithEntity:[self entity]]; + // TODO: print a warning on entity mismatch? + if (self->fetchRequest == nil) { + fs = [self fetchSpecificationForFetch]; + self->fetchRequest = [[fs fetchRequestWithEntity:[self entity]] retain]; + } - results = [[self managedObjectContext] executeFetchRequest:fr error:&error]; + results = [[self managedObjectContext] + executeFetchRequest:self->fetchRequest error:&error]; if (results == nil) { + // TODO: improve (-lastException on the datasource or return the error?) + NSLog(@"ERROR(%s): datasource failed to fetch: %@", __PRETTY_FUNCTION__, + error); + return nil; } // TODO: add grouping support? @@ -221,6 +312,78 @@ static NSString *EODataSourceDidChangeNotification = return (id)[self entity]; } +/* archiving */ + +- (id)initWithKeyValueUnarchiver:(EOKeyValueUnarchiver *)_unarchiver { + id lEntity; + id fs; + id ec; + + /* fetch object context */ + + ec = [_unarchiver decodeObjectReferenceForKey:@"managedObjectContext"]; + if (ec == nil) + ec = [_unarchiver decodeObjectReferenceForKey:@"editingContext"]; + + if (ec != nil && ![ec isKindOfClass:[NSManagedObjectContext class]]) { + NSLog(@"WARNING(%s): decode object context is of unexpected class: %@", + __PRETTY_FUNCTION__, ec); + } + + /* fetch fetch specification */ + + fs = [_unarchiver decodeObjectForKey:@"fetchRequest"]; + if (fs == nil) + fs = [_unarchiver decodeObjectForKey:@"fetchSpecification"]; + if (fs != nil && [fs isKindOfClass:[NSFetchRequest class]]) + fs = [[[EOFetchSpecification alloc] initWithFetchRequest:fs] autorelease]; + + /* setup entity */ + + lEntity = [_unarchiver decodeObjectForKey:@"entity"]; + if (lEntity == nil && fs != nil) { + /* try to determine entity from fetch-spec */ + lEntity = [(EOFetchSpecification *)fs entityName]; + } + if ([lEntity isKindOfClass:[NSString class]]) { + lEntity = [NSEntityDescription entityForName:lEntity + inManagedObjectContext:ec]; + } + + /* create object */ + + if ((self = [self initWithManagedObjectContext:ec entity:lEntity]) == nil) + return nil; + + /* add non-initializer settings */ + + [self setFetchSpecification:fs]; + [self setAuxiliaryQualifier: + [_unarchiver decodeObjectForKey:@"auxiliaryQualifier"]]; + [self setQualifierBindings: + [_unarchiver decodeObjectForKey:@"qualifierBindings"]]; + + [self setIsFetchEnabled:[_unarchiver decodeBoolForKey:@"isFetchEnabled"]]; + + return self; +} +- (void)encodeWithKeyValueArchiver:(EOKeyValueArchiver *)_archiver { + // TODO: do we need to produce the reference on our own? + [_archiver encodeReferenceToObject:[self managedObjectContext] + forKey:@"managedObjectContext"]; + + [_archiver encodeObject:[self fetchSpecification] + forKey:@"fetchSpecification"]; + [_archiver encodeObject:[self entity] + forKey:@"entity"]; + [_archiver encodeObject:[self auxiliaryQualifier] + forKey:@"auxiliaryQualifier"]; + [_archiver encodeObject:[self qualifierBindings] + forKey:@"qualifierBindings"]; + [_archiver encodeBool:[self isFetchEnabled] + forKey:@"isFetchEnabled"]; +} + /* description */ - (NSString *)description { diff --git a/sope-core/EOCoreData/EOFetchSpecification+CoreData.m b/sope-core/EOCoreData/EOFetchSpecification+CoreData.m index 5ace1b43..9620487a 100644 --- a/sope-core/EOCoreData/EOFetchSpecification+CoreData.m +++ b/sope-core/EOCoreData/EOFetchSpecification+CoreData.m @@ -28,8 +28,54 @@ @implementation EOFetchSpecification(CoreData) - (id)initWithFetchRequest:(NSFetchRequest *)_fr { -#warning IMPLEMENT ME - return nil; + NSMutableArray *so; + EOQualifier *q; + NSArray *sd; + unsigned count; + + if (_fr == nil) { + [self release]; + return nil; + } + + /* convert sort descriptors */ + + sd = [_fr sortDescriptors]; + so = nil; + if ((count = [sd count]) > 0) { + unsigned i; + + so = [[NSMutableArray alloc] initWithCapacity:count]; + for (i = 0; i < count; i++) { + EOSortOrdering *soo; + + soo = [[EOSortOrdering alloc] initWithSortDescriptor: + [sd objectAtIndex:i]]; + if (soo == nil) { + soo = [sd objectAtIndex:i]; /* oh well, this is sneaky */ + NSLog(@"WARNING(%s): could not convert NSSortDescriptor to " + @"EOSortOrdering: %@", __PRETTY_FUNCTION__, soo); + } + [so addObject:soo]; + [soo release]; + } + } + + /* convert predicate */ + + q = [EOQualifier qualifierForPredicate:[_fr predicate]]; + + /* create object */ + + // TODO: maybe add 'affectedStores' as a hint? + self = [self initWithEntityName:[[_fr entity] name] + qualifier:q sortOrderings:so + usesDistinct:YES isDeep:NO + hints:nil]; + [so release]; so = nil; + + [self setFetchLimit:[_fr fetchLimit]]; + return self; } - (NSArray *)sortOrderingsAsSortDescriptors { @@ -74,3 +120,15 @@ } @end /* EOFetchSpecification(CoreData) */ + + +@implementation NSFetchRequest(EOCoreData) + +- (NSFetchRequest *)fetchRequestWithEntity:(NSEntityDescription *)_entity { + return self; +} +- (NSFetchRequest *)fetchRequestWithModel:(NSManagedObjectModel *)_model { + return self; +} + +@end /* NSFetchRequest(EOCoreData) */ diff --git a/sope-core/EOCoreData/EOKeyComparisonQualifier+CoreData.m b/sope-core/EOCoreData/EOKeyComparisonQualifier+CoreData.m new file mode 100644 index 00000000..15c62c9c --- /dev/null +++ b/sope-core/EOCoreData/EOKeyComparisonQualifier+CoreData.m @@ -0,0 +1,66 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "EOQualifier+CoreData.h" +#include "NSPredicate+EO.h" +#include "NSExpression+EO.h" +#include "common.h" + +@implementation EOKeyComparisonQualifier(CoreData) + ++ (EOQualifier *)qualifierForComparisonPredicate:(NSComparisonPredicate *)_p { + SEL sel; + + if ((sel = [self eoSelectorForForComparisonPredicate:_p]) == nil) + return (EOQualifier *)_p; + + return [[[self alloc] initWithLeftKey:[[_p leftExpression] keyPath] + operatorSelector:sel + rightKey:[[_p rightExpression] keyPath]] autorelease]; +} + +- (NSPredicate *)asPredicate { + NSLog(@"TODO(%s): implement me for class %@!", __PRETTY_FUNCTION__, + NSStringFromClass([self class])); + return nil; +} + +/* CoreData compatibility */ + +- (NSComparisonPredicateModifier)comparisonPredicateModifier { + return NSDirectPredicateModifier; +} + +- (NSPredicateOperatorType)predicateOperatorType { + return [[self class] predicateOperatorTypeForEOSelector:[self selector]]; +} + +- (unsigned)options { + return (SEL_EQ([self selector], EOQualifierOperatorCaseInsensitiveLike)) + ? NSCaseInsensitivePredicateOption : 0; +} + +- (SEL)customSelector { + return [self predicateOperatorType] == NSCustomSelectorPredicateOperatorType + ? [self selector] : nil; +} + +@end /* EOKeyComparisonQualifier(CoreData) */ diff --git a/sope-core/EOCoreData/EOKeyValueQualifier+CoreData.m b/sope-core/EOCoreData/EOKeyValueQualifier+CoreData.m new file mode 100644 index 00000000..5c621987 --- /dev/null +++ b/sope-core/EOCoreData/EOKeyValueQualifier+CoreData.m @@ -0,0 +1,67 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "EOQualifier+CoreData.h" +#include "NSPredicate+EO.h" +#include "NSExpression+EO.h" +#include "common.h" + +@implementation EOKeyValueQualifier(CoreData) + ++ (EOQualifier *)qualifierForComparisonPredicate:(NSComparisonPredicate *)_p { + SEL sel; + + if ((sel = [self eoSelectorForForComparisonPredicate:_p]) == nil) + return (EOQualifier *)_p; + + return [[[self alloc] initWithKey:[[_p leftExpression] keyPath] + operatorSelector:sel + value:[[_p rightExpression] constantValue]] + autorelease]; +} + +- (NSPredicate *)asPredicate { + NSLog(@"TODO(%s): implement me for class %@!", __PRETTY_FUNCTION__, + NSStringFromClass([self class])); + return nil; +} + +/* CoreData compatibility */ + +- (NSComparisonPredicateModifier)comparisonPredicateModifier { + return NSDirectPredicateModifier; +} + +- (NSPredicateOperatorType)predicateOperatorType { + return [[self class] predicateOperatorTypeForEOSelector:[self selector]]; +} + +- (unsigned)options { + return (SEL_EQ([self selector], EOQualifierOperatorCaseInsensitiveLike)) + ? NSCaseInsensitivePredicateOption : 0; +} + +- (SEL)customSelector { + return [self predicateOperatorType] == NSCustomSelectorPredicateOperatorType + ? [self selector] : nil; +} + +@end /* EOKeyValueQualifier(CoreData) */ diff --git a/sope-core/EOCoreData/EOQualifier+CoreData.h b/sope-core/EOCoreData/EOQualifier+CoreData.h index b6700aeb..43e10161 100644 --- a/sope-core/EOCoreData/EOQualifier+CoreData.h +++ b/sope-core/EOCoreData/EOQualifier+CoreData.h @@ -22,6 +22,8 @@ #ifndef __EOQualifier_CoreData_H__ #define __EOQualifier_CoreData_H__ +#import +#import #include /* @@ -31,13 +33,62 @@ object. */ -@class NSPredicate; +@class NSArray; +@class NSPredicate, NSExpression, NSComparisonPredicate, NSCompoundPredicate; @interface EOQualifier(CoreData) -- (id)initWithPredicate:(NSPredicate *)_predicate; ++ (EOQualifier *)qualifierForPredicate:(NSPredicate *)_predicate; - (NSPredicate *)asPredicate; +- (NSExpression *)asExpression; +/* support methods */ + ++ (SEL)eoSelectorForForComparisonPredicate:(NSComparisonPredicate *)_p; ++ (NSPredicateOperatorType)predicateOperatorTypeForEOSelector:(SEL)_sel; + +/* CoreData compatibility */ + ++ (NSPredicate *)andPredicateWithSubpredicates:(NSArray *)_sub; ++ (NSPredicate *)orPredicateWithSubpredicates:(NSArray *)_sub; ++ (NSPredicate *)notPredicateWithSubpredicate:(id)_predicate; + +@end + +#import + + +/* compound qualifiers */ + +@interface EOAndQualifier(CoreData) +- (NSCompoundPredicateType)compoundPredicateType; +@end + +@interface EOOrQualifier(CoreData) +- (NSCompoundPredicateType)compoundPredicateType; +@end + +@interface EONotQualifier(CoreData) +- (NSCompoundPredicateType)compoundPredicateType; +@end + + +/* comparison qualifiers */ + +@interface EOKeyValueQualifier(CoreData) ++ (EOQualifier *)qualifierForComparisonPredicate:(NSComparisonPredicate *)_p; +- (NSComparisonPredicateModifier)comparisonPredicateModifier; +- (NSPredicateOperatorType)predicateOperatorType; +- (SEL)customSelector; +- (unsigned)options; +@end + +@interface EOKeyComparisonQualifier(CoreData) ++ (EOQualifier *)qualifierForComparisonPredicate:(NSComparisonPredicate *)_p; +- (NSComparisonPredicateModifier)comparisonPredicateModifier; +- (NSPredicateOperatorType)predicateOperatorType; +- (SEL)customSelector; +- (unsigned)options; @end #endif /* __EOQualifier_CoreData_H__ */ diff --git a/sope-core/EOCoreData/EOQualifier+CoreData.m b/sope-core/EOCoreData/EOQualifier+CoreData.m index 2c76bd80..6d255c97 100644 --- a/sope-core/EOCoreData/EOQualifier+CoreData.m +++ b/sope-core/EOCoreData/EOQualifier+CoreData.m @@ -20,21 +20,167 @@ */ #include "EOQualifier+CoreData.h" +#include "NSPredicate+EO.h" +#include "NSExpression+EO.h" #include "common.h" +/* + CoreData / Foundation EOF + Predicates: + NSComparisonPredicate EOKeyValueQualifier / EOKeyComparisonQualifier + NSCompoundPredicate EOAndQualifier / EOOrQualifier / EONotQualifier + + NSExpressions: + - constant + - evaluatedObject + - variable EOQualifierVariable + - keypath + - function + + EOF operators: + EOQualifierOperatorEqual; + EOQualifierOperatorNotEqual; + EOQualifierOperatorLessThan; + EOQualifierOperatorGreaterThan; + EOQualifierOperatorLessThanOrEqualTo; + EOQualifierOperatorGreaterThanOrEqualTo; + EOQualifierOperatorContains; + EOQualifierOperatorLike; + EOQualifierOperatorCaseInsensitiveLike; +*/ + @implementation EOQualifier(CoreData) -- (id)initWithPredicate:(NSPredicate *)_predicate { -#warning IMPLEMENT ME - NSLog(@"TODO(%s): implement me!", __PRETTY_FUNCTION__); - [self release]; ++ (NSPredicateOperatorType)predicateOperatorTypeForEOSelector:(SEL)_sel { + if (SEL_EQ(_sel, EOQualifierOperatorEqual)) + return NSEqualToPredicateOperatorType; + if (SEL_EQ(_sel, EOQualifierOperatorNotEqual)) + return NSNotEqualToPredicateOperatorType; + + if (SEL_EQ(_sel, EOQualifierOperatorLessThan)) + return NSLessThanPredicateOperatorType; + if (SEL_EQ(_sel, EOQualifierOperatorGreaterThan)) + return NSGreaterThanPredicateOperatorType; + + if (SEL_EQ(_sel, EOQualifierOperatorLessThanOrEqualTo)) + return NSLessThanOrEqualToPredicateOperatorType; + if (SEL_EQ(_sel, EOQualifierOperatorGreaterThanOrEqualTo)) + return NSGreaterThanOrEqualToPredicateOperatorType; + + if (SEL_EQ(_sel, EOQualifierOperatorContains)) + return NSInPredicateOperatorType; + + if (SEL_EQ(_sel, EOQualifierOperatorLike) || + SEL_EQ(_sel, EOQualifierOperatorCaseInsensitiveLike)) + return NSLikePredicateOperatorType; + + return NSCustomSelectorPredicateOperatorType; +} + ++ (SEL)eoSelectorForForComparisonPredicate:(NSComparisonPredicate *)_p { + BOOL hasOpt; + SEL sel = NULL; + + if (_p == nil) + return NULL; + + hasOpt = [_p options] != 0 ? YES : NO; + + // TODO: need to check options + + switch ([_p predicateOperatorType]) { + case NSCustomSelectorPredicateOperatorType: + sel = hasOpt ? NULL : [_p customSelector]; + break; + + case NSLessThanPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorLessThan; break; + case NSLessThanOrEqualToPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorLessThanOrEqualTo; break; + case NSGreaterThanPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorGreaterThan; break; + case NSGreaterThanOrEqualToPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorGreaterThanOrEqualTo; break; + + case NSEqualToPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorEqual; break; + case NSNotEqualToPredicateOperatorType: + sel = hasOpt ? NULL : EOQualifierOperatorNotEqual; break; + + case NSLikePredicateOperatorType: + sel = ([_p options] == NSCaseInsensitivePredicateOption) + ? EOQualifierOperatorCaseInsensitiveLike + : (hasOpt ? NULL : EOQualifierOperatorLike); + break; + + case NSInPredicateOperatorType: + // TODO: for arrays: containsObject:, for strings: containsString: + sel = hasOpt ? NULL : EOQualifierOperatorContains; break; + + case NSBeginsWithPredicateOperatorType: + sel = hasOpt ? NULL : @selector(hasPrefix:); break; + case NSEndsWithPredicateOperatorType: + sel = hasOpt ? NULL : @selector(hasSuffix:); break; + + /* unsupported predicates */ + case NSMatchesPredicateOperatorType: + // TODO + default: + sel = NULL; + break; + } + + if (sel == NULL) { + NSLog(@"ERROR(%s): cannot map NSComparisonPredicate to " + @"EOQualifier selector: %@", + __PRETTY_FUNCTION__, _p); + } + return sel; +} + ++ (EOQualifier *)qualifierForPredicate:(NSPredicate *)_predicate { + if (_predicate == nil) + return nil; + + if ([_predicate respondsToSelector:@selector(asQualifier)]) + return [_predicate asQualifier]; + + NSLog(@"ERROR(%s): cannot convert NSPredicate class %@!", + __PRETTY_FUNCTION__, + NSStringFromClass([self class])); return nil; } +- (EOQualifier *)asQualifier { + return self; +} + - (NSPredicate *)asPredicate { -#warning IMPLEMENT ME - NSLog(@"TODO(%s): implement me!", __PRETTY_FUNCTION__); + NSLog(@"TODO(%s): implement me for class %@!", __PRETTY_FUNCTION__, + NSStringFromClass([self class])); + return nil; +} + +- (NSExpression *)asExpression { return nil; } + +/* CoreData compatibility */ + ++ (NSPredicate *)andPredicateWithSubpredicates:(NSArray *)_sub { + return [NSCompoundPredicate andPredicateWithSubpredicates: + [_sub valueForKey:@"asPredicate"]]; +} + ++ (NSPredicate *)orPredicateWithSubpredicates:(NSArray *)_sub { + return [NSCompoundPredicate orPredicateWithSubpredicates: + [_sub valueForKey:@"asPredicate"]]; +} + ++ (NSPredicate *)notPredicateWithSubpredicate:(id)_predicate { + return [NSCompoundPredicate notPredicateWithSubpredicate: + [_predicate asPredicate]]; +} + @end /* EOQualifier(CoreData) */ diff --git a/sope-core/EOCoreData/EOSortOrdering+CoreData.h b/sope-core/EOCoreData/EOSortOrdering+CoreData.h index 69f18164..efc0dc62 100644 --- a/sope-core/EOCoreData/EOSortOrdering+CoreData.h +++ b/sope-core/EOCoreData/EOSortOrdering+CoreData.h @@ -38,6 +38,11 @@ - (id)initWithSortDescriptor:(NSSortDescriptor *)_descriptor; - (NSSortDescriptor *)asSortDescriptor; +/* converting selectors */ + +- (BOOL)isAscendingEOSortSelector:(SEL)_sel; +- (SEL)cdSortSelectorFromEOSortSelector:(SEL)_sel; + @end #endif /* __EOSortOrdering_CoreData_H__ */ diff --git a/sope-core/EOCoreData/EOSortOrdering+CoreData.m b/sope-core/EOCoreData/EOSortOrdering+CoreData.m index 66317599..d1e9f7e5 100644 --- a/sope-core/EOCoreData/EOSortOrdering+CoreData.m +++ b/sope-core/EOCoreData/EOSortOrdering+CoreData.m @@ -25,16 +25,70 @@ @implementation EOSortOrdering(CoreData) - (id)initWithSortDescriptor:(NSSortDescriptor *)_descriptor { -#warning IMPLEMENT ME - NSLog(@"TODO(%s): implement me!", __PRETTY_FUNCTION__); - [self release]; - return nil; + SEL sel; + + if (_descriptor == nil) { + [self release]; + return nil; + } + + sel = [_descriptor selector]; + if (SEL_EQ(sel, @selector(compare:))) { + sel = [_descriptor ascending] + ? EOCompareAscending + : EOCompareDescending; + } + else if (SEL_EQ(sel, @selector(caseInsensitiveCompare:))) { + sel = [_descriptor ascending] + ? EOCompareCaseInsensitiveAscending + : EOCompareCaseInsensitiveDescending; + } + else { + if (![_descriptor ascending]) { + NSLog(@"WARNING(%s): cannot representing descending selector in " + @"NSSortDescriptor: %@", __PRETTY_FUNCTION__, _descriptor); + } + } + + return [self initWithKey:[_descriptor key] selector:sel]; +} + +- (BOOL)isAscendingEOSortSelector:(SEL)_sel { + if (SEL_EQ(_sel, EOCompareDescending)) return NO; + if (SEL_EQ(_sel, EOCompareCaseInsensitiveAscending)) return NO; + return YES; +} + +- (SEL)cdSortSelectorFromEOSortSelector:(SEL)_sel { + if (SEL_EQ(_sel, EOCompareAscending)) return @selector(compare:); + if (SEL_EQ(_sel, EOCompareDescending)) return @selector(compare:); + + if (SEL_EQ(_sel, EOCompareCaseInsensitiveAscending)) + return @selector(caseInsensitiveCompare:); + if (SEL_EQ(_sel, EOCompareCaseInsensitiveDescending)) + return @selector(caseInsensitiveCompare:); + + return _sel; } - (NSSortDescriptor *)asSortDescriptor { -#warning IMPLEMENT ME - NSLog(@"TODO(%s): implement me!", __PRETTY_FUNCTION__); - return nil; + SEL sel; + + sel = [self selector]; + + return [[[NSSortDescriptor alloc] + initWithKey:[self key] + ascending:[self isAscendingEOSortSelector:sel] + selector:[self cdSortSelectorFromEOSortSelector:sel]] autorelease]; } @end /* EOSortOrdering(CoreData) */ + + +@implementation NSSortDescriptor(EOCoreData) + +- (NSSortDescriptor *)asSortDescriptor { + return self; +} + +@end /* NSSortDescriptor(EOCoreData) */ diff --git a/sope-core/EOCoreData/GNUmakefile b/sope-core/EOCoreData/GNUmakefile index 2befa5c3..94667d16 100644 --- a/sope-core/EOCoreData/GNUmakefile +++ b/sope-core/EOCoreData/GNUmakefile @@ -17,12 +17,19 @@ libEOCoreData_HEADER_FILES = \ EOFetchSpecification+CoreData.h \ EOQualifier+CoreData.h \ EOSortOrdering+CoreData.h \ + NSExpression+EO.h \ + NSPredicate+EO.h \ libEOCoreData_OBJC_FILES = \ - EOCoreDataSource.m \ - EOFetchSpecification+CoreData.m \ - EOQualifier+CoreData.m \ - EOSortOrdering+CoreData.m \ + EOCoreDataSource.m \ + EOFetchSpecification+CoreData.m \ + EOQualifier+CoreData.m \ + EOSortOrdering+CoreData.m \ + NSExpression+EO.m \ + NSPredicate+EO.m \ + EOKeyValueQualifier+CoreData.m \ + EOKeyComparisonQualifier+CoreData.m \ + EOCompoundQualifiers.m \ -include GNUmakefile.preamble diff --git a/sope-core/EOCoreData/NSExpression+EO.h b/sope-core/EOCoreData/NSExpression+EO.h new file mode 100644 index 00000000..8cf46283 --- /dev/null +++ b/sope-core/EOCoreData/NSExpression+EO.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#ifndef __NSExpression_EO_H__ +#define __NSExpression_EO_H__ + +#import + +/* + NSExpression(EO) + + Convert an NSExpression to an EOQualifier. +*/ + +@class NSExpression; +@class EOQualifier; + +@interface NSExpression(EO) + +- (NSPredicate *)asPredicate; +- (NSExpression *)asExpression; + +@end + +#endif /* __NSExpression_EO_H__ */ diff --git a/sope-core/EOCoreData/NSExpression+EO.m b/sope-core/EOCoreData/NSExpression+EO.m new file mode 100644 index 00000000..3f7b3b40 --- /dev/null +++ b/sope-core/EOCoreData/NSExpression+EO.m @@ -0,0 +1,34 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#import +#include "common.h" + +@implementation NSExpression(EOCoreData) + +- (NSPredicate *)asPredicate { + return nil; +} +- (NSExpression *)asExpression { + return self; +} + +@end /* NSPredicate(EOCoreData) */ diff --git a/sope-core/EOCoreData/NSPredicate+EO.h b/sope-core/EOCoreData/NSPredicate+EO.h new file mode 100644 index 00000000..56c31a8b --- /dev/null +++ b/sope-core/EOCoreData/NSPredicate+EO.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#ifndef __NSPredicate_EO_H__ +#define __NSPredicate_EO_H__ + +#import + +/* + NSPredicate(EO) + + Convert an NSPredicate to an EOQualifier. +*/ + +@class NSExpression; +@class EOQualifier; + +@interface NSPredicate(EO) + +- (NSPredicate *)asPredicate; +- (NSExpression *)asExpression; +- (EOQualifier *)asQualifier; + +@end + +#endif /* __NSPredicate_EO_H__ */ diff --git a/sope-core/EOCoreData/NSPredicate+EO.m b/sope-core/EOCoreData/NSPredicate+EO.m new file mode 100644 index 00000000..6485c2bf --- /dev/null +++ b/sope-core/EOCoreData/NSPredicate+EO.m @@ -0,0 +1,133 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "NSPredicate+EO.h" +#include "EOQualifier+CoreData.h" +#include "common.h" + +@implementation NSPredicate(EOCoreData) + +- (NSPredicate *)asPredicate { + return self; +} +- (NSExpression *)asExpression { + return nil; +} + +@end /* NSPredicate(EOCoreData) */ + + +@implementation NSCompoundPredicate(EOCoreData) + +- (EOQualifier *)asQualifier { + /* + Compound predicates join other predicates, they do not deal with + expressions. + */ + NSMutableArray *sq; + NSArray *sp; + unsigned i, count; + Class clazz; + BOOL isNot = NO; + EOQualifier *q; + + sp = [self subpredicates]; + count = [sp count]; + + switch ([self compoundPredicateType]) { + case NSNotPredicateType: + isNot = YES; + clazz = [EONotQualifier class]; + break; + case NSAndPredicateType: + clazz = [EOAndQualifier class]; + break; + case NSOrPredicateType: + clazz = [EOOrQualifier class]; + break; + default: + NSLog(@"ERROR(%s): unknown compound predicate type: %@", + __PRETTY_FUNCTION__, self); + return nil; + } + + if (count == 0) + return [[[clazz alloc] init] autorelease]; + + if (count == 1) { + q = [sp objectAtIndex:0]; + return (isNot) + ? [[[EONotQualifier alloc] initWithQualifier:q] autorelease] + : q; + } + + sq = [[NSMutableArray alloc] initWithCapacity:count]; + + for (i = 0; i < count; i++) { + q = [EOQualifier qualifierForPredicate:[sp objectAtIndex:i]]; + if (q == nil) { + q = [sp objectAtIndex:i]; + NSLog(@"ERROR(%s): could not convert predicate to qualifier: %@", + __PRETTY_FUNCTION__, q); + } + + if (isNot) + q = [[EONotQualifier alloc] initWithQualifier:q]; + + [sq addObject:q]; + if (isNot) [q release]; + + q = nil; + } + + q = [[(isNot ? [EOAndQualifier class] : clazz) alloc] initWithQualifier:q]; + [sq release]; + return [q autorelease]; +} + +@end /* NSCompoundPredicate(EOCoreData) */ + + +@implementation NSComparisonPredicate(EOCoreData) + +- (EOQualifier *)asQualifier { + NSExpression *lhs, *rhs; + + lhs = [self leftExpression]; + rhs = [self rightExpression]; + + // TODO: need to check predicate modifiers + // TODO: add support for variables + + if ([rhs expressionType] == NSKeyPathExpressionType) { + if ([lhs expressionType] == NSConstantValueExpressionType) + return [EOKeyValueQualifier qualifierForComparisonPredicate:self]; + + if ([lhs expressionType] == NSKeyPathExpressionType) + return [EOKeyComparisonQualifier qualifierForComparisonPredicate:self]; + } + + NSLog(@"ERROR(%s): cannot map NSComparisonPredicate to EOQualifier: %@", + __PRETTY_FUNCTION__, self); + return (id)self; +} + +@end /* NSComparisonPredicate(EOCoreData) */ diff --git a/sope-core/EOCoreData/Version b/sope-core/EOCoreData/Version index 93f90d16..ed045adf 100644 --- a/sope-core/EOCoreData/Version +++ b/sope-core/EOCoreData/Version @@ -1,3 +1,3 @@ # version file -SUBMINOR_VERSION:=1 +SUBMINOR_VERSION:=2 diff --git a/sope-core/EOCoreData/common.h b/sope-core/EOCoreData/common.h index f0129b9c..649cbb12 100644 --- a/sope-core/EOCoreData/common.h +++ b/sope-core/EOCoreData/common.h @@ -51,4 +51,17 @@ object = __value;}}) #endif + +#if GNU_RUNTIME +# include +#endif + +#ifndef SEL_EQ +# if GNU_RUNTIME +# define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2) +# else +# define SEL_EQ(sel1,sel2) (sel1 == sel2) +# endif +#endif + #endif /* __EOCoreData_COMMON_H__ */ -- 2.39.5