libs-gscoredata/NSEntityDescription.m

417 lines
12 KiB
Mathematica
Raw Permalink Normal View History

/* Implementation of the NSEntityDescription class for the GNUstep
Core Data framework.
Copyright (C) 2005 Free Software Foundation, Inc.
Written by: Saso Kiselkov <diablos@manga.sk>
Date: August 2005
This file is part of the GNUstep Core Data framework.
This library 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.1 of the License, or (at your option) any later version.
This library 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 this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
*/
#import "CoreDataHeaders.h"
// Ensures the entity can be edited. Raises an NSGenericException
// if the passed model is not nil and is not editable, with a reason
// set to `reason'.
static inline void EnsureEntityEditable(NSManagedObjectModel * model,
NSString * reason)
{
if (model != nil && [model _isEditable] == NO)
{
[NSException raise: NSGenericException format: reason];
}
}
@implementation NSEntityDescription
- (NSDictionary *) _filteredPropertiesOfClass: (Class) aClass
{
NSMutableDictionary * dict;
NSEnumerator * e;
NSPropertyDescription * property;
dict = [NSMutableDictionary dictionaryWithCapacity: [_properties count]];
e = [_properties objectEnumerator];
while ((property = [e nextObject]) != nil)
{
if (aClass == Nil || [property isKindOfClass: aClass])
{
[dict setObject: property forKey: [property name]];
}
}
return [[dict copy] autorelease];
}
- (NSDictionary *) _fetchedPropertiesByName
{
return [self _filteredPropertiesOfClass: [NSFetchedPropertyDescription
class]];
}
+ (NSEntityDescription *) entityForName: (NSString *) entityName
inManagedObjectContext: (NSManagedObjectContext *) ctxt
{
return [[[[ctxt persistentStoreCoordinator] managedObjectModel]
entitiesByName] objectForKey: entityName];
}
+ (id) insertNewObjectForEntityForName: (NSString *) anEntityName
inManagedObjectContext: (NSManagedObjectContext *) aContext
{
NSEntityDescription * entity;
Class entityClass;
NSManagedObjectModel * model;
model = [[aContext persistentStoreCoordinator] managedObjectModel];
entity = [[model entitiesByName] objectForKey: anEntityName];
entityClass = NSClassFromString([entity managedObjectClassName]);
return [[[entityClass alloc]
initWithEntity: entity insertIntoManagedObjectContext: aContext]
autorelease];
}
- (void) dealloc
{
TEST_RELEASE(_name);
// let go of our properties
[_properties makeObjectsPerformSelector: @selector(_setEntity:)
withObject: nil];
TEST_RELEASE(_properties);
TEST_RELEASE(_userInfo);
TEST_RELEASE(_managedObjectClassName);
[_subentities makeObjectsPerformSelector: @selector(setSuperentity:)
withObject: nil];
TEST_RELEASE(_subentities);
[super dealloc];
}
- (NSString *) name
{
return _name;
}
- (void) setName: (NSString *) aName
{
EnsureEntityEditable(_model, _(@"Tried to set the name of an "
@"entity alredy in use."));
ASSIGN(_name, aName);
}
- (NSManagedObjectModel *) managedObjectModel
{
return _model;
}
- (NSString *) managedObjectClassName
{
return _managedObjectClassName;
}
- (void) setManagedObjectClassName: (NSString *) aName
{
EnsureEntityEditable(_model, _(@"Tried to set the managed object "
@"class name of an entity already in use"));
ASSIGN(_managedObjectClassName, aName);
}
- (BOOL) isAbstract
{
return _abstract;
}
- (void) setAbstract: (BOOL) flag
{
EnsureEntityEditable(_model, _(@"Tried to set abstractness "
@"of an entity already in use"));
_abstract = flag;
}
/**
* Returns YES if the receiver is a subentity (inclusively) of
* `otherEntity', and NO otherwise.
*/
- (BOOL) _isSubentityOfEntity: (NSEntityDescription *) otherEntity
{
NSEntityDescription * entity;
for (entity = self; entity != nil; entity = [entity superentity])
{
if ([entity isEqual: otherEntity])
{
return YES;
}
}
return NO;
}
- (NSDictionary *) subentitiesByName
{
NSMutableDictionary * dict;
NSEnumerator * e;
NSEntityDescription * subentity;
dict = [NSMutableDictionary dictionaryWithCapacity: [_subentities count]];
e = [_subentities objectEnumerator];
while ((subentity = [e nextObject]) != nil)
{
[dict setObject: subentity forKey: [subentity name]];
}
return [[dict copy] autorelease];
}
- (NSArray *) subentities
{
return _subentities;
}
- (void) setSubentities: (NSArray *) someEntities
{
EnsureEntityEditable(_model, _(@"Tried to set sub-entities of an entity "
@"already in use"));
ASSIGN(_subentities, [[someEntities copy] autorelease]);
}
- (NSEntityDescription *) superentity
{
return _superentity;
}
- (void) _setSuperentity: (NSEntityDescription *) entity
{
EnsureEntityEditable(_model, _(@"Tried to set super-entity of an entity "
@"already in use"));
_superentity = entity;
}
- (NSDictionary *) propertiesByName
{
return [self filteredPropertiesOfClass: Nil];
}
- (NSArray *) properties
{
return _properties;
}
- (void) setProperties: (NSArray *) someProperties
{
EnsureEntityEditable(_model, _(@"Tried to set properties "
@"of an entity already in use"));
ASSIGN(_properties, [[someProperties copy] autorelease]);
[_properties makeObjectsPerformSelector: @selector(_setEntity:)
withObject: self];
}
- (NSDictionary *) userInfo
{
return _userInfo;
}
- (void) setUserInfo: (NSDictionary *) userInfo
{
EnsureEntityEditable(_model, _(@"Tried to set properties "
@"of an entity already in use"));
ASSIGN(_userInfo, [[userInfo copy] autorelease]);
}
- (NSDictionary *) attributesByName
{
return [self _filteredPropertiesOfClass: [NSAttributeDescription class]];
}
- (NSDictionary *) relationshipsByName
{
return [self _filteredPropertiesOfClass: [NSRelationshipDescription class]];
}
- (NSArray *) relationshipsWithDestinationEntity:
(NSEntityDescription *) destEntity
{
NSMutableArray * array;
NSEnumerator * e;
NSRelationshipDescription * relationship;
Class relationshipClass;
array = [NSMutableArray arrayWithCapacity: [_properties count]];
relationshipClass = [NSRelationshipDescription class];
e = [_properties objectEnumerator];
while ((relationship = [e nextObject]) != nil)
{
if ([relationship isKindOfClass: relationshipClass] &&
[relationship destinationEntity] == destEntity)
{
[array addObject: relationship];
}
}
return [[array copy] autorelease];
}
// NSCopying
- (id) copyWithZone: (NSZone *) aZone
{
NSEntityDescription * entity;
entity = [[NSEntityDescription allocWithZone: aZone] init];
[entity setName: _name];
[entity setManagedObjectClassName: _managedObjectClassName];
[entity setAbstract: _abstract];
[entity setSubentities: _subentities];
[entity _setSuperentity: _superentity];
return entity;
}
// NSCoding
- (id) initWithCoder: (NSCoder *) coder
{
if ((self = [self init]))
{
if ([coder allowsKeyedCoding])
{
ASSIGN(_name, [coder decodeObjectForKey: @"Name"]);
_abstract = [coder decodeBoolForKey: @"Abstract"];
ASSIGN(_managedObjectClassName,
[coder decodeObjectForKey: @"ManagedObjectClassName"]);
ASSIGN(_properties, [coder decodeObjectForKey: @"Properties"]);
ASSIGN(_userInfo, [coder decodeObjectForKey: @"UserInfo"]);
ASSIGN(_subentities, [coder decodeObjectForKey: @"SubEntities"]);
_superentity = [coder decodeObjectForKey: @"SuperEntity"];
_model = [coder decodeObjectForKey: @"ManagedObjectModel"];
_modelRefCount = [coder decodeIntForKey: @"ModelReferenceCount"];
}
else
{
ASSIGN(_name, [coder decodeObject]);
[coder decodeValueOfObjCType: @encode(BOOL) at: &_abstract];
ASSIGN(_managedObjectClassName, [coder decodeObject]);
ASSIGN(_properties, [coder decodeObject]);
ASSIGN(_userInfo, [coder decodeObject]);
ASSIGN(_subentities, [coder decodeObject]);
_superentity = [coder decodeObject];
_model = [coder decodeObject];
[coder decodeValueOfObjCType: @encode(unsigned int)
at: &_modelRefCount];
}
}
return self;
}
- (void) encodeWithCoder: (NSCoder *) coder
{
if ([coder allowsKeyedCoding])
{
[coder encodeObject: _name forKey: @"Name"];
[coder encodeBool: _abstract forKey: @"Abstract"];
[coder encodeObject: _managedObjectClassName
forKey: @"ManagedObjectClassName"];
[coder encodeObject: _properties forKey: @"Properties"];
[coder encodeObject: _userInfo forKey: @"UserInfo"];
[coder encodeObject: _subentities forKey: @"SubEntities"];
[coder encodeObject: _superentity forKey: @"SuperEntity"];
[coder encodeObject: _model forKey: @"ManagedObjectModel"];
[coder encodeInt: _modelRefCount forKey: @"ModelReferenceCount"];
}
else
{
[coder encodeObject: _name];
[coder encodeValueOfObjCType: @encode(BOOL) at: &_abstract];
[coder encodeObject: _managedObjectClassName];
[coder encodeObject: _properties];
[coder encodeObject: _userInfo];
[coder encodeObject: _subentities];
[coder encodeObject: _superentity];
[coder encodeObject: _model];
[coder encodeValueOfObjCType: @encode(unsigned int)
at: &_modelRefCount];
}
}
/**
* This makes the receiver refer to the passed model as it's managed
* object model. Sending it repeatedly will increment the reference count
* to the model. This happens when the entity is, for example, put into
* several configurations inside the same model.
*
* Under no circumstances can another managed object model try to grab the
* entity this way - an assertion failure would arise should another model
* try to increment the count. This way we ensure that an entity can only
* be contained in a single model.
*
* To again "release" the entity from the managed object model, that model
* must send "-removeReferenceToManagedObjectModel:" as many times as it
* sent this message.
*/
- (void) _addReferenceToManagedObjectModel: (NSManagedObjectModel *) aModel
{
// don't allow re-setting the owner like this
NSAssert(aModel != nil && (_model == nil || _model == aModel),
_(@"Attempted to forcefully change the reference from an entity "
@"to it's managed object model owner or ``nil'' model argument "
@"passed."));
_model = aModel;
_modelRefCount++;
}
- (void) _removeReferenceToManagedObjectModel: (NSManagedObjectModel *) aModel
{
NSAssert(_model == aModel, _(@"Attempted to forcefully remove the "
@"reference from an entity to it's managed object model by some other, "
@"unrelated model."));
NSAssert(_modelRefCount > 0, _(@"Attempted to underflow the "
@"reference count from an entity to it's managed object model."));
_modelRefCount--;
if (_modelRefCount == 0)
{
_model = nil;
}
}
@end