mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-30 07:20:35 +00:00
464 lines
15 KiB
Objective-C
464 lines
15 KiB
Objective-C
/* Copyright (c) 2008 Dan Knapp
|
|
|
|
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:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
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. */
|
|
#import "NSEntityDescription-Private.h"
|
|
#import <CoreData/NSAttributeDescription.h>
|
|
#import <CoreData/NSManagedObject.h>
|
|
#import <CoreData/NSManagedObjectContext.h>
|
|
#import <CoreData/NSManagedObjectModel.h>
|
|
#import <CoreData/NSPersistentStoreCoordinator.h>
|
|
#import <CoreData/NSPropertyDescription.h>
|
|
#import <CoreData/NSRelationshipDescription.h>
|
|
#import <Foundation/NSKeyedUnarchiver.h>
|
|
#import <Foundation/NSRaise.h>
|
|
#import <ctype.h>
|
|
#import <objc/objc-class.h>
|
|
#import <stdint.h>
|
|
#import <string.h>
|
|
|
|
@implementation NSEntityDescription
|
|
|
|
static id getValue(id self, SEL selector) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
id result = [self valueForKey: [property name]];
|
|
return result;
|
|
}
|
|
|
|
static void setValue(id self, SEL selector, id newValue) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
[self setValue: newValue forKey: [property name]];
|
|
}
|
|
|
|
static void addObject(id self, SEL selector, id value) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
NSMutableSet *set = [self mutableSetValueForKey: [property name]];
|
|
|
|
[set addObject: value];
|
|
}
|
|
|
|
static void removeObject(id self, SEL selector, id value) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
NSMutableSet *set = [self mutableSetValueForKey: [property name]];
|
|
[set removeObject: value];
|
|
}
|
|
|
|
static void addObjectSet(id self, SEL selector, NSSet *values) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
NSMutableSet *set = [self mutableSetValueForKey: [property name]];
|
|
[set unionSet: values];
|
|
}
|
|
|
|
static void removeObjectSet(id self, SEL selector, NSSet *values) {
|
|
NSPropertyDescription *property =
|
|
[[self entity] _propertyForSelector: selector];
|
|
NSMutableSet *set = [self mutableSetValueForKey: [property name]];
|
|
[set minusSet: values];
|
|
}
|
|
|
|
id keyObjectForSelector(SEL selector) {
|
|
return [NSNumber numberWithInteger: (NSInteger) selector];
|
|
}
|
|
|
|
static void appendMethodToList(Class class, NSString *selectorName, IMP imp,
|
|
const char *types, SEL *selectorp)
|
|
{
|
|
|
|
SEL selector = NSSelectorFromString(selectorName);
|
|
|
|
class_addMethod(class, selector, imp, types);
|
|
|
|
*selectorp = selector;
|
|
}
|
|
|
|
- initWithCoder: (NSCoder *) coder {
|
|
if (![coder allowsKeyedCoding]) {
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"%@ can not initWithCoder:%@", [self class],
|
|
[coder class]];
|
|
return nil;
|
|
}
|
|
|
|
_className = [[coder decodeObjectForKey: @"NSClassNameForEntity"] retain];
|
|
_name = [[coder decodeObjectForKey: @"NSEntityName"] retain];
|
|
_model = [coder decodeObjectForKey: @"NSManagedObjectModel"];
|
|
_properties = [[coder decodeObjectForKey: @"NSProperties"] retain];
|
|
_subentities = [[coder decodeObjectForKey: @"NSSubentities"] retain];
|
|
_superentity = [[coder decodeObjectForKey: @"NSSuperentity"] retain];
|
|
_userInfo = [[coder decodeObjectForKey: @"NSUserInfo"] retain];
|
|
_versionHashModifier =
|
|
[[coder decodeObjectForKey: @"NSVersionHashModifier"] retain];
|
|
|
|
_selectorPropertyMap = [[NSMutableDictionary alloc] init];
|
|
|
|
_hasBeenInstantiated = NO;
|
|
|
|
if (_className) {
|
|
Class class = NSClassFromString(_className);
|
|
|
|
for (NSPropertyDescription *property in [_properties allValues]) {
|
|
NSString *propertyName = [property name];
|
|
NSString *upperName = [[[propertyName substringToIndex: 1]
|
|
uppercaseString]
|
|
stringByAppendingString: [propertyName
|
|
substringFromIndex: 1]];
|
|
NSString *selectorName;
|
|
SEL selector;
|
|
|
|
appendMethodToList(class, propertyName, (IMP) getValue,
|
|
"@@:", &selector);
|
|
[_selectorPropertyMap setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
|
|
appendMethodToList(
|
|
class, [NSString stringWithFormat: @"set%@:", upperName],
|
|
(IMP) setValue, "v@:@", &selector);
|
|
[_selectorPropertyMap setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
|
|
if ([property isKindOfClass: [NSRelationshipDescription class]]) {
|
|
NSRelationshipDescription *relationship =
|
|
(NSRelationshipDescription *) property;
|
|
|
|
if ([relationship isToMany]) {
|
|
appendMethodToList(
|
|
class,
|
|
[NSString stringWithFormat: @"add%@Object:",
|
|
upperName],
|
|
(IMP) addObject, "v@:@", &selector);
|
|
[_selectorPropertyMap
|
|
setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
|
|
appendMethodToList(
|
|
class,
|
|
[NSString stringWithFormat: @"remove%@Object:",
|
|
upperName],
|
|
(IMP) removeObject, "v@:@", &selector);
|
|
[_selectorPropertyMap
|
|
setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
|
|
appendMethodToList(
|
|
class,
|
|
[NSString stringWithFormat: @"add%@:", upperName],
|
|
(IMP) addObjectSet, "v@:@", &selector);
|
|
[_selectorPropertyMap
|
|
setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
|
|
appendMethodToList(class,
|
|
[NSString stringWithFormat: @"remove%@:",
|
|
upperName],
|
|
(IMP) removeObjectSet, "v@:@",
|
|
&selector);
|
|
[_selectorPropertyMap
|
|
setObject: property
|
|
forKey: keyObjectForSelector(selector)];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSString *) description {
|
|
return [NSString stringWithFormat: @"<NSEntityDescription %@>", _name];
|
|
}
|
|
|
|
- (NSPropertyDescription *) _propertyForSelector: (SEL) selector {
|
|
id keyObject = keyObjectForSelector(selector);
|
|
NSEntityDescription *entity;
|
|
|
|
for (entity = self; entity; entity = [entity superentity]) {
|
|
NSPropertyDescription *result =
|
|
[entity->_selectorPropertyMap objectForKey: keyObject];
|
|
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (BOOL) _hasBeenInstantiated {
|
|
return _hasBeenInstantiated;
|
|
}
|
|
|
|
/*
|
|
- (BOOL) _computeAttribute: (NSAttributeDescription *) attribute
|
|
getter: (IMP *) getter
|
|
setter: (IMP *) setter
|
|
{
|
|
switch([attribute attributeType]) {
|
|
case NSUndefinedAttributeType:
|
|
NSLog(@"Undefined-type attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSInteger16AttributeType:
|
|
NSLog(@"Integer 16 attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSInteger32AttributeType:
|
|
*getter = (IMP) getInt32;
|
|
*setter = (IMP) setInt32;
|
|
return [NSString stringWithUTF8String: @encode(int32_t)];
|
|
|
|
case NSInteger64AttributeType:
|
|
NSLog(@"Integer 64 attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSDecimalAttributeType:
|
|
NSLog(@"Decimal attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSDoubleAttributeType:
|
|
NSLog(@"Double attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSFloatAttributeType:
|
|
NSLog(@"Float attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSStringAttributeType:
|
|
*getter = (IMP) getString;
|
|
*setter = (IMP) setString;
|
|
return [NSString stringWithUTF8String: @encode(NSString *)];
|
|
|
|
case NSBooleanAttributeType:
|
|
*getter = (IMP) getBool;
|
|
*setter = (IMP) setBool;
|
|
return [NSString stringWithUTF8String: @encode(BOOL)];
|
|
|
|
case NSDateAttributeType:
|
|
NSLog(@"Date attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSBinaryDataAttributeType:
|
|
NSLog(@"Binary data attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
case NSTransformableAttributeType:
|
|
NSLog(@"Transformable attributes not implemented for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
|
|
default:
|
|
NSLog(@"Unknown attribute type for %@.%@",
|
|
_className, [attribute name]);
|
|
return NO;
|
|
}
|
|
}
|
|
*/
|
|
|
|
+ (NSEntityDescription *) entityForName: (NSString *) entityName
|
|
inManagedObjectContext: (NSManagedObjectContext *) context
|
|
{
|
|
NSDictionary *entities = [[[context persistentStoreCoordinator]
|
|
managedObjectModel] entitiesByName];
|
|
|
|
return [entities objectForKey: entityName];
|
|
}
|
|
|
|
+ insertNewObjectForEntityForName: (NSString *) entityName
|
|
inManagedObjectContext: (NSManagedObjectContext *) context
|
|
{
|
|
NSEntityDescription *entity = [self entityForName: entityName
|
|
inManagedObjectContext: context];
|
|
NSString *className = [entity managedObjectClassName];
|
|
Class class;
|
|
|
|
if (className)
|
|
class = NSClassFromString(className);
|
|
else {
|
|
NSLog(@"Unable to find class %@ specified by entity %@ in the runtime",
|
|
className, [entity name]);
|
|
|
|
class = [NSManagedObject class];
|
|
}
|
|
|
|
return [[class alloc] initWithEntity: entity
|
|
insertIntoManagedObjectContext: context];
|
|
}
|
|
|
|
- (NSManagedObjectModel *) managedObjectModel {
|
|
return _model;
|
|
}
|
|
|
|
- (NSString *) name {
|
|
return _name;
|
|
}
|
|
|
|
- (BOOL) isAbstract {
|
|
return _isAbstract;
|
|
}
|
|
|
|
- (NSString *) managedObjectClassName {
|
|
// should probably init _className like this but initWithCoder logic needs
|
|
// to be changed
|
|
if (_className == nil)
|
|
return @"NSManagedObject";
|
|
|
|
return _className;
|
|
}
|
|
|
|
- (NSArray *) properties {
|
|
return [_properties allValues];
|
|
}
|
|
|
|
- (NSArray *) subentities {
|
|
return [_subentities allValues];
|
|
}
|
|
|
|
- (NSDictionary *) userInfo {
|
|
return _userInfo;
|
|
}
|
|
|
|
- (void) setName: (NSString *) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
value = [value copy];
|
|
[_name release];
|
|
_name = value;
|
|
}
|
|
|
|
- (void) setAbstract: (BOOL) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
_isAbstract = value;
|
|
}
|
|
|
|
- (void) setManagedObjectClassName: (NSString *) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
value = [value copy];
|
|
[_className release];
|
|
_className = value;
|
|
}
|
|
|
|
- (void) setProperties: (NSArray *) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
NSUnimplementedMethod();
|
|
}
|
|
|
|
- (void) setSubentities: (NSArray *) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
NSUnimplementedMethod();
|
|
}
|
|
|
|
- (void) setUserInfo: (NSDictionary *) value {
|
|
if (_hasBeenInstantiated) {
|
|
NSLog(@"Attempt to modify entity after instantiating it.");
|
|
return;
|
|
}
|
|
|
|
value = [value copy];
|
|
[_userInfo release];
|
|
_userInfo = value;
|
|
}
|
|
|
|
- (NSEntityDescription *) superentity {
|
|
return _superentity;
|
|
}
|
|
|
|
- (NSDictionary *) subentitiesByName {
|
|
NSUnimplementedMethod();
|
|
return nil;
|
|
}
|
|
|
|
- (NSDictionary *) attributesByName {
|
|
NSMutableDictionary *result = [NSMutableDictionary dictionary];
|
|
|
|
for (NSPropertyDescription *check in [_properties allValues]) {
|
|
if ([check isKindOfClass: [NSAttributeDescription class]]) {
|
|
[result setObject: check forKey: [check name]];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (NSDictionary *) propertiesByName {
|
|
return _properties;
|
|
}
|
|
|
|
- (NSDictionary *) relationshipsByName {
|
|
NSMutableDictionary *result = [NSMutableDictionary dictionary];
|
|
|
|
for (NSPropertyDescription *check in [_properties allValues]) {
|
|
if ([check isKindOfClass: [NSRelationshipDescription class]])
|
|
[result setObject: check forKey: [check name]];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (NSArray *) relationshipsWithDestinationEntity: (NSEntityDescription *) entity
|
|
{
|
|
NSMutableArray *result = [NSMutableArray array];
|
|
|
|
for (NSPropertyDescription *check in [_properties allValues]) {
|
|
if ([check isKindOfClass: [NSRelationshipDescription class]]) {
|
|
if ([[check entity] isEqual: entity])
|
|
[result addObject: check];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (BOOL) _isKindOfEntity: (NSEntityDescription *) other {
|
|
NSEntityDescription *check = self;
|
|
|
|
for (; check != nil; check = check->_superentity)
|
|
if (check == other)
|
|
return YES;
|
|
|
|
return NO;
|
|
}
|
|
|
|
@end
|