Merge pull request #9 from gunyarakun/fix-typo
[cocotron.git] / CoreData / NSManagedObject.m
blobb8667015e93df1a7de2f79df31c696e220b6c671
1 /* Copyright (c) 2008 Dan Knapp
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8 #import <CoreData/NSManagedObject.h>
9 #import "NSManagedObjectID-Private.h"
10 #import "NSManagedObjectContext-Private.h"
11 #import "NSEntityDescription-Private.h"
12 #import <CoreData/NSAttributeDescription.h>
13 #import <CoreData/NSRelationshipDescription.h>
14 #import <CoreData/NSAtomicStoreCacheNode.h>
15 #import <Foundation/NSRaise.h>
16 #import "NSManagedObjectSet.h"
17 #import "NSManagedObjectSetEnumerator.h"
18 #import "NSManagedObjectMutableSet.h"
20 @implementation NSManagedObject
22 -init {
23    NSLog(@"Error - can't initialize an NSManagedObject with -init");
24    return nil;
27 -initWithObjectID:(NSManagedObjectID *)objectID managedObjectContext:(NSManagedObjectContext *)context {
28    NSEntityDescription *entity=[objectID entity];
29    NSString            *className=[entity managedObjectClassName];
30    Class                class=NSClassFromString(className);
32    if(class==Nil){
33     NSLog(@"Unable to find class %@ specified by entity %@ in the runtime, using NSManagedObject,objectID=%@",className,[entity name],objectID);
34     
35     class=[NSManagedObject class];
36    }
37    
38    [super dealloc];
39    self=[class allocWithZone:NULL];
40    
41    _objectID=[objectID copy];
42    _context=context;
43    _committedValues = nil;
44    _changedValues = [[NSMutableDictionary alloc] init];
45    _isFault=YES;
46    return self;
49 -initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context {
50    NSManagedObjectID *objectID=[[[NSManagedObjectID alloc] initWithEntity:entity] autorelease];
51    
52    if((self=[self initWithObjectID:objectID managedObjectContext:context])==nil)
53     return nil;
55    NSDictionary *attributes=[entity attributesByName];
56    NSEnumerator *state=[attributes keyEnumerator];
57    NSString     *key;
58    
59    while((key=[state nextObject])!=nil){
60     id object=[attributes objectForKey:key];
61     id value=[object defaultValue];
62     
63     if(value!=nil)
64      [self setPrimitiveValue:value forKey:key]; 
65    }
67    [context insertObject:self];
68    
69    return self;
72 -(void)dealloc {
73    [self didTurnIntoFault];
74    
75    [_objectID release];
76    [_changedValues release];
77    [super dealloc];
80 -(NSUInteger)hash {
81    return [_objectID hash];
84 -(BOOL)isEqual:otherX {
85    if(![otherX isKindOfClass:[NSManagedObject class]])
86     return NO;
87    
88    NSManagedObject *other=otherX;
89    
90    return [_objectID isEqual:other->_objectID];
93 -(NSEntityDescription *)entity {
94    return [_objectID entity];
97 -(NSManagedObjectID *)objectID {
98    return _objectID;
101 -self {
102    return self;
105 -(NSManagedObjectContext *)managedObjectContext {
106    return _context;
109 -(BOOL)isInserted {
110    return _isInserted;
113 -(BOOL)isUpdated {
114    return _isUpdated;
117 -(BOOL)isDeleted {
118    return _isDeleted;
121 -(BOOL)isFault {
122    return _isFault;
125 - (BOOL) hasFaultForRelationshipNamed:(NSString *) key {
126     NSUnimplementedMethod();
127     return NO;
130 - (void) awakeFromFetch {
131     NSUnimplementedMethod();
134 - (void) awakeFromInsert {
135     NSUnimplementedMethod();
138 -(NSDictionary *)changedValues {
139    return _changedValues;
142 -(NSDictionary *)_committedValues {
144    if([[self objectID] isTemporaryID])
145     return nil;
146     
147    if(_committedValues==nil){
148     NSAtomicStoreCacheNode *node=[_context _cacheNodeForObjectID:[self objectID]];
149     NSDictionary           *propertyCache=[node propertyCache];
150     NSMutableDictionary    *storedValues=[[NSMutableDictionary alloc] init];
151     
152     NSArray *properties=[[self entity] properties];
153     
154     for(NSPropertyDescription *property in properties){
155      NSString *name=[property name];
156      
157      if([property isKindOfClass:[NSAttributeDescription class]]){
158       id value=[propertyCache objectForKey:name];
159       
160       if(value!=nil){
161        [storedValues setObject:value forKey:name];
162       }
163      }
164      else if([property isKindOfClass:[NSRelationshipDescription class]]){
165       NSRelationshipDescription *relationship=(NSRelationshipDescription *)property;
166       id                         indirectValue=[propertyCache objectForKey:name];
168       if(indirectValue!=nil){
169        id value;
170              
171        if(![relationship isToMany])
172         value=[indirectValue objectID];
173        else {
174         value=[NSMutableSet set];
175         
176         for(NSAtomicStoreCacheNode *relNode in indirectValue){
177          [value addObject:[relNode objectID]];
178         }
179        }
180        
181        [storedValues setObject:value forKey:name];
182       }
183      }
184     }
185     
186     [_committedValues release];
187     _committedValues=storedValues;
188    }
189    return _committedValues;
192 -(NSDictionary *)committedValuesForKeys:(NSArray *)keys {   
193    if(keys==nil)
194     return [self _committedValues];
195    else {
196     NSMutableDictionary *result=[NSMutableDictionary dictionary];
197     
198     for(NSString *key in keys){
199      id object=[[self _committedValues] objectForKey:key];
200      
201      if(object!=nil){
202       [result setObject:object forKey:key];
203      }
204     }
205     
206     return result;
207    }
210 - (void) didSave {
213 - (void) willTurnIntoFault {
214   // do nothing per doc.s
217 - (void) didTurnIntoFault {
218   // do nothing also?
221 - (void) willSave {
225 -valueForKey:(NSString *)key {
226    if(!key)
227     return [self valueForUndefinedKey:nil];
229    NSPropertyDescription *property=[[self entity] _propertyForSelector:NSSelectorFromString(key)];
230    NSString *propertyName=[property name];
231    
232    if([property isKindOfClass:[NSAttributeDescription class]]){
233     [self willAccessValueForKey:propertyName];
234     
235     id result=[self primitiveValueForKey:propertyName];
236     
237     [self didAccessValueForKey:propertyName];
238     
239     return result;
240    }
241    else if([property isKindOfClass:[NSRelationshipDescription class]]){
242     NSRelationshipDescription *relationship=(NSRelationshipDescription *)property;
243     
244     [self willAccessValueForKey:propertyName];
246     id result=[self primitiveValueForKey:propertyName];
247     
248     if(result!=nil){
249      if([relationship isToMany])
250       result=[[[NSManagedObjectSet alloc] initWithManagedObjectContext:_context set:result] autorelease];
251      else
252       result=[_context objectWithID:result];
253     }
254     
255     [self didAccessValueForKey:propertyName];
256     
257     return result;
258    }
259   
260    return [super valueForKey:key];
264 -(void)setValue:value forKey:(NSString *) key {
265    NSPropertyDescription *property= [[self entity] _propertyForSelector:NSSelectorFromString(key)];
266    NSString              *propertyName=[property name];
267    
268    if([property isKindOfClass:[NSAttributeDescription class]]){
269     [self willChangeValueForKey:propertyName];
270     [self setPrimitiveValue:value forKey:propertyName];
271     [self didChangeValueForKey:propertyName];
272     return;
273    }
274    else if([property isKindOfClass:[NSRelationshipDescription class]]){
275     NSRelationshipDescription *relationship=(NSRelationshipDescription *)property;
276     NSRelationshipDescription *inverse=[relationship inverseRelationship];
277     NSString                  *inverseName=[inverse name];
278     id                         valueByID;
279         
280     if([relationship isToMany]){
281      NSMutableSet *set=[NSMutableSet set];
282      
283      for(NSManagedObject *object in value)
284       [set addObject:[object objectID]];
285       
286      valueByID=set;
287     }
288     else {
289      valueByID=[value objectID];
290     }
292     if(inverse!=nil){
293      id primitivePrevious=[self primitiveValueForKey:key];
294      
295      if(primitivePrevious!=nil){
296       NSSet *allPrevious=[relationship isToMany]?primitivePrevious:[NSSet setWithObject:primitivePrevious];
297       
298       for(NSManagedObjectID *previousID in allPrevious){
299        NSManagedObject *previous=[_context objectWithID:previousID];
301      // FIXME: should be using set mutation notifications for to many
302        [previous willChangeValueForKey:inverseName];
304        if([inverse isToMany])
305         [[previous primitiveValueForKey:inverseName] removeObject:[self objectID]];
306        else
307         [previous setPrimitiveValue:nil forKey:inverseName];
308       
309        [previous didChangeValueForKey:inverseName];
310       }
311      }
312     }
314     [self willChangeValueForKey:propertyName];
315     [self setPrimitiveValue:valueByID forKey:propertyName];
316     [self didChangeValueForKey:propertyName];
318     if(inverse!=nil){     
319      NSSet *allValues=[relationship isToMany]?valueByID:[NSSet setWithObject:valueByID];
321      for(NSManagedObjectID *valueID in allValues){
322       NSManagedObject *value=[_context objectWithID:valueID];
324      // FIXME: should be using set mutation notifications for to many
325       [value willChangeValueForKey:inverseName];
326      
327       if([inverse isToMany]){
328        NSMutableSet *set=[value primitiveValueForKey:inverseName];
329     
330        if(set==nil){
331         set=[NSMutableSet set];
332         [value setPrimitiveValue:set forKey:inverseName];
333        }
335        [set addObject:[self objectID]];
336       }
337       else{
338        [value setPrimitiveValue:[self objectID] forKey:inverseName];
339       }
340      
341       [value didChangeValueForKey:inverseName];
342      }
343     }
344     return;
345    }
346    
347    [super setValue:value forKey:key];
350 -(NSMutableSet *) mutableSetValueForKey:(NSString *) key {
351    return [[[NSManagedObjectMutableSet alloc] initWithManagedObject:self key:key] autorelease];
354 -primitiveValueForKey:(NSString *) key {
355    id result=[_changedValues objectForKey:key];
356    
357    if(result==nil)
358     result=[[self _committedValues] objectForKey:key];
359    
360    return result;
363 -(void)setPrimitiveValue:value forKey:(NSString *)key {
364    if(value==nil)
365     [_changedValues removeObjectForKey:key];
366    else {
367     [_changedValues setObject:value forKey:key];
368    }
371 - (BOOL) validateValue:(id *) value forKey:(NSString *) key error:(NSError **) error {
372     NSUnimplementedMethod();
373     return YES;
377 - (BOOL) validateForDelete:(NSError **) error {
378     NSUnimplementedMethod();
379     return YES;
383 - (BOOL) validateForInsert:(NSError **) error {
384     NSUnimplementedMethod();
385     return YES;
389 - (BOOL) validateForUpdate:(NSError **) error {
390     NSUnimplementedMethod();
391     return YES;
395 +(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
396   // FIXME: Doc.s for NSManagedObject state this returns YES for unmodeled properties.
398    return NO;
401 -(void)didAccessValueForKey:(NSString *) key {
404 -(void *)observationInfo {
405    return _observationInfo;
409 -(void)setObservationInfo:(void *) value {
410    _observationInfo=value;
413 -(void)willAccessValueForKey:(NSString *)key {
416 -(NSString *)description {
417    NSMutableDictionary *values=[NSMutableDictionary dictionaryWithDictionary:[self _committedValues]];
418    
419    [values addEntriesFromDictionary:_changedValues];
420    
421    return [NSString stringWithFormat:@"<%@ %x:objectID=%@ entity name=%@, values=%@>",isa,self,_objectID,[self entity],values];
424 @end