]> err.no Git - sope/commitdiff
work on CD/EOF translation
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 4 Aug 2005 00:39:18 +0000 (00:39 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 4 Aug 2005 00:39:18 +0000 (00:39 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@963 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

19 files changed:
sope-core/EOCoreData/ChangeLog
sope-core/EOCoreData/EOCompoundQualifiers.m [new file with mode: 0644]
sope-core/EOCoreData/EOCoreData.h
sope-core/EOCoreData/EOCoreDataSource.h
sope-core/EOCoreData/EOCoreDataSource.m
sope-core/EOCoreData/EOFetchSpecification+CoreData.m
sope-core/EOCoreData/EOKeyComparisonQualifier+CoreData.m [new file with mode: 0644]
sope-core/EOCoreData/EOKeyValueQualifier+CoreData.m [new file with mode: 0644]
sope-core/EOCoreData/EOQualifier+CoreData.h
sope-core/EOCoreData/EOQualifier+CoreData.m
sope-core/EOCoreData/EOSortOrdering+CoreData.h
sope-core/EOCoreData/EOSortOrdering+CoreData.m
sope-core/EOCoreData/GNUmakefile
sope-core/EOCoreData/NSExpression+EO.h [new file with mode: 0644]
sope-core/EOCoreData/NSExpression+EO.m [new file with mode: 0644]
sope-core/EOCoreData/NSPredicate+EO.h [new file with mode: 0644]
sope-core/EOCoreData/NSPredicate+EO.m [new file with mode: 0644]
sope-core/EOCoreData/Version
sope-core/EOCoreData/common.h

index 4339c75db424665b4c2aa93ea672d5c66cc3afb5..d11fd545ea5e2aff9e00ca0b80f7a7a768954d0e 100644 (file)
@@ -1,5 +1,19 @@
 2005-08-03  Helge Hess  <helge.hess@opengroupware.org>
 
+       * 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 (file)
index 0000000..ffb0791
--- /dev/null
@@ -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) */
index e9396be90e07199316ba73227cc21b0db6a7e47b..2a806e257354a0e7b436f563986e23539dfb2379 100644 (file)
@@ -27,4 +27,7 @@
 #include <EOCoreData/EOQualifier+CoreData.h>
 #include <EOCoreData/EOSortOrdering+CoreData.h>
 
+#include <EOCoreData/NSExpression+EO.h>
+#include <EOCoreData/NSPredicate+EO.h>
+
 #endif /* __EOCoreData_H__ */
index 0e9b1bee9e01a1c35ee037e383c298847c6dcee0..124f3057be3d6cb848043aa5c67de0fedc59d9e5 100644 (file)
   
   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
   EOFetchSpecification   *fetchSpecification;
   EOQualifier            *auxiliaryQualifier;
   NSDictionary           *qualifierBindings;
+  NSFetchRequest         *fetchRequest;
   struct {
     int isFetchEnabled:1;
-    int reserved:31;
+    int isEntityFromFetchSpec:1;
+    int reserved:30;
   } ecdFlags;
 }
 
 - (void)setQualifierBindings:(NSDictionary *)_bindings;
 - (NSDictionary *)qualifierBindings;
 
+/* directly access a CoreData fetch request */
+
+- (void)setFetchRequest:(NSFetchRequest *)_fr;
+- (NSFetchRequest *)fetchRequest;
+
 /* accessors */
 
 - (NSEntityDescription *)entity;
index 8e5028503ad641fbd82d9f346cf6ecbda376a655..8d328eecc11c4fc01cf9de16fb8263cf2dccd36f 100644 (file)
@@ -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 {
index 5ace1b434f44e96b04aee52fc7262d3de3a90cdc..9620487ad892a7b5ee6094a14c8437fbc3cbb948 100644 (file)
 @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 {
 }
 
 @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 (file)
index 0000000..15c62c9
--- /dev/null
@@ -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 (file)
index 0000000..5c62198
--- /dev/null
@@ -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) */
index b6700aeb58c9d5c4c563bce777969f8d70b60bb8..43e10161de4c40fcfc19e0291c72a9deab5243ba 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __EOQualifier_CoreData_H__
 #define __EOQualifier_CoreData_H__
 
+#import <Foundation/NSPredicate.h>
+#import <Foundation/NSComparisonPredicate.h>
 #include <EOControl/EOQualifier.h>
 
 /*
   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 <Foundation/Foundation.h>
+
+
+/* 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__ */
index 2c76bd805e60c08ccb5410d8dcb73f7b54f93a54..6d255c97295107ffd82bb407a618866772e927a7 100644 (file)
 */
 
 #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) */
index 69f18164e17ad56aeae7191a7d0a8747991739f8..efc0dc629bb22c81b5a5ffeb77bdf0b21f78dd46 100644 (file)
 - (id)initWithSortDescriptor:(NSSortDescriptor *)_descriptor;
 - (NSSortDescriptor *)asSortDescriptor;
 
+/* converting selectors */
+
+- (BOOL)isAscendingEOSortSelector:(SEL)_sel;
+- (SEL)cdSortSelectorFromEOSortSelector:(SEL)_sel;
+
 @end
 
 #endif /* __EOSortOrdering_CoreData_H__ */
index 66317599471256978a56b4b323326c599caf07a4..d1e9f7e59de169e0a78b368f378077f5729e171f 100644 (file)
 @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) */
index 2befa5c3e6f7e1406c056db7105ef5c80cf1291f..94667d1660680bb273689626bf2403ef10e465d0 100644 (file)
@@ -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 (file)
index 0000000..8cf4628
--- /dev/null
@@ -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 <Foundation/NSExpression.h>
+
+/*
+  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 (file)
index 0000000..3f7b3b4
--- /dev/null
@@ -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 <Foundation/NSExpression.h>
+#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 (file)
index 0000000..56c31a8
--- /dev/null
@@ -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 <Foundation/NSPredicate.h>
+
+/*
+  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 (file)
index 0000000..6485c2b
--- /dev/null
@@ -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) */
index 93f90d160d934db19ec53d743f5928d2ae1f646f..ed045adfeab4736fa025a4a2ef062f6515fc7a9c 100644 (file)
@@ -1,3 +1,3 @@
 # version file
 
-SUBMINOR_VERSION:=1
+SUBMINOR_VERSION:=2
index f0129b9cfa48ae1afbbd9e350d83687fa19de5d2..649cbb12a77e859def0877eaef74568453fbc69f 100644 (file)
           object = __value;}})
 #endif
 
+
+#if GNU_RUNTIME
+#  include <objc/objc.h>
+#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__ */