libs-gdl2/EOAccess/EOEntity.m
Sebastian Reitenbach 291ec858bf * EOAccess/EOEntity.m
remove unused variable
        * EOControl/EOEditingContext.m
          use the object, instead of the EOGlobalID to get the entityName
        * EOControl/EOGenericRecord.m
        * EOInterface/EOColumnAssociation.[h|m]
        * EOInterface/EOTableViewAssociation.m
          some NS(U)Integer conversions


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@36677 72102866-910b-0410-8b05-ffd578937521
2013-05-29 13:24:29 +00:00

4406 lines
121 KiB
Objective-C

/**
EOEntity.m <title>EOEntity Class</title>
Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Author: Mirko Viviani <mirko.viviani@gmail.com>
Date: February 2000
Author: Manuel Guesdon <mguesdon@orange-concept.com>
Date: October 2000
$Revision$
$Date$
<abstract></abstract>
This file is part of the GNUstep Database Library.
<license>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 3 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
</license>
**/
#include "config.h"
RCS_ID("$Id$")
#include <ctype.h>
#ifdef GNUSTEP
#include <Foundation/NSString.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSValue.h>
#include <Foundation/NSProcessInfo.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSFormatter.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSException.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSObjCRuntime.h>
#include <Foundation/NSZone.h>
#else
#include <Foundation/Foundation.h>
#include <GNUstepBase/GNUstep.h>
#include <GNUstepBase/GSObjCRuntime.h>
#include <GNUstepBase/NSObject+GNUstepBase.h>
#include <GNUstepBase/NSDebug+GNUstepBase.h>
#endif
#include <EOControl/EOKeyValueCoding.h>
#include <EOControl/EOQualifier.h>
#include <EOControl/EOKeyGlobalID.h>
#include <EOControl/EOEditingContext.h>
#include <EOControl/EONull.h>
#include <EOControl/EOMutableKnownKeyDictionary.h>
#include <EOControl/EONSAddOns.h>
#include <EOControl/EOCheapArray.h>
#include <EOControl/EODebug.h>
#include <EOControl/EOFetchSpecification.h>
#include <EOAccess/EOModel.h>
#include <EOAccess/EOModelGroup.h>
#include <EOAccess/EOEntity.h>
#include <EOAccess/EOAttribute.h>
#include <EOAccess/EORelationship.h>
#include <EOAccess/EOStoredProcedure.h>
#include <EOAccess/EOExpressionArray.h>
#include "EOPrivate.h"
#include "EOEntityPriv.h"
#include "EOAttributePriv.h"
#include "../EOControl/EOPrivate.h"
@interface EOModel (Privat)
- (void)_updateCache;
@end
NSString *EOFetchAllProcedureOperation = @"EOFetchAllProcedureOperation";
NSString *EOFetchWithPrimaryKeyProcedureOperation = @"EOFetchWithPrimaryKeyProcedureOperation";
NSString *EOInsertProcedureOperation = @"EOInsertProcedureOperation";
NSString *EODeleteProcedureOperation = @"EODeleteProcedureOperation";
NSString *EONextPrimaryKeyProcedureOperation = @"EONextPrimaryKeyProcedureOperation";
@implementation EOEntity
+ (void)initialize
{
static BOOL initialized=NO;
if (!initialized)
{
initialized=YES;
GDL2_EOAccessPrivateInit();
};
};
/* Not documented becuase it is not a public method. */
- (id)initWithPropertyList: (NSDictionary*)propertyList
owner: (id)owner
{
[EOObserverCenter suppressObserverNotification];
EOFLOGObjectLevelArgs(@"EOEntity", @"propertyList=%@", propertyList);
NS_DURING
{
if ((self = [self init]) != nil)
{
NSArray *array = nil;
NSDictionary * aDict = nil;
NSString *tmpString = nil;
id tmpObject = nil;
_flags.updating = YES;
/* set this before validation. */
if ([owner isKindOfClass:[EOModel class]])
[self _setModel:owner];
// else _setParent:??
tmpString = [propertyList objectForKey:@"name"];
/*
we dont want it to call _updateCache. So we validate and
set the name directly, as we haven't been added to the model yet,
and this would causes problems.
*/
[[self validateName:tmpString] raise];
ASSIGN(_name, tmpString);
[self setExternalName: [propertyList objectForKey: @"externalName"]];
tmpObject = [propertyList objectForKey: @"externalQuery"];
[self setExternalQuery: tmpObject];
tmpString = [propertyList objectForKey: @"restrictingQualifier"];
EOFLOGObjectLevelArgs(@"EOEntity",@"tmpString=%@",tmpString);
if (tmpString)
{
EOQualifier *restrictingQualifier
= [EOQualifier qualifierWithQualifierFormat: tmpString
arguments:nil];
[self setRestrictingQualifier: restrictingQualifier];
}
tmpString = [propertyList objectForKey: @"mappingQualifier"];
if (tmpString)
{
NSEmitTODO(); //TODO
}
tmpObject = [propertyList objectForKey: @"isReadOnly"];
[self setReadOnly: [tmpObject boolValue]];
tmpObject = [propertyList objectForKey: @"cachesObjects"];
[self setCachesObjects: [tmpObject boolValue]];
tmpObject = [propertyList objectForKey: @"userInfo"];
EOFLOGObjectLevelArgs(@"EOEntity", @"tmpObject=%@", tmpObject);
if (tmpObject)
{
[self setUserInfo: tmpObject];
}
else
{
tmpObject = [propertyList objectForKey: @"userDictionary"];
[self setUserInfo: tmpObject];
}
tmpObject = [propertyList objectForKey: @"internalInfo"];
EOFLOGObjectLevelArgs(@"EOEntity", @"tmpObject=%@ [%@]",
tmpObject, [tmpObject class]);
[self _setInternalInfo: tmpObject];
[self setDocComment:[propertyList objectForKey:@"docComment"]];
[self setClassName: [propertyList objectForKey: @"className"]];
tmpObject = [propertyList objectForKey: @"isAbstractEntity"];
[self setIsAbstractEntity: [tmpObject boolValue]];
tmpString = [propertyList objectForKey: @"isFetchable"];
if (tmpString)
{
NSEmitTODO(); //TODO
}
array = [propertyList objectForKey: @"attributes"];
EOFLOGObjectLevelArgs(@"EOEntity", @"Attributes: %@", array);
if ([array count] > 0)
{
ASSIGN(_attributes, array);
_flags.attributesIsLazy = YES;
}
array = [propertyList objectForKey: @"attributesUsedForLocking"];
EOFLOGObjectLevelArgs(@"EOEntity", @"attributesUsedForLocking: %@",
array);
if ([array count] > 0)
{
ASSIGN(_attributesUsedForLocking, array);
_flags.attributesUsedForLockingIsLazy = YES;
}
array = [propertyList objectForKey: @"primaryKeyAttributes"];
array = [array sortedArrayUsingSelector: @selector(compare:)];
EOFLOGObjectLevelArgs(@"EOEntity", @"primaryKeyAttributes: %@",
array);
if ([array count] > 0)
{
ASSIGN(_primaryKeyAttributes, array);
_flags.primaryKeyAttributesIsLazy = YES;
}
/*
* Assign them to _classProperties, not _classPropertyNames,
* this will be build after
*/
array = [propertyList objectForKey: @"classProperties"];
EOFLOGObjectLevelArgs(@"EOEntity", @"classProperties: %@", array);
if ([array count] > 0)
{
ASSIGN(_classProperties, array);
_flags.classPropertiesIsLazy = YES;
}
array = [propertyList objectForKey: @"relationships"];
EOFLOGObjectLevelArgs(@"EOEntity", @"relationships: %@", array);
if ([array count] > 0)
{
ASSIGN(_relationships, array);
_flags.relationshipsIsLazy = YES;
}
if ((aDict = [propertyList objectForKey: @"storedProcedureNames"]) != nil)
{
NSEnumerator * keyEnumerator = [aDict keyEnumerator];
NSString * curentKey;
ASSIGN(_storedProcedures, [NSMutableDictionary dictionary]);
while ((curentKey = [keyEnumerator nextObject])) {
EOStoredProcedure * storedproc;
if ((storedproc = [_model storedProcedureNamed:[aDict objectForKey:curentKey]]))
{
[_storedProcedures setObject:storedproc
forKey:curentKey];
}
}
}
tmpString = [propertyList objectForKey: @"maxNumberOfInstancesToBatchFetch"];
EOFLOGObjectLevelArgs(@"EOEntity",
@"maxNumberOfInstancesToBatchFetch=%@ [%@]",
tmpString, [tmpString class]);
if (tmpString)
[self setMaxNumberOfInstancesToBatchFetch: [tmpString intValue]];
tmpString=[propertyList objectForKey:@"batchFaultingMaxSize"];
if (tmpString)
{
NSEmitTODO(); //TODO
//[self setBatchFaultingMaxSize: [tmpString intValue]];
}
tmpObject
= [propertyList objectForKey: @"fetchSpecificationDictionary"];
EOFLOGObjectLevelArgs(@"EOEntity",
@"fetchSpecificationDictionary=%@ [%@]",
tmpObject, [tmpObject class]);
if (tmpObject)
{
tmpObject = AUTORELEASE([tmpObject mutableCopy]);
ASSIGN(_fetchSpecificationDictionary, tmpObject);
}
else
{
_fetchSpecificationDictionary = [NSMutableDictionary new];
EOFLOGObjectLevelArgs(@"EOEntity",
@"Entity %@ - _fetchSpecificationDictionary %p [RC=%d]:%@",
[self name],
_fetchSpecificationDictionary,
[_fetchSpecificationDictionary retainCount],
_fetchSpecificationDictionary);
}
// load entity's FetchSpecifications
{
NSDictionary *plist = nil;
NSString* fileName;
NSString* path;
fileName = [NSString stringWithFormat: @"%@.fspec", _name];
path = [(EOModel *)owner path];
path = [path stringByAppendingPathComponent: fileName];
if ([[NSFileManager defaultManager] fileExistsAtPath: path])
plist
= [[NSString stringWithContentsOfFile: path] propertyList];
if (plist)
{
EOKeyValueUnarchiver *unarchiver;
NSDictionary *variables;
NSEnumerator *variablesEnum;
id fetchSpecName;
unarchiver
= AUTORELEASE([[EOKeyValueUnarchiver alloc]
initWithDictionary:
[NSDictionary dictionaryWithObject: plist
forKey: @"fspecs"]]);
variables = [unarchiver decodeObjectForKey: @"fspecs"];
[unarchiver finishInitializationOfObjects];
[unarchiver awakeObjects];
variablesEnum = [variables keyEnumerator];
while ((fetchSpecName = [variablesEnum nextObject]))
{
id fetchSpec = [variables objectForKey: fetchSpecName];
[self addFetchSpecification: fetchSpec
withName: fetchSpecName];
}
}
}
_flags.updating = NO;
}
}
NS_HANDLER
{
[EOObserverCenter enableObserverNotification];
NSLog(@"exception in EOEntity initWithPropertyList:owner:");
NSLog(@"exception=%@", localException);
NSLog(@"exception=%@", localException);
[localException raise];
}
NS_ENDHANDLER;
[EOObserverCenter enableObserverNotification];
return self;
}
- (void)awakeWithPropertyList: (NSDictionary *)propertyList
{
NSString *tmp;
if ((tmp = [propertyList objectForKey:@"parent"]))
{
EOEntity *parent = [_model entityNamed:tmp];
/* TODO tests for parents spanning models. */
if (!parent)
parent = [[_model modelGroup] entityNamed:tmp];
[parent addSubEntity:self];
}
}
- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList
{
int i, count;
if (_name)
[propertyList setObject: _name
forKey: @"name"];
if (_className)
[propertyList setObject: _className
forKey: @"className"];
if (_externalName)
[propertyList setObject: _externalName
forKey: @"externalName"];
if (_externalQuery)
[propertyList setObject: _externalQuery
forKey: @"externalQuery"];
if (_userInfo)
[propertyList setObject: _userInfo
forKey: @"userInfo"];
if (_docComment)
[propertyList setObject: _docComment
forKey: @"docComment"];
if (_batchCount)
[propertyList setObject: [NSString stringWithFormat:@"%d", _batchCount]
forKey: @"maxNumberOfInstancesToBatchFetch"];
if (_flags.cachesObjects)
[propertyList setObject: @"Y"
forKey: @"cachesObjects"];
if (_flags.isAbstractEntity)
[propertyList setObject: @"Y"
forKey: @"isAbstractEntity"];
if (_parent)
[propertyList setObject: [_parent name]
forKey: @"parent"];
if ((count = [_attributes count]))
{
if (_flags.attributesIsLazy)
[propertyList setObject: _attributes
forKey: @"attributes"];
else
{
NSMutableArray *attributesPList = [NSMutableArray array];
for (i = 0; i < count; i++)
{
NSMutableDictionary *attributePList = [NSMutableDictionary
dictionary];
[[_attributes objectAtIndex: i]
encodeIntoPropertyList: attributePList];
[attributesPList addObject: attributePList];
}
[propertyList setObject: attributesPList
forKey: @"attributes"];
}
}
if ((count = [_attributesUsedForLocking count]))
{
if (_flags.attributesUsedForLockingIsLazy)
[propertyList setObject: _attributesUsedForLocking
forKey: @"attributesUsedForLocking"];
else
{
NSMutableArray *attributesUsedForLockingPList = [NSMutableArray
array];
for (i = 0; i < count; i++)
{
NSString *attributePList
= [(EOAttribute *)[_attributesUsedForLocking objectAtIndex: i]
name];
[attributesUsedForLockingPList addObject: attributePList];
}
[propertyList setObject: attributesUsedForLockingPList
forKey: @"attributesUsedForLocking"];
}
}
if ((count = [_classProperties count]))
{
if (_flags.classPropertiesIsLazy)
[propertyList setObject: _classProperties
forKey: @"classProperties"];
else
{
NSMutableArray *classPropertiesPList = [NSMutableArray array];
for (i = 0; i < count; i++)
{
NSString *classPropertyPList
= [(EOAttribute *)[_classProperties objectAtIndex: i]
name];
[classPropertiesPList addObject: classPropertyPList];
}
[propertyList setObject: classPropertiesPList
forKey: @"classProperties"];
}
}
if ((count = [_primaryKeyAttributes count]))
{
if (_flags.primaryKeyAttributesIsLazy)
[propertyList setObject: _primaryKeyAttributes
forKey: @"primaryKeyAttributes"];
else
{
NSMutableArray *primaryKeyAttributesPList = [NSMutableArray array];
for (i = 0; i < count; i++)
{
NSString *attributePList= [(EOAttribute *)[_primaryKeyAttributes
objectAtIndex: i]
name];
[primaryKeyAttributesPList addObject: attributePList];
}
[propertyList setObject: primaryKeyAttributesPList
forKey: @"primaryKeyAttributes"];
}
}
{
NSArray *relsPlist = [self relationshipsPlist];
if (relsPlist)
{
[propertyList setObject: relsPlist
forKey: @"relationships"];
}
}
// stored procedures
//
// storedProcedureNames = {EOInsertProcedure = fooproc; };
if ((_storedProcedures != nil) && ([_storedProcedures count]))
{
NSString *currentKey = nil;
NSEnumerator *keyEnumerator = [[[_storedProcedures allKeys]
sortedArrayUsingSelector:@selector(compare:)] objectEnumerator];
NSMutableDictionary * newDict = [NSMutableDictionary dictionary];
while ((currentKey = [keyEnumerator nextObject])) {
[newDict setObject:[[_storedProcedures objectForKey:currentKey] name]
forKey:currentKey];
}
[propertyList setObject: newDict
forKey: @"storedProcedureNames"];
}
}
- (id) init
{
//OK
if ((self = [super init]))
{
_attributes = [NSMutableArray new];
_subEntities = [NSMutableArray new];
_relationships = [NSMutableArray new];
}
return self;
}
static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL selector, id arg, Class class)
{
int i, c;
arr = [arr copy];
for (i = 0, c = [arr count]; i < c; i++)
{
id obj = [arr objectAtIndex:i];
if ([obj isKindOfClass:class])
{
[obj performSelector:selector withObject:arg];
}
}
RELEASE(arr);
}
- (void) dealloc
{
/* these classes may contain NSDictionaries as well as entities, attributes and relationships
in the case of delayed instantiation */
performSelectorOnArrayWithEachObjectOfClass(_subEntities, @selector(_setParentEntity:),
nil, [EOEntity class]);
performSelectorOnArrayWithEachObjectOfClass(_attributes, @selector(setParent:),
nil, [EOAttribute class]);
performSelectorOnArrayWithEachObjectOfClass(_relationships, @selector(setEntity:),
nil, [EORelationship class]);
if (_classDescription) [[EOClassDescription class] invalidateClassDescriptionCache];
DESTROY(_adaptorDictionaryInitializer);
DESTROY(_instanceDictionaryInitializer);
DESTROY(_primaryKeyDictionaryInitializer);
DESTROY(_propertyDictionaryInitializer);
DESTROY(_snapshotDictionaryInitializer);
DESTROY(_attributes);
DESTROY(_attributesByName);
DESTROY(_attributesToFetch);
DESTROY(_attributesToSave);
DESTROY(_attributesUsedForLocking);
DESTROY(_classDescription);
DESTROY(_classForInstances);
DESTROY(_className);
DESTROY(_classProperties);
DESTROY(_classPropertyAttributeNames);
DESTROY(_classPropertyNames);
DESTROY(_classPropertyToManyRelationshipNames);
DESTROY(_classPropertyToOneRelationshipNames);
DESTROY(_dbSnapshotKeys);
DESTROY(_docComment);
DESTROY(_externalName);
DESTROY(_externalQuery);
DESTROY(_fetchSpecificationDictionary);
DESTROY(_fetchSpecificationNames);
DESTROY(_hiddenRelationships);
DESTROY(_internalInfo);
DESTROY(_name);
DESTROY(_primaryKeyAttributes);
DESTROY(_primaryKeyAttributeNames);
DESTROY(_propertiesToFault); // never initialized?
DESTROY(_restrictingQualifier);
DESTROY(_relationships);
DESTROY(_relationshipsByName);
DESTROY(_storedProcedures); // never initialized?
DESTROY(_snapshotToAdaptorRowSubsetMapping);
DESTROY(_subEntities);
DESTROY(_userInfo);
[super dealloc];
}
- (NSString *)description
{
NSMutableDictionary *plist;
plist = [NSMutableDictionary dictionaryWithCapacity: 4];
[self encodeIntoPropertyList: plist];
return [plist description];
}
- (NSString *)debugDescription
{
NSString *dscr = nil;
dscr = [NSString stringWithFormat: @"<%s %p - name=%@ className=%@ externalName=%@ externalQuery=%@",
object_getClassName(self),
(void*)self,
_name,
_className,
_externalName,
_externalQuery];
dscr = [dscr stringByAppendingFormat:@" userInfo=%@",
_userInfo];
dscr = [dscr stringByAppendingFormat:@" primaryKeyAttributeNames=%@ classPropertyNames=%@>",
[self primaryKeyAttributeNames],
[self classPropertyNames]];
NSAssert4(!_attributesToFetch
|| [_attributesToFetch isKindOfClass:[NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@",
[self name],
_attributesToFetch,
[_attributesToFetch class],
_attributesToFetch);
return dscr;
}
/*----------------------------------------*/
- (NSString *)name
{
return _name;
}
- (EOModel *)model
{
return _model;
}
- (NSString *)externalName
{
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %p (%@): external name=%@",
self, [self name], _externalName);
return _externalName;
}
- (NSString *)externalQuery
{
return _externalQuery;
}
- (EOQualifier *)restrictingQualifier
{
return _restrictingQualifier;
}
- (BOOL)isReadOnly
{
return _flags.isReadOnly;
}
- (BOOL)cachesObjects
{
return _flags.cachesObjects;
}
- (NSString *)className
{
return _className;
}
- (NSDictionary *)userInfo
{
return _userInfo;
}
- (NSArray *)attributes
{
if (_flags.attributesIsLazy)
{
int count = 0;
EOFLOGObjectLevelArgs(@"EOEntity",
@"START construct attributes on %p", self);
count = [_attributes count];
EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@: Lazy _attributes=%@",
[self name],
_attributes);
if (count > 0)
{
int i = 0;
NSArray *attributePLists = AUTORELEASE(RETAIN(_attributes));
DESTROY(_attributes);
DESTROY(_attributesByName);
_attributes = [NSMutableArray new];
_attributesByName = [NSMutableDictionary new];
/* if we've already loaded relationships rebuild the name cache */
if (!_flags.relationshipsIsLazy && _relationshipsByName == nil)
[self relationshipsByName];
_flags.attributesIsLazy = NO;
[EOObserverCenter suppressObserverNotification];
_flags.updating = YES;
NS_DURING
{
NSArray *attrNames = nil;
for (i = 0; i < count; i++)
{
id attrPList = [attributePLists objectAtIndex: i];
EOAttribute *attribute = nil;
NSString *attributeName = nil;
// this should validate name against its owner via setName:
attribute = [EOAttribute attributeWithPropertyList: attrPList
owner: self];
attributeName = [attribute name];
// don't call -addAttribute: because it wipes our name cache
[_attributes addObject: attribute];
[_attributesByName setObject: attribute
forKey: attributeName];
}
attrNames = [_attributes resultsOfPerformingSelector:
@selector(name)];
count = [attrNames count];
NSAssert(count == [attributePLists count],
@"Error during attribute creations");
{
int pass = 0;
//We'll first awake non derived/flattened attributes
for (pass = 0; pass < 2; pass++)
{
for (i = 0; i < count; i++)
{
NSString *attrName = [attrNames objectAtIndex: i];
NSDictionary *attrPList = nil;
EOAttribute *attribute = nil;
id definition = nil;
EOFLOGObjectLevelArgs(@"EOEntity", @"XXX attrName=%@",
attrName);
attrPList = [attributePLists objectAtIndex: i];
definition = [attrPList objectForKey: @"definition"];
if ((pass == 0 && definition == nil)
|| (pass == 1 && definition != nil))
{
attribute = [self attributeNamed: attrName];
EOFLOGObjectLevelArgs(@"EOEntity",
@"XXX 2A ATTRIBUTE: self=%p AWAKE attribute=%@",
self, attribute);
[attribute awakeWithPropertyList: attrPList];
EOFLOGObjectLevelArgs(@"EOEntity",
@"XXX 2B ATTRIBUTE: self=%p attribute=%@",
self, attribute);
}
}
}
}
}
NS_HANDLER
{
_flags.updating = NO;
[EOObserverCenter enableObserverNotification];
[localException raise];
}
NS_ENDHANDLER;
_flags.updating = NO;
[EOObserverCenter enableObserverNotification];
[_attributes sortUsingSelector: @selector(eoCompareOnName:)];//Very important to have always the same order.
}
else
_flags.attributesIsLazy = NO;
EOFLOGObjectLevelArgs(@"EOEntity", @"STOP construct attributes on %p",
self);
}
return _attributes;
}
- (EOAttribute *)attributeNamed: (NSString *)attributeName
{
//OK
EOAttribute *attribute = nil;
NSDictionary *attributesByName = nil;
attributesByName = [self attributesByName];
EOFLOGObjectLevelArgs(@"EOEntity", @"attributesByName [%p] (%@)",
attributesByName,
[attributesByName class]);
NSAssert2((!attributesByName
|| [attributesByName isKindOfClass: [NSDictionary class]]),
@"attributesByName is not a NSDictionary but a %@. attributesByName [%p]",
[attributesByName class],
attributesByName);
// EOFLOGObjectLevelArgs(@"EOEntity",@"attributesByName=%@",attributesByName);
attribute = [attributesByName objectForKey: attributeName];
return attribute;
}
/** returns attribute named attributeName (no relationship) **/
- (EOAttribute *)anyAttributeNamed: (NSString *)attributeName
{
EOAttribute *attr;
NSEnumerator *attrEnum;
attr = [self attributeNamed:attributeName];
//VERIFY
/* I suppose this is intended to find the 'hidden' attributes mentioned in
* the documentation of this method, but if these are in -primaryKeyAttributes
* they don't appear to be well hidden, and _primaryKeyAttributes is filled
* by calling -attributeNamed: and doesn't appear to be modified outside
* -primaryKeyAttributes:, so this check appears to be redundant to the one
* above.
*/
if (!attr)
{
IMP enumNO=NULL;
attrEnum = [[self primaryKeyAttributes] objectEnumerator];
while ((attr = GDL2_NextObjectWithImpPtr(attrEnum,&enumNO)))
{
if ([[attr name] isEqual: attributeName])
return attr;
}
}
return attr;
}
- (NSArray *)relationships
{
//OK
if (_flags.relationshipsIsLazy)
{
int count = 0;
EOFLOGObjectLevelArgs(@"EOEntity", @"START construct relationships on %p",
self);
count = [_relationships count];
EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _relationships=%@",
_relationships);
if (count > 0)
{
int i = 0;
NSArray *relationshipPLists = _relationships;
DESTROY(_relationshipsByName);
_relationships = [NSMutableArray new];
_relationshipsByName = [NSMutableDictionary new];
if (!_flags.attributesIsLazy && _attributesByName == nil)
[self attributesByName];
_flags.relationshipsIsLazy = NO;
[EOObserverCenter suppressObserverNotification];
_flags.updating = YES;
NS_DURING
{
NSArray *relNames = nil;
for (i = 0; i < count; i++)
{
id attrPList = [relationshipPLists
objectAtIndex: i];
EORelationship *relationship = nil;
NSString *relationshipName = nil;
/* this should cause validation to occur. */
relationship= [EORelationship
relationshipWithPropertyList: attrPList
owner: self];
relationshipName = [relationship name];
[_relationships addObject: relationship];
[_relationshipsByName setObject: relationship
forKey: relationshipName];
}
EOFLOGObjectLevel(@"EOEntity", @"Rels added");
relNames = [_relationships
resultsOfPerformingSelector: @selector(name)];
EOFLOGObjectLevelArgs(@"EOEntity", @"relNames=%@", relNames);
count = [relNames count];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p rel count=%d",
self, count);
NSAssert(count == [relationshipPLists count],
@"Error during attribute creations");
{
int pass = 0;
//We'll first awake non flattened relationships
for (pass = 0; pass < 2; pass++)
{
for (i = 0; i < count; i++)
{
NSDictionary *relPList = [relationshipPLists
objectAtIndex: i];
if ([relPList isKindOfClass: [EORelationship class]])
continue;
{
NSString *relName = [relNames objectAtIndex: i];
EORelationship *relationship;
relationship = [self relationshipNamed: relName];
EOFLOGObjectLevelArgs(@"EOEntity", @"relName=%@",
relName);
if ((pass == 0
&& ![relPList objectForKey: @"definition"])
|| (pass == 1
&& [relPList objectForKey: @"definition"]))
{
EOFLOGObjectLevelArgs(@"EOEntity", @"XXX REL: self=%p AWAKE relationship=%@",
self, relationship);
[relationship awakeWithPropertyList: relPList];
}
}
}
}
}
}
NS_HANDLER
{
EOFLOGObjectLevelArgs(@"EOEntity", @"localException=%@",
localException);
DESTROY(relationshipPLists);
_flags.updating = NO;
[EOObserverCenter enableObserverNotification];
[localException raise];
}
NS_ENDHANDLER;
DESTROY(relationshipPLists);
_flags.updating = NO;
[EOObserverCenter enableObserverNotification];
}
else
_flags.relationshipsIsLazy = NO;
EOFLOGObjectLevelArgs(@"EOEntity", @"STOP construct relationships on %p",
self);
}
return _relationships;
}
- (EORelationship *)relationshipNamed: (NSString *)relationshipName
{
//OK
return [[self relationshipsByName] objectForKey: relationshipName];
}
- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipName
{
EORelationship *rel;
NSEnumerator *relEnum = nil;
rel = [self relationshipNamed: relationshipName];
//VERIFY
if (!rel)
{
EORelationship *tmpRel = nil;
IMP enumNO=NULL;
relEnum = [_hiddenRelationships objectEnumerator];
while (!rel && (tmpRel = GDL2_NextObjectWithImpPtr(relEnum,&enumNO)))
{
if ([[tmpRel name] isEqual: relationshipName])
rel = tmpRel;
}
}
return rel;
}
- (NSArray *)classProperties
{
if (_flags.classPropertiesIsLazy)
{
int count = [_classProperties count];
if (count > 0)
{
NSArray *classPropertiesList = _classProperties;
int i;
_classProperties = [NSMutableArray new];
_flags.classPropertiesIsLazy = NO;
for (i = 0; i < count; i++)
{
#if 0
NSString *classPropertyName = [classPropertiesList
objectAtIndex: i];
#else
id classPropertyName = (
[[classPropertiesList objectAtIndex:i] isKindOfClass:[NSString class]] ?
[classPropertiesList objectAtIndex:i] :
[(EOEntity *)[classPropertiesList objectAtIndex: i] name]);
#endif
id classProperty = [self attributeNamed: classPropertyName];
if (!classProperty)
classProperty = [self relationshipNamed: classPropertyName];
NSAssert4(classProperty,
@"No attribute or relationship named '%@' (property at index %d) to use as classProperty in entity name '%@' : %@",
classPropertyName,
i+1,
[self name],
self);
if ([self isValidClassProperty: classProperty])
[_classProperties addObject: classProperty];
else
{
//TODO
NSAssert2(NO, @"not valid class prop %@ in %@",
classProperty, [self name]);
}
}
DESTROY(classPropertiesList);
[_classProperties sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order.
[self _setIsEdited]; //To Clean Buffers
}
else
_flags.classPropertiesIsLazy = NO;
}
return _classProperties;
}
- (NSArray *)classPropertyNames
{
//OK
if (!_classPropertyNames)
{
NSArray *classProperties = [self classProperties];
NSAssert2(!classProperties
|| [classProperties isKindOfClass: [NSArray class]],
@"classProperties is not an NSArray but a %@\n%@",
[classProperties class],
classProperties);
ASSIGN(_classPropertyNames,
[classProperties resultsOfPerformingSelector: @selector(name)]);
}
NSAssert4(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@",
[self name],
_attributesToFetch,
[_attributesToFetch class],
_attributesToFetch);
return _classPropertyNames;
}
- (NSArray *)fetchSpecificationNames
{
return _fetchSpecificationNames;
}
- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)fetchSpecName
{
return [_fetchSpecificationDictionary objectForKey: fetchSpecName];
}
- (NSArray *)sharedObjectFetchSpecificationNames
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];
return nil;
}
- (NSArray*)primaryKeyAttributes
{
//OK
if (_flags.primaryKeyAttributesIsLazy)
{
int count = [_primaryKeyAttributes count];
EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _primaryKeyAttributes=%@",
_primaryKeyAttributes);
if (count > 0)
{
int i = 0;
NSArray *primaryKeyAttributes = _primaryKeyAttributes;
_primaryKeyAttributes = [NSMutableArray new];
_flags.primaryKeyAttributesIsLazy = NO;
for (i = 0; i < count; i++)
{
NSString *attributeName = [primaryKeyAttributes objectAtIndex: i];
EOAttribute *attribute = [self attributeNamed: attributeName];
NSAssert3(attribute, @"In entity %@: No attribute named %@ "
@"to use for locking (attributes: %@)", [self name],
attributeName, [[self attributes]
resultsOfPerformingSelector: @selector(name)]);
if ([self isValidPrimaryKeyAttribute: attribute])
[_primaryKeyAttributes addObject: attribute];
else
{
NSAssert2(NO, @"not valid pk attribute %@ in %@",
attribute, [self name]);
}
}
DESTROY(primaryKeyAttributes);
[_primaryKeyAttributes sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order.
[self _setIsEdited]; //To Clean Buffers
}
else
_flags.primaryKeyAttributesIsLazy = NO;
}
return _primaryKeyAttributes;
}
- (NSArray *)primaryKeyAttributeNames
{
//OK
if (!_primaryKeyAttributeNames)
{
NSArray *primaryKeyAttributes = [self primaryKeyAttributes];
NSArray *primaryKeyAttributeNames = [primaryKeyAttributes
resultsOfPerformingSelector:
@selector(name)];
primaryKeyAttributeNames = [primaryKeyAttributeNames sortedArrayUsingSelector: @selector(compare:)]; //Not necessary: they are already sorted
ASSIGN(_primaryKeyAttributeNames, primaryKeyAttributeNames);
}
return _primaryKeyAttributeNames;
}
- (NSArray *)attributesUsedForLocking
{
if (_flags.attributesUsedForLockingIsLazy)
{
int count = [_attributesUsedForLocking count];
if (count > 0)
{
int i = 0;
NSArray *attributesUsedForLocking = _attributesUsedForLocking;
_attributesUsedForLocking = [NSMutableArray new];
_flags.attributesUsedForLockingIsLazy = NO;
for (i = 0; i < count; i++)
{
NSString *attributeName = [attributesUsedForLocking
objectAtIndex: i];
EOAttribute *attribute = [self attributeNamed: attributeName];
if (attribute)
{
[_attributesUsedForLocking addObject: attribute];
}
}
DESTROY(attributesUsedForLocking);
[self _setIsEdited]; //To Clean Buffers
}
else
_flags.attributesUsedForLockingIsLazy = NO;
}
return _attributesUsedForLocking;
}
- (NSArray *)attributesToFetch
{
//OK
NSAssert3(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@",
[self name],
_attributesToFetch,
[_attributesToFetch class]);
return [self _attributesToFetch];
}
- (EOQualifier *)qualifierForPrimaryKey: (NSDictionary *)row
{
//OK
EOQualifier *qualifier = nil;
NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames];
int count = [primaryKeyAttributeNames count];
if (count == 1)
{
//OK
NSString *key = [primaryKeyAttributeNames objectAtIndex: 0];
id value = [row objectForKey: key];
qualifier = [EOKeyValueQualifier qualifierWithKey: key
operatorSelector:
EOQualifierOperatorEqual
value: value];
}
else
{
//Seems OK
NSMutableArray *array
= AUTORELEASE([GDL2_alloc(NSMutableArray) initWithCapacity: count]);
IMP pkanOAI=NULL;
IMP rowOFK=NULL;
IMP arrayAO=NULL;
int i;
for (i = 0; i < count; i++)
{
NSString *key = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,&pkanOAI,i);
id value = GDL2_ObjectForKeyWithImpPtr(row,&rowOFK,key);
GDL2_AddObjectWithImpPtr(array,&arrayAO,
[EOKeyValueQualifier qualifierWithKey: key
operatorSelector:
EOQualifierOperatorEqual
value: value]);
}
qualifier = [EOAndQualifier qualifierWithQualifierArray: array];
}
return qualifier;
}
- (BOOL)isQualifierForPrimaryKey: (EOQualifier *)qualifier
{
int count = [[self primaryKeyAttributeNames] count];
if (count == 1)
{
if ([qualifier isKindOfClass: [EOKeyValueQualifier class]] == YES)
return YES;
else
return NO;
}
else
{
}
//TODO
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
return NO;
}
- (NSDictionary *)primaryKeyForRow: (NSDictionary *)row
{
NSMutableDictionary *dict = nil;
int i, count;
NSArray *primaryKeyAttributes = [self primaryKeyAttributes];
IMP pkaOAI=NULL;
IMP rowOFK=NULL;
IMP dictSOFK=NULL;
count = [primaryKeyAttributes count];
dict = [NSMutableDictionary dictionaryWithCapacity: count];
for (i = 0; i < count; i++)
{
EOAttribute *attr = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributes,&pkaOAI,i);
NSString* attrName = [attr name];
id value = GDL2_ObjectForKeyWithImpPtr(row,&rowOFK,attrName);
if (!value)
value = GDL2_EONull;
GDL2_SetObjectForKeyWithImpPtr(dict,&dictSOFK,value,attrName);
}
return dict;
}
- (BOOL)isValidAttributeUsedForLocking: (EOAttribute *)attribute
{
if (!([attribute isKindOfClass: GDL2_EOAttributeClass]
&& ([self attributeNamed: [attribute name]] == attribute)))
return NO;
if ([attribute isDerived])
return NO;
return YES;
}
- (BOOL)isValidPrimaryKeyAttribute: (EOAttribute *)attribute
{
if (!([attribute isKindOfClass: GDL2_EOAttributeClass]
&& ([self attributeNamed: [attribute name]] == attribute)))
return NO;
if ([attribute isDerived])
return NO;
return YES;
}
- (BOOL)isPrimaryKeyValidInObject: (id)object
{
NSArray *primaryKeyAttributeNames = nil;
NSString *key = nil;
id value = nil;
NSUInteger i, count;
IMP pkanOAI=NULL;
IMP objectVFK=NULL;
primaryKeyAttributeNames = [self primaryKeyAttributeNames];
count = [primaryKeyAttributeNames count];
for (i = 0; i < count; i++)
{
key = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,&pkanOAI,i);
value = GDL2_ValueForKeyWithImpPtr(object,&objectVFK,key);
// a 0 is NOT a valid PK value! -- dw
if ((_isNilOrEONull(value)) || (([value isKindOfClass:[NSNumber class]]) &&
([value intValue] == 0))) {
return NO;
}
}
return YES;
}
- (BOOL)isValidClassProperty: (id)property
{
id thePropertyName;
if (!([property isKindOfClass: GDL2_EOAttributeClass]
|| [property isKindOfClass: [EORelationship class]]))
return NO;
thePropertyName = [(EOAttribute *)property name];
if ([[self attributesByName] objectForKey: thePropertyName] == property
|| [[self relationshipsByName] objectForKey: thePropertyName] == property)
return YES;
return NO;
}
- (NSArray *)subEntities
{
return _subEntities;
}
- (EOEntity *)parentEntity
{
return _parent;
}
- (BOOL)isAbstractEntity
{
return _flags.isAbstractEntity;
}
- (unsigned int)maxNumberOfInstancesToBatchFetch
{
return _batchCount;
}
- (EOGlobalID *)globalIDForRow: (NSDictionary *)row
{
EOGlobalID *gid = [self globalIDForRow: row
isFinal: NO];
NSAssert(gid, @"No gid");
//TODO
/*
pas toutjur: la suite editingc objectForGlobalID:
EODatabaseContext snapshotForGlobalID:
if no snpashot:
{
database recordSnapshot:forGlobalID:
self classDescriptionForInstances
createInstanceWithEditingContext:globalID:zone:
}
*/
return gid;
}
- (NSDictionary *)primaryKeyForGlobalID: (EOKeyGlobalID *)gid
{
//OK
NSMutableDictionary *dictionaryForPrimaryKey = nil;
if ([gid isKindOfClass: [EOKeyGlobalID class]]) //if ([gid isFinal])//?? or class test ??//TODO
{
NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames];
int count = [primaryKeyAttributeNames count];
if (count > 0)
{
int i;
id *gidkeyValues = [gid keyValues];
if (gidkeyValues)
{
IMP pkanOAI=NULL;
IMP dfpkSOFK=NULL;
dictionaryForPrimaryKey = [self _dictionaryForPrimaryKey];
NSAssert1(dictionaryForPrimaryKey,
@"No dictionaryForPrimaryKey in entity %@",
[self name]);
for (i = 0; i < count; i++)
{
id key = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,&pkanOAI,i);
GDL2_SetObjectForKeyWithImpPtr(dictionaryForPrimaryKey,&dfpkSOFK,
gidkeyValues[i],key);
}
}
}
}
else
{
NSDebugLog(@"EOEntity (%@): primaryKey is *nil* for globalID = %@",
_name, gid);
}
return dictionaryForPrimaryKey;
}
@end
@implementation EOEntity (EOEntityEditing)
- (void)setName: (NSString *)name
{
NSInteger fCount = -1;
NSInteger i;
EOModel * oldModel = nil;
if (name && [name isEqual: _name]) return;
[[self validateName: name] raise];
[self willChange];
RETAIN(self);
ASSIGN(oldModel,_model);
// We have to make sure all references are loaded before we change the name
// if somebody finds a better solution, please tell me -- dw
[_model referencesToProperty:self];
[_model removeEntity:self];
// update the fetch specifications
if (_fetchSpecificationNames)
{
fCount = [_fetchSpecificationNames count];
}
for (i = 0; i < fCount; i++)
{
EOFetchSpecification * fetchSpec = [self fetchSpecificationNamed:[_fetchSpecificationNames objectAtIndex:i]];
[fetchSpec setEntityName:name];
}
ASSIGNCOPY(_name, name);
[oldModel addEntity:self];
RELEASE(oldModel);
RELEASE(self);
[self _setIsEdited];
// this destroys everything. -- dw
//[_model _updateCache];
}
- (void)setExternalName: (NSString *)name
{
//OK
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %p (%@): external name=%@",
self, [self name], name);
[self willChange];
ASSIGNCOPY(_externalName,name);
[self _setIsEdited];
}
- (void)setExternalQuery: (NSString *)query
{
//OK
[self willChange];
ASSIGNCOPY(_externalQuery, query);
[self _setIsEdited];
}
- (void)setRestrictingQualifier: (EOQualifier *)qualifier
{
[self willChange];
ASSIGN(_restrictingQualifier, qualifier);
}
- (void)setReadOnly: (BOOL)flag
{
//OK
[self willChange];
_flags.isReadOnly = flag;
}
- (void)setCachesObjects: (BOOL)flag
{
//OK
[self willChange];
_flags.cachesObjects = flag;
}
- (void)addAttribute: (EOAttribute *)attribute
{
NSString *attributeName = [attribute name];
NSAssert2([[self attributesByName] objectForKey: attributeName] == nil,
@"'%@': attribute '%@' already used in the entity",
[self name],
attributeName);
NSAssert2([[self relationshipsByName] objectForKey: attributeName] == nil,
@"'%@': attribute '%@' already used in entity as relationship",
[self name],
attributeName);
NSAssert4([attribute parent] == nil,
@"'%@': attribute '%@' already owned by '%@' '%@'",
[self name],
attributeName,
NSStringFromClass([[attribute parent] class]),
[(EOEntity *)[attribute parent] name]);
[self willChange];
[_attributes addObject: attribute];
[self _setIsEdited]; //To clean caches
[attribute setParent: self];
}
/**
* Removes the attribute from the -attributes array, and the
* -classProperties, and -primaryKeyAttributes arrays if they contain it.
* does not remove any references to the attribute from other properties.
* the caller should insure that no such references exist by calling
* -referencesProperty: or [EOModel -referencesToProperty:].
*/
- (void) removeAttribute: (EOAttribute *)attribute
{
if (attribute)
{
[self willChange];
// make sure everything is initialized
[self attributes];
[self classProperties];
[self attributesUsedForLocking];
[self primaryKeyAttributes];
[_attributesByName removeObjectForKey:[attribute name]];
[_classProperties removeObject: attribute];
[_attributesUsedForLocking removeObject: attribute];
[_primaryKeyAttributes removeObject:attribute];
[attribute setParent: nil];
[_attributes removeObject: attribute];
[self _setIsEdited];//To clean caches
}
}
- (void)addRelationship: (EORelationship *)relationship
{
NSString *relationshipName = [relationship name];
if ([[self attributesByName] objectForKey: relationshipName])
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: \"%@\" already used in the model as attribute",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
relationshipName];
if ([[self relationshipsByName] objectForKey: relationshipName])
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: \"%@\" already used in the model",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
relationshipName];
[self willChange];
[_relationships addObject: relationship];
if (_relationshipsByName == nil)
{
_relationshipsByName = [NSMutableDictionary new];
}
[_relationshipsByName setObject: relationship forKey: relationshipName];
[relationship setEntity: self];
[self _setIsEdited];//To clean caches
}
/**
* Removes the relationship from the -relationships array and
* the -classProperties array if it contains the relationship.
* The caller should insure that no references to the
* relationship exist by calling -referencesProperty: or
* [EOModel -referencesToProperty].
*/
- (void)removeRelationship: (EORelationship *)relationship
{
if (relationship)
{
[self willChange];
[self relationships];
[self classProperties];
[_relationshipsByName removeObjectForKey:[relationship name]];
[_classProperties removeObject: relationship];
[_relationships removeObject: relationship];
/* We call this after adjusting the arrays so that setEntity: has
the opportunity to check the relationships before calling
removeRelationshipt which would lead to an infinite loop. */
[relationship setEntity:nil];
[self _setIsEdited];//To clean caches
}
}
- (void)addFetchSpecification: (EOFetchSpecification *)fetchSpec
withName: (NSString *)name
{
if (_fetchSpecificationDictionary == nil)
{
_fetchSpecificationDictionary = [NSMutableDictionary new];
}
[self willChange];
[_fetchSpecificationDictionary setObject: fetchSpec forKey: name];
ASSIGN(_fetchSpecificationNames, [[_fetchSpecificationDictionary allKeys]
sortedArrayUsingSelector:
@selector(compare:)]);
}
- (void)removeFetchSpecificationNamed: (NSString *)name
{
[self willChange];
[_fetchSpecificationDictionary removeObjectForKey:name];
ASSIGN(_fetchSpecificationNames, [[_fetchSpecificationDictionary allKeys]
sortedArrayUsingSelector:
@selector(compare:)]);
}
- (void)setSharedObjectFetchSpecificationsByName: (NSArray *)names
{
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
}
- (void)addSharedObjectFetchSpecificationByName: (NSString *)name
{
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
}
- (void)removeSharedObjectFetchSpecificationByName: (NSString *)name
{
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
}
- (void)setClassName:(NSString *)name
{
//OK
[self willChange];
if (!name)
{
NSLog(@"Entity %@ has no class name. Use EOGenericRecord", [self name]);
name = @"EOGenericRecord";
}
ASSIGNCOPY(_className, name);
[self _setIsEdited];
}
- (void)setUserInfo: (NSDictionary *)dictionary
{
//OK
[self willChange];
ASSIGN(_userInfo, dictionary);
[self _setIsEdited];
}
- (BOOL)setClassProperties: (NSArray *)properties
{
int i, count = [properties count];
for (i = 0; i < count; i++)
if (![self isValidClassProperty: [properties objectAtIndex:i]])
return NO;
[self willChange];
DESTROY(_classProperties);
_classProperties = [[NSMutableArray alloc] initWithArray: properties]; //TODO
[self _setIsEdited]; //To clean cache
return YES;
}
- (BOOL)setPrimaryKeyAttributes: (NSArray *)keys
{
int i, count = [keys count];
for (i = 0; i < count; i++)
if (![self isValidPrimaryKeyAttribute: [keys objectAtIndex:i]])
return NO;
[self willChange];
DESTROY(_primaryKeyAttributes);
_primaryKeyAttributes = [[NSMutableArray alloc] initWithArray: keys]; // TODO
[self _setIsEdited];//To clean cache
return YES;
}
- (BOOL) setAttributesUsedForLocking: (NSArray *)attributes
{
int i, count = [attributes count];
for (i = 0; i < count; i++)
if (![self isValidAttributeUsedForLocking: [attributes objectAtIndex: i]])
return NO;
[self willChange];
DESTROY(_attributesUsedForLocking);
_attributesUsedForLocking = [[NSMutableArray alloc]
initWithArray: attributes];
[self _setIsEdited]; //To clean cache
return YES;
}
- (NSException *)validateName: (NSString *)name
{
const char *p, *s = [name cString];
int exc = 0;
NSArray *storedProcedures;
if ([_name isEqual:name]) return nil;
if (!name || ![name length]) exc++;
if (!exc)
{
p = s;
while (*p)
{
if (!isalnum(*p) &&
*p != '@' && *p != '#' && *p != '_' && *p != '$')
{
exc++;
break;
}
p++;
}
if (!exc && *s == '$') exc++;
if (exc)
return [NSException exceptionWithName: NSInvalidArgumentException
reason: [NSString stringWithFormat:@"%@ -- %@ 0x%x: argument \"%@\" contains invalid char '%c'",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
name,
*p]
userInfo: nil];
if ([_model entityNamed: name]) exc++;
else if ((storedProcedures = [[self model] storedProcedures]))
{
NSEnumerator *stEnum = [storedProcedures objectEnumerator];
EOStoredProcedure *st;
while ((st = [stEnum nextObject]))
{
NSEnumerator *attrEnum;
EOAttribute *attr;
attrEnum = [[st arguments] objectEnumerator];
while ((attr = [attrEnum nextObject]))
{
if ([name isEqualToString: [attr name]])
{
exc++;
break;
}
}
if (exc) break;
}
}
}
if (exc)
{
return [NSException exceptionWithName: NSInvalidArgumentException
reason: [NSString stringWithFormat: @"%@ -- %@ 0x%x: \"%@\" already used in the model",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
name]
userInfo: nil];
}
return nil;
}
- (void)addSubEntity: (EOEntity *)child
{
[self willChange];
[_subEntities addObject: child];
[[child parentEntity] removeSubEntity:child];
[child _setParentEntity: self];
}
- (void)removeSubEntity: (EOEntity *)child
{
[self willChange];
if ([child parentEntity] == self)
[child _setParentEntity: nil];
[_subEntities removeObject: child];
}
- (void)setIsAbstractEntity: (BOOL)flag
{
//OK
[self willChange];
_flags.isAbstractEntity = flag;
}
- (void)setMaxNumberOfInstancesToBatchFetch: (unsigned int)size
{
[self willChange];
_batchCount = size;
}
@end
@implementation EOEntity (EOModelReferentialIntegrity)
- (BOOL)referencesProperty: (id)property
{
NSEnumerator *enumerator;
EORelationship *rel;
EOAttribute *attr;
IMP enumNO=NULL;
enumerator = [[self attributes] objectEnumerator];
enumNO=NULL;
while ((attr = GDL2_NextObjectWithImpPtr(enumerator,&enumNO)))
{
if ([attr isFlattened] && [[attr realAttribute] isEqual: property])
return YES;
}
enumerator = [[self relationships] objectEnumerator];
enumNO=NULL;
while ((rel = GDL2_NextObjectWithImpPtr(enumerator,&enumNO)))
{
if ([rel referencesProperty: property])
return YES;
}
return NO;
}
- (NSArray *)externalModelsReferenced
{
NSEmitTODO(); //TODO
return nil; // TODO
}
@end
@implementation EOEntity (EOModelBeautifier)
- (void)beautifyName
{
//VERIFY
NSString *name = [self name];
[self setName: name];
[[self attributes] makeObjectsPerformSelector: @selector(beautifyName)];
[[self relationships] makeObjectsPerformSelector: @selector(beautifyName)];
[[self flattenedAttributes] makeObjectsPerformSelector: @selector(beautifyName)];
//Turbocat:
/*
// Make the entity name and all of its components conform
// to the Next naming style
// NAME -> name, FIRST_NAME -> firstName +
NSArray *listItems;
NSString *newString=[NSString string];
int anz,i;
EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity");
// Makes the receiver's name conform to a standard convention. Names that conform to this style are all lower-case except for the initial letter of each embedded word other than the first, which is upper case. Thus, "NAME" becomes "name", and "FIRST_NAME" becomes "firstName".
if ((_name) && ([_name length]>0)) {
listItems=[_name componentsSeparatedByString:@"_"];
newString=[newString stringByAppendingString:[[listItems objectAtIndex:0] lowercaseString]];
anz=[listItems count];
for (i=1; i < anz; i++) {
newString=[newString stringByAppendingString:[[listItems objectAtIndex:i] capitalizedString]];
}
//#warning ergaenzen um alle components (attributes, ...)
// Exception abfangen
NS_DURING
[self setName:newString];
NS_HANDLER
NSLog(@"%@ in Class: EOEntity , Method: beautifyName >> error : %@",[localException name],[localException reason]);
NS_ENDHANDLER
}
EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity");
*/
}
@end
@implementation EOEntity (GDL2Extenstions)
- (NSString *)docComment
{
return _docComment;
}
- (void)setDocComment: (NSString *)docComment
{
//OK
[self willChange];
ASSIGNCOPY(_docComment, docComment);
[self _setIsEdited];
}
@end
@implementation EOEntity (EOStoredProcedures)
- (EOStoredProcedure *)storedProcedureForOperation: (NSString *)operation
{
return [_storedProcedures objectForKey: operation];
}
- (void)setStoredProcedure: (EOStoredProcedure *)storedProcedure
forOperation: (NSString *)operation
{
[self willChange];
if (!_storedProcedures)
{
ASSIGN(_storedProcedures, [NSMutableDictionary dictionary]);
}
if (storedProcedure != nil) {
[_storedProcedures setObject:storedProcedure
forKey:operation];
} else {
[_storedProcedures removeObjectForKey:operation];
}
}
@end
@implementation EOEntity (EOPrimaryKeyGeneration)
- (NSString *)primaryKeyRootName
{
if (_parent)
return [_parent primaryKeyRootName];
return _externalName;
}
@end
@implementation EOEntity (EOEntityClassDescription)
- (EOClassDescription *)classDescriptionForInstances
{
// EOFLOGObjectLevelArgs(@"EOEntity", @"in classDescriptionForInstances");
EOFLOGObjectLevelArgs(@"EOEntity", @"_classDescription=%@",
_classDescription);
if (!_classDescription)
{
_classDescription
= [[EOEntityClassDescription alloc] initWithEntity: self];
//NO ? NotifyCenter addObserver:EOEntityClassDescription selector:_eoNowMultiThreaded: name:NSWillBecomeMultiThreadedNotification object:nil
}
return _classDescription;
}
@end
/** Useful private methods made public in GDL2 **/
@implementation EOEntity (EOEntityGDL2Additions)
/** Returns attribute (if any) for path **/
- (EOAttribute*) attributeForPath: (NSString*)path
{
//OK
EOAttribute *attribute = nil;
NSArray *pathElements = nil;
NSString *part = nil;
EOEntity *entity = self;
int i, count = 0;
EOFLOGObjectLevelArgs(@"EOEntity", @"path=%@", path);
pathElements = [path componentsSeparatedByString: @"."];
EOFLOGObjectLevelArgs(@"EOEntity", @"pathElements=%@", pathElements);
count = [pathElements count];
for (i = 0; i < count - 1; i++)
{
EORelationship *rel = nil;
part = [pathElements objectAtIndex: i];
EOFLOGObjectLevelArgs(@"EOEntity", @"i=%d part=%@", i, part);
rel = [entity anyRelationshipNamed: part];
NSAssert2(rel,
@"no relationship named %@ in entity %@",
part,
[entity name]);
EOFLOGObjectLevelArgs(@"EOEntity", @"i=%d part=%@ rel=%@",
i, part, rel);
entity = [rel destinationEntity];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity name=%@", [entity name]);
}
part = [pathElements lastObject];
EOFLOGObjectLevelArgs(@"EOEntity", @"part=%@", part);
attribute = [entity anyAttributeNamed: part];
EOFLOGObjectLevelArgs(@"EOEntity", @"resulting attribute=%@", attribute);
return attribute;
}
/** Returns relationship (if any) for path **/
- (EORelationship*) relationshipForPath: (NSString*)path
{
//OK ?
EORelationship *relationship = nil;
EOEntity *entity = self;
NSArray *pathElements = nil;
int i, count;
EOFLOGObjectLevelArgs(@"EOEntity", @"path=%@", path);
pathElements = [path componentsSeparatedByString: @"."];
count = [pathElements count];
for (i = 0; i < count; i++)
{
NSString *part = [pathElements objectAtIndex: i];
relationship = [entity anyRelationshipNamed: part];
EOFLOGObjectLevelArgs(@"EOEntity", @"i=%d part=%@ rel=%@",
i, part, relationship);
if (relationship)
{
entity = [relationship destinationEntity];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity name=%@", [entity name]);
}
else if (i < (count - 1)) // Not the last part
{
NSAssert2(relationship,
@"no relationship named %@ in entity %@",
part,
[entity name]);
}
}
EOFLOGObjectLevelArgs(@"EOEntity", @"relationship=%@", relationship);
return relationship;
}
@end
@implementation EOEntity (EOEntityPrivate)
/* private method for finding out if there is an attribute with a name
without triggering lazy loading */
- (BOOL) _hasAttributeNamed:(NSString *)name
{
return [[_attributes valueForKey:@"name"] containsObject:name];
}
- (BOOL)isPrototypeEntity
{
[self notImplemented:_cmd];
return NO; // TODO
}
/* throws an exception if _model is not nil, and the model argument is not
* identical to the _model ivar. As a special case EOModel -removeEntity:
* is allowed to call this with a nil model, but removeEntity: is responsible
* for any bookeeping.
*
* in other words, this method should not be used to change an entity's model.
*/
- (void)_setModel: (EOModel *)model
{
EOFLOGObjectLevelArgs(@"EOEntity", @"setModel=%p", model);
NSAssert4(!_attributesToFetch
|| [_attributesToFetch isKindOfClass:[NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@",
[self name],
_attributesToFetch,
[_attributesToFetch class],
_attributesToFetch);
NSAssert3((_model == nil || _model == model || model == nil),
@"Attempt to set entity: %@ owned by model: %@ to model: @%.",
[self name], [_model name], [model name]);
_model = model;
}
/* only for private usage of -addSubEntity: and -removeSubEntity: */
- (void)_setParentEntity: (EOEntity *)parent
{
[self willChange]; // TODO: verify
_parent = parent;
}
- (NSDictionary *)snapshotForRow: (NSDictionary *)aRow
{
NSArray *array = [self attributesUsedForLocking];
int i, n = [array count];
NSMutableDictionary *dict
= AUTORELEASE([GDL2_alloc(NSMutableDictionary) initWithCapacity: n]);
IMP arrayOAI=NULL;
IMP dictSOFK=NULL;
IMP aRowOFK=NULL;
for (i = 0; i < n; i++)
{
id key = [(EOAttribute *)GDL2_ObjectAtIndexWithImpPtr(array,&arrayOAI,i)
name];
GDL2_SetObjectForKeyWithImpPtr(dict,&dictSOFK,
GDL2_ObjectForKeyWithImpPtr(aRow,&aRowOFK,key),
key);
}
return dict;
}
- (Class)_classForInstances
{
if (!_classForInstances)
{
NSString *className = nil;
Class objectClass = Nil;
className = [self className];
EOFLOGObjectLevelArgs(@"EOEntity", @"className=%@", className);
objectClass = NSClassFromString(className);
if (!objectClass)
{
NSLog(@"Error: No class named %@", className);
}
else
{
EOFLOGObjectLevelArgs(@"EOEntity", @"objectClass=%@", objectClass);
ASSIGN(_classForInstances, objectClass);
}
}
return _classForInstances;
}
- (void)_setInternalInfo: (NSDictionary *)dictionary
{
//OK
[self willChange];
ASSIGN(_internalInfo, dictionary);
[self _setIsEdited];
}
- (id) globalIDForRow: (NSDictionary*)row
isFinal: (BOOL)isFinal
{
EOKeyGlobalID *globalID = nil;
NSArray *primaryKeyAttributeNames = nil;
int count = 0;
NSAssert([row count] > 0, @"Empty Row.");
primaryKeyAttributeNames = [self primaryKeyAttributeNames];
count = [primaryKeyAttributeNames count];
{
id keyArray[count];
int i;
IMP rowOFK=NULL;
IMP pkanOAI=NULL;
memset(keyArray, 0, sizeof(id) * count);
for (i = 0; i < count; i++)
{
keyArray[i] = GDL2_ObjectForKeyWithImpPtr(row,&rowOFK,
GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,
&pkanOAI,i));
}
globalID = [EOKeyGlobalID globalIDWithEntityName: [self name]
keys: keyArray
keyCount: count
zone: [self zone]];
}
//NSEmitTODO(); //TODO
//TODO isFinal ??
return globalID;
}
-(Class)classForObjectWithGlobalID: (EOKeyGlobalID*)globalID
{
//near OK
Class classForInstances = _classForInstances;
//TODO:use globalID ??
if (!classForInstances)
{
classForInstances = [self _classForInstances];
}
return _classForInstances;
}
//DESTROY v later because it may be still in use
#define AUTORELEASE_SETNIL(v) { AUTORELEASE(v); v=nil; }
- (void)_setIsEdited
{
if(_flags.updating)
return;
EOFLOGObjectLevelArgs(@"EOEntity", @"START entity name=%@", [self name]);
NSAssert4(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@",
[self name],
_attributesToFetch,
[_attributesToFetch class],
_attributesToFetch);
//Destroy cached ivar
EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyNames: void:%p [%p] %s",
(void*)nil, (void*)_classPropertyNames,
(_classPropertyNames ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_classPropertyNames);
EOFLOGObjectLevelArgs(@"EOEntity", @"_primaryKeyAttributeNames: %p %s",
(void*)_primaryKeyAttributeNames,
(_primaryKeyAttributeNames ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_primaryKeyAttributeNames);
EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyAttributeNames: %p %s",
_classPropertyAttributeNames,
(_classPropertyAttributeNames ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_classPropertyAttributeNames);
EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyToOneRelationshipNames: %p %s",
_classPropertyToOneRelationshipNames,
(_classPropertyToOneRelationshipNames ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_classPropertyToOneRelationshipNames);
EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyToManyRelationshipNames: %p %s",
_classPropertyToManyRelationshipNames,
(_classPropertyToManyRelationshipNames ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_classPropertyToManyRelationshipNames);
EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesToFetch: %p %s",
_attributesToFetch,
(_attributesToFetch ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_attributesToFetch);
EOFLOGObjectLevelArgs(@"EOEntity", @"_dbSnapshotKeys: %p %s",
_dbSnapshotKeys, (_dbSnapshotKeys ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_dbSnapshotKeys);
EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesToSave: %p %s",
_attributesToSave, (_attributesToSave ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_attributesToSave);
EOFLOGObjectLevelArgs(@"EOEntity", @"_propertiesToFault: %p %s",
_propertiesToFault, (_propertiesToFault ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_propertiesToFault);
EOFLOGObjectLevelArgs(@"EOEntity", @"_adaptorDictionaryInitializer: %p %s",
_adaptorDictionaryInitializer,
(_adaptorDictionaryInitializer ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_adaptorDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity", @"_snapshotDictionaryInitializer: %p %s",
_snapshotDictionaryInitializer,
(_snapshotDictionaryInitializer ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_snapshotDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity",@"_primaryKeyDictionaryInitializer: %p %s",
_primaryKeyDictionaryInitializer,
(_primaryKeyDictionaryInitializer ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_primaryKeyDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity",@"_propertyDictionaryInitializer: %p %s",
_propertyDictionaryInitializer,
(_propertyDictionaryInitializer ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_propertyDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity",@"_instanceDictionaryInitializer: %p %s",
_instanceDictionaryInitializer,
(_instanceDictionaryInitializer ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_instanceDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity",@"_relationshipsByName: %p %s",
_relationshipsByName,
(_relationshipsByName ? "Not NIL" : "NIL"));
AUTORELEASE_SETNIL(_relationshipsByName);
AUTORELEASE_SETNIL(_attributesByName);
//TODO call _flushCache on each attr
NSAssert4(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@",
[self name],
_attributesToFetch,
[_attributesToFetch class],
_attributesToFetch);
EOFLOGObjectLevelArgs(@"EOEntity", @"STOP%s", "");
}
/** Returns attributes by name (only attributes, not relationships) **/
- (NSDictionary*)attributesByName
{
if (_flags.attributesIsLazy)
[self attributes];
if (!_attributesByName)
{
unsigned int i, c;
_attributesByName = [[NSMutableDictionary alloc] init];
for (i = 0, c = [_attributes count]; i < c; i++)
{
[_attributesByName setObject:[_attributes objectAtIndex:i]
forKey:[[_attributes objectAtIndex:i] name]];
}
}
return _attributesByName;
}
- (NSDictionary*)relationshipsByName
{
if (_flags.relationshipsIsLazy)
[self relationships];
if (!_relationshipsByName)
{
unsigned int i, c;
_relationshipsByName = [[NSMutableDictionary alloc] init];
for (i = 0, c = [_relationships count]; i < c; i++)
{
[_relationshipsByName setObject:[_relationships objectAtIndex:i]
forKey:[[_relationships objectAtIndex:i] name]];
}
}
return _relationshipsByName;
}
- (NSArray*) _allFetchSpecifications
{
//OK
NSDictionary *fetchSpecificationDictionary =
[self _fetchSpecificationDictionary];
NSArray *fetchSpecValues = [fetchSpecificationDictionary allValues];
return fetchSpecValues;
}
- (NSDictionary*) _fetchSpecificationDictionary
{
if ((!_fetchSpecificationDictionary) && (_model))
{
ASSIGN(_fetchSpecificationDictionary,
[_model _loadFetchSpecificationDictionaryForEntityNamed:_name]);
}
return _fetchSpecificationDictionary;
}
- (void) _loadEntity
{
[self attributes];
[self relationships];
[self _fetchSpecificationDictionary];
}
- (id) parentRelationship
{
//TODO
return [self notImplemented: _cmd];
}
- (int) _numberOfRelationships
{
//OK
return [[self relationships] count];
}
- (BOOL) _hasReadOnlyAttributes
{
//OK
BOOL hasReadOnlyAttributes = NO;
NSArray *attributes = [self attributes];
int i, count=[attributes count];
for (i = 0; !hasReadOnlyAttributes && i < count; i++)
hasReadOnlyAttributes = [[attributes objectAtIndex: i] isReadOnly];
return hasReadOnlyAttributes;
}
- (NSArray*) writableDBSnapshotKeys
{
//OK
NSArray *writableDBSnapshotKeys=nil;
if (![self isReadOnly])
{
NSArray *attributesToFetch = [self _attributesToFetch];
int i, count = [attributesToFetch count];
IMP atfOAI=NULL;
IMP sAO=NULL;
NSMutableArray* tmpArray
= AUTORELEASE([GDL2_alloc(NSMutableArray) initWithCapacity: count]);
NSAssert3(!attributesToFetch
|| [attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[attributesToFetch class],
attributesToFetch);
for (i = 0; i < count; i++)
{
EOAttribute *attribute = GDL2_ObjectAtIndexWithImpPtr(attributesToFetch,&atfOAI,i);
if (![attribute isReadOnly])
GDL2_AddObjectWithImpPtr(tmpArray,&sAO,[attribute name]);
}
writableDBSnapshotKeys=tmpArray;
}
else
writableDBSnapshotKeys=GDL2_NSArray;
return writableDBSnapshotKeys;
}
- (NSArray*) rootAttributesUsedForLocking
{
//OK ?
NSArray *rootAttributesUsedForLocking = nil;
NSArray *attributesUsedForLocking = [self attributesUsedForLocking];
int count = [attributesUsedForLocking count];
if (count>0)
{
int i=0;
NSMutableArray *tmpArray
= AUTORELEASE([GDL2_alloc(NSMutableArray) initWithCapacity: count]);
IMP auflOAI=NULL;
IMP tAO=NULL;
for (i = 0; i < count; i++)
{
EOAttribute *attribute = GDL2_ObjectAtIndexWithImpPtr(attributesUsedForLocking,
&auflOAI,i);
if (![attribute isDerived])
GDL2_AddObjectWithImpPtr(tmpArray,&tAO,attribute);
}
rootAttributesUsedForLocking=tmpArray;
}
else
rootAttributesUsedForLocking=GDL2_NSArray;
return rootAttributesUsedForLocking;
}
- (BOOL) isSubEntityOf: (id)param0
{
//TODO
[self notImplemented: _cmd];
return NO;
}
- (id) initObject: (id)param0
editingContext: (id)param1
globalID: (id)param2
{
//TODO
return [self notImplemented: _cmd];
}
- (id) allocBiggestObjectWithZone: (NSZone*)zone
{
//TODO
return [self notImplemented: _cmd];
}
- (Class) _biggestClass
{
//OK
Class biggestClass = Nil;
biggestClass = [self classForObjectWithGlobalID: nil];
return biggestClass;
}
- (NSArray*) relationshipsPlist
{
//OK
NSMutableArray *relsPlist;
if (_flags.relationshipsIsLazy)
{
relsPlist = _relationships;
}
else
{
NSArray *relationships;
int relCount;
relsPlist = [NSMutableArray array];
relationships = [self relationships];
relCount = [relationships count];
if (relCount > 0)
{
int i;
for (i = 0; i < relCount; i++)
{
NSMutableDictionary *relPlist = [NSMutableDictionary dictionary];
EORelationship *rel = [relationships objectAtIndex: i];
[rel encodeIntoPropertyList: relPlist];
[relsPlist addObject: relPlist];
}
}
}
return relsPlist;
}
- (id) rootParent
{
id prevParent = self;
id parent = self;
while (parent)
{
prevParent = parent;
parent = [prevParent parentEntity];
}
return prevParent;
}
- (void) _setParent: (id)param0
{
//TODO
[self notImplemented: _cmd];
}
- (NSArray*) _hiddenRelationships
{
//OK
if (!_hiddenRelationships)
_hiddenRelationships = [NSMutableArray new];
return _hiddenRelationships;
}
- (NSArray*) _propertyNames
{
//OK
NSMutableArray *propertyNames = nil;
NSArray *attributes = [self attributes];
NSArray *attributeNames = [attributes resultsOfPerformingSelector:
@selector(name)];
NSArray *relationships = [self relationships];
NSArray *relationshipNames = [relationships resultsOfPerformingSelector:
@selector(name)];
propertyNames = [NSMutableArray arrayWithArray: attributeNames];
[propertyNames addObjectsFromArray: relationshipNames];
return propertyNames;
}
- (id) _flattenAttribute: (id)param0
relationshipPath: (id)param1
currentAttributes: (id)param2
{
//TODO
return [self notImplemented: _cmd];
}
- (NSString*) snapshotKeyForAttributeName: (NSString*)attributeName
{
NSString *attName = [self _flattenedAttNameToSnapshotKeyMapping];
if (attName)
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];
}
else
attName = attributeName; //TODO-VERIFY
return attName;
}
- (id) _flattenedAttNameToSnapshotKeyMapping
{
// NSArray *attributesToSave = [self _attributesToSave];
//NSEmitTODO(); //TODO
return nil; //[self notImplemented:_cmd]; //TODO
}
- (EOMKKDSubsetMapping*) _snapshotToAdaptorRowSubsetMapping
{
if (!_snapshotToAdaptorRowSubsetMapping)
{
EOMKKDInitializer *snapshotDictionaryInitializer =
[self _snapshotDictionaryInitializer];
EOMKKDInitializer *adaptorDictionaryInitializer =
[self _adaptorDictionaryInitializer];
EOMKKDSubsetMapping *subsetMapping =
[snapshotDictionaryInitializer
subsetMappingForSourceDictionaryInitializer: adaptorDictionaryInitializer];
ASSIGN(_snapshotToAdaptorRowSubsetMapping,subsetMapping);
}
return _snapshotToAdaptorRowSubsetMapping;
}
- (EOMutableKnownKeyDictionary*) _dictionaryForPrimaryKey
{
//OK
EOMKKDInitializer *primaryKeyDictionaryInitializer =
[self _primaryKeyDictionaryInitializer];
EOMutableKnownKeyDictionary *dictionaryForPrimaryKey =
[EOMutableKnownKeyDictionary dictionaryWithInitializer:
primaryKeyDictionaryInitializer];
return dictionaryForPrimaryKey;
}
- (EOMutableKnownKeyDictionary*) _dictionaryForProperties
{
//OK
EOMKKDInitializer *propertyDictionaryInitializer = nil;
EOMutableKnownKeyDictionary *dictionaryForProperties = nil;
propertyDictionaryInitializer = [self _propertyDictionaryInitializer];
dictionaryForProperties
= [EOMutableKnownKeyDictionary dictionaryWithInitializer:
propertyDictionaryInitializer];
return dictionaryForProperties;
}
/** returns a new autoreleased mutable dictionary to store properties
returns nil if there's no key in the instanceDictionaryInitializer
**/
- (EOMutableKnownKeyDictionary*) _dictionaryForInstanceProperties
{
//OK
EOMKKDInitializer *instanceDictionaryInitializer = nil;
EOMutableKnownKeyDictionary *dictionaryForProperties = nil;
instanceDictionaryInitializer = [self _instanceDictionaryInitializer];
// No need to build the dictionary if there's no key.
// The only drawback I see is if someone use extraData feature of MKK dictionary
if ([instanceDictionaryInitializer count]>0)
{
dictionaryForProperties = [EOMutableKnownKeyDictionary
dictionaryWithInitializer:
instanceDictionaryInitializer];
}
return dictionaryForProperties;
}
- (NSArray*) _relationshipsToFaultForRow: (NSDictionary*)row
{
NSMutableArray *rels = [NSMutableArray array];
NSArray *classProperties = [self classProperties];
int i, count = [classProperties count];
for (i = 0; i < count; i++)
{
EORelationship *classProperty = [classProperties objectAtIndex: i];
if ([classProperty isKindOfClass: [EORelationship class]])
{
EORelationship *relsubs = [classProperty
_substitutionRelationshipForRow: row];
[rels addObject: relsubs];
}
}
return rels;
}
- (NSArray*) _classPropertyAttributes
{
//OK
//IMPROVE We can improve this by caching the result....
NSArray *classPropertyAttributes = nil;
//Get classProperties (EOAttributes + EORelationships)
NSArray *classProperties = [self classProperties];
int count = [classProperties count];
if (count>0)
{
int i=0;
NSMutableArray *tmpArray
= AUTORELEASE([GDL2_alloc(NSMutableArray) initWithCapacity: count]);
IMP cpOAI=NULL;
IMP tAO=NULL;
for (i = 0; i < count; i++)
{
id object = GDL2_ObjectAtIndexWithImpPtr(classProperties,&cpOAI,i);
if ([object isKindOfClass: GDL2_EOAttributeClass])
GDL2_AddObjectWithImpPtr(tmpArray,&tAO,object);
}
classPropertyAttributes = tmpArray;
}
else
classPropertyAttributes=GDL2_NSArray;
return classPropertyAttributes;
}
- (NSArray*) _attributesToSave
{
//Near OK
EOFLOGObjectLevelArgs(@"EOEntity",
@"START Entity _attributesToSave entityname=%@",
[self name]);
if (!_attributesToSave)
{
NSArray *attributesToFetch = [self _attributesToFetch];
int i, count = [attributesToFetch count];
NSMutableArray *attributesToSave = [NSMutableArray arrayWithCapacity:count];
NSAssert3(!attributesToFetch
|| [attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[_attributesToFetch class],
_attributesToFetch);
for (i = 0; i < count; i++)
{
EOAttribute *attribute = [attributesToFetch objectAtIndex: i];
BOOL isFlattened = [attribute isFlattened];
if (!isFlattened)
[attributesToSave addObject: attribute];
}
ASSIGN(_attributesToSave, attributesToSave);
}
EOFLOGObjectLevelArgs(@"EOEntity", @"STOP Entity _attributesToSave entityname=%@ attrs:%@",
[self name], _attributesToSave);
return _attributesToSave;
}
//sorted by name attributes
- (NSArray*) _attributesToFetch
{
//Seems OK
EOFLOGObjectLevelArgs(@"EOEntity",
@"START Entity _attributesToFetch entityname=%@",
[self name]);
EOFLOGObjectLevelArgs(@"EOEntity", @"AttributesToFetch:%p",
_attributesToFetch);
EOFLOGObjectLevelArgs(@"EOEntity", @"AttributesToFetch:%@",
_attributesToFetch);
NSAssert2(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@",
[self name],
[_attributesToFetch class]);
if (!_attributesToFetch)
{
NSMutableDictionary *attributesDict = [NSMutableDictionary dictionary];
NS_DURING
{
int iArray = 0;
NSArray *arrays[] = { [self attributesUsedForLocking],
[self primaryKeyAttributes],
[self classProperties],
[self relationships] };
_attributesToFetch = RETAIN([NSMutableArray array]);
EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@ - _attributesToFetch %p [RC=%d]:%@",
[self name],
_attributesToFetch,
[_attributesToFetch retainCount],
_attributesToFetch);
for (iArray = 0; iArray < 4; iArray++)
{
int i, count = 0;
EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@ - arrays[iArray]:%@",
[self name], arrays[iArray]);
count = [arrays[iArray] count];
for (i = 0; i < count; i++)
{
id property = [arrays[iArray] objectAtIndex: i];
NSString *propertyName = [(EOAttribute*)property name];
//VERIFY
EOFLOGObjectLevelArgs(@"EOEntity",
@"propertyName=%@ - property=%@",
propertyName, property);
if ([property isKindOfClass: GDL2_EOAttributeClass])
{
EOAttribute *attribute = property;
if ([attribute isFlattened])
{
attribute = [[attribute _definitionArray]
objectAtIndex: 0];
propertyName = [attribute name];
}
}
if ([property isKindOfClass: [EORelationship class]])
{
[self _addAttributesToFetchForRelationshipPath:
[(EORelationship*)property relationshipPath]
atts: attributesDict];
}
else if ([property isKindOfClass: GDL2_EOAttributeClass])
{
[attributesDict setObject: property
forKey: propertyName];
}
else
{
NSEmitTODO(); //TODO
}
}
}
}
NS_HANDLER
{
NSDebugMLog(@"Exception: %@",localException);
[localException raise];
}
NS_ENDHANDLER;
NS_DURING
{
NSDebugMLog(@"Attributes to fetch classes %@",
[_attributesToFetch resultsOfPerformingSelector:
@selector(class)]);
[_attributesToFetch addObjectsFromArray: [attributesDict allValues]];
NSDebugMLog(@"Attributes to fetch classes %@",
[_attributesToFetch resultsOfPerformingSelector:
@selector(class)]);
[_attributesToFetch sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order.
}
NS_HANDLER
{
NSDebugMLog(@"Exception: %@",localException);
[localException raise];
}
NS_ENDHANDLER;
}
NSAssert3(!_attributesToFetch
|| [_attributesToFetch isKindOfClass: [NSArray class]],
@"Entity %@: _attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[_attributesToFetch class],
_attributesToFetch);
EOFLOGObjectLevelArgs(@"EOEntity", @"Stop Entity %@ - _attributesToFetch %p [RC=%d]:%@",
[self name],
_attributesToFetch,
[_attributesToFetch retainCount],
_attributesToFetch);
return _attributesToFetch;
}
- (EOMKKDInitializer*) _adaptorDictionaryInitializer
{
//OK
EOFLOGObjectLevelArgs(@"EOEntity", @"Start _adaptorDictionaryInitializer=%@",
_adaptorDictionaryInitializer);
if (!_adaptorDictionaryInitializer)
{
NSArray *attributesToFetch = [self _attributesToFetch];
NSArray *attributeToFetchNames = [attributesToFetch
resultsOfPerformingSelector:
@selector(name)];
EOFLOGObjectLevelArgs(@"EOEntity", @"attributeToFetchNames=%@",
attributeToFetchNames);
NSAssert3(!attributesToFetch
|| [attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[attributesToFetch class],
attributesToFetch);
NSAssert1([attributesToFetch count] > 0,
@"No Attributes to fetch in entity %@", [self name]);
NSAssert1([attributeToFetchNames count] > 0,
@"No Attribute names to fetch in entity %@", [self name]);
EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: attributeToFetchNames=%@",
[self name],
attributeToFetchNames);
ASSIGN(_adaptorDictionaryInitializer,
[EOMutableKnownKeyDictionary initializerFromKeyArray:
attributeToFetchNames]);
EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@ _adaptorDictionaryInitializer=%@",
[self name],
_adaptorDictionaryInitializer);
}
EOFLOGObjectLevelArgs(@"EOEntity", @"Stop _adaptorDictionaryInitializer=%p",
_adaptorDictionaryInitializer);
EOFLOGObjectLevelArgs(@"EOEntity", @"Stop _adaptorDictionaryInitializer=%@",
_adaptorDictionaryInitializer);
return _adaptorDictionaryInitializer;
}
- (EOMKKDInitializer*) _snapshotDictionaryInitializer
{
if (!_snapshotDictionaryInitializer)
{
NSArray *dbSnapshotKeys = [self dbSnapshotKeys];
ASSIGN(_snapshotDictionaryInitializer,
[EOMutableKnownKeyDictionary initializerFromKeyArray:
dbSnapshotKeys]);
}
return _snapshotDictionaryInitializer;
}
- (EOMKKDInitializer*) _primaryKeyDictionaryInitializer
{
//OK
if (!_primaryKeyDictionaryInitializer)
{
NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames];
NSAssert1([primaryKeyAttributeNames count] > 0,
@"No primaryKeyAttributeNames in entity %@", [self name]);
EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: primaryKeyAttributeNames=%@",
[self name],
primaryKeyAttributeNames);
_primaryKeyDictionaryInitializer = [EOMKKDInitializer
newWithKeyArray:
primaryKeyAttributeNames];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: _primaryKeyDictionaryInitializer=%@",
[self name],
_primaryKeyDictionaryInitializer);
}
return _primaryKeyDictionaryInitializer;
}
- (EOMKKDInitializer*) _propertyDictionaryInitializer
{
//OK
// If not already built, built it
if (!_propertyDictionaryInitializer)
{
// Get class properties (EOAttributes + EORelationships)
NSArray *classProperties = [self classProperties];
NSArray *classPropertyNames =
[classProperties resultsOfPerformingSelector: @selector(name)];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %@ classPropertyNames=%@",
[self name], classPropertyNames);
NSAssert1([classProperties count] > 0,
@"No classProperties in entity %@", [self name]);
NSAssert1([classPropertyNames count] > 0,
@"No classPropertyNames in entity %@", [self name]);
//Build the multiple known key initializer
_propertyDictionaryInitializer = [EOMKKDInitializer
newWithKeyArray: classPropertyNames];
}
return _propertyDictionaryInitializer;
}
- (EOMKKDInitializer*) _instanceDictionaryInitializer
{
//OK
// If not already built, built it
if (!_instanceDictionaryInitializer)
{
// Get class properties (EOAttributes + EORelationships)
NSArray *classProperties = [self classProperties];
NSArray* excludedPropertyNames=nil;
NSArray *classPropertyNames = nil;
Class classForInstances = [self _classForInstances];
classPropertyNames = [classProperties resultsOfPerformingSelector: @selector(name)];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %@ classPropertyNames=%@",
[self name], classPropertyNames);
excludedPropertyNames = [classForInstances
_instanceDictionaryInitializerExcludedPropertyNames];
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %@ excludedPropertyNames=%@",
[self name], excludedPropertyNames);
if ([excludedPropertyNames count]>0)
{
NSMutableArray* mutableClassPropertyNames=[classPropertyNames mutableCopy];
[mutableClassPropertyNames removeObjectsInArray:excludedPropertyNames];
classPropertyNames=AUTORELEASE(mutableClassPropertyNames);
}
EOFLOGObjectLevelArgs(@"EOEntity", @"entity %@ classPropertyNames=%@",
[self name], classPropertyNames);
NSAssert1([classProperties count] > 0,
@"No classProperties in entity %@", [self name]);
NSAssert1([classPropertyNames count] > 0,
@"No classPropertyNames in entity %@", [self name]);
//Build the multiple known key initializer
_instanceDictionaryInitializer = [EOMKKDInitializer
newWithKeyArray: classPropertyNames];
EOFLOGObjectLevelArgs(@"EOEntity", @"_instanceDictionaryInitializer=%@",
_instanceDictionaryInitializer);
}
return _instanceDictionaryInitializer;
}
@end
@implementation EOEntity (EOEntityRelationshipPrivate)
- (EORelationship*) _inverseRelationshipPathForPath: (NSString*)path
{
//TODO
return [self notImplemented: _cmd];
}
- (NSDictionary*) _keyMapForIdenticalKeyRelationshipPath: (NSString*)path
{
NSDictionary *keyMap = nil;
EORelationship *rel;
NSMutableArray *sourceAttributeNames = [NSMutableArray array];
NSMutableArray *destinationAttributeNames = [NSMutableArray array];
NSArray *joins;
int count = 0;
//use path,not only one element ?
rel = [self relationshipNamed: path];
joins = [rel joins];
count = [joins count];
if (count>0)
{
int i=0;
IMP joinsOAI=NULL;
IMP sanAO=NULL;
IMP danAO=NULL;
for (i = 0; i < count; i++)
{
EOJoin *join = GDL2_ObjectAtIndexWithImpPtr(joins,&joinsOAI,i);
EOAttribute *sourceAttribute = [join sourceAttribute];
EOAttribute *destinationAttribute =
[self _mapAttribute:sourceAttribute
toDestinationAttributeInLastComponentOfRelationshipPath: path];
GDL2_AddObjectWithImpPtr(sourceAttributeNames,&sanAO,
[sourceAttribute name]);
GDL2_AddObjectWithImpPtr(destinationAttributeNames,&danAO,
[destinationAttribute name]);
}
};
keyMap = [NSDictionary dictionaryWithObjectsAndKeys:
sourceAttributeNames, @"sourceKeys",
destinationAttributeNames, @"destinationKeys",
nil, nil];
//return something like {destinationKeys = (code); sourceKeys = (languageCode); }
return keyMap;
}
- (EOAttribute *)_mapAttribute: (EOAttribute *)attribute
toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path
{
NSArray *components = nil;
EORelationship *rel = nil;
NSArray *sourceAttributes = nil;
NSArray *destinationAttributes = nil;
EOEntity *destinationEntity = nil;
NSAssert(attribute, @"No attribute");
NSAssert(path, @"No path");
NSAssert([path length] > 0, @"Empty path");
components = [path componentsSeparatedByString: @"."];
NSAssert([components count] > 0, @"Empty components array");
rel = [self relationshipNamed: [components lastObject]];
sourceAttributes = [rel sourceAttributes];
destinationAttributes = [rel destinationAttributes];
destinationEntity = [rel destinationEntity];
NSEmitTODO(); //TODO
return [self notImplemented: _cmd];
}
- (BOOL) _relationshipPathIsToMany: (NSString*)relPath
{
//Seems OK
BOOL isToMany = NO;
NSArray *parts = [relPath componentsSeparatedByString: @"."];
EOEntity *entity = self;
int i, count = [parts count];
for (i = 0 ; !isToMany && i < count; i++) //VERIFY Stop when finding the 1st isToMany ?
{
EORelationship *rel = [entity relationshipNamed:
[parts objectAtIndex: i]];
isToMany = [rel isToMany];
if (!isToMany)
entity = [rel destinationEntity];
}
return isToMany;
}
- (BOOL) _relationshipPathHasIdenticalKeys: (id)param0
{
[self notImplemented: _cmd];
return NO;
}
- (NSDictionary *)_keyMapForRelationshipPath: (NSString *)path
{
//Ayers: Review
// what if relationshipPathIsMultiHop (foo.bar.joe)?
//NearOK
NSMutableArray *sourceKeys = [NSMutableArray array];
NSMutableArray *destinationKeys = [NSMutableArray array];
//NSArray *attributesToFetch = [self _attributesToFetch]; //Use It !!
EORelationship *relationship = [self anyRelationshipNamed: path]; //?? iterate on path ? //TODO
NSEmitTODO(); //TODO
if (relationship)
{
NSArray *joins = [relationship joins];
int count = [joins count];
if (count>0)
{
int i=0;
IMP joinsOAI=NULL;
IMP skAO=NULL;
IMP dkAO=NULL;
for(i = 0; i < count; i++)
{
EOJoin *join = GDL2_ObjectAtIndexWithImpPtr(joins,&joinsOAI,i);
EOAttribute *sourceAttribute = [join sourceAttribute];
EOAttribute *destinationAttribute = [join destinationAttribute];
GDL2_AddObjectWithImpPtr(sourceKeys,&skAO,[sourceAttribute name]);
GDL2_AddObjectWithImpPtr(destinationKeys,&dkAO,[destinationAttribute name]);
}
};
}
return [NSDictionary dictionaryWithObjectsAndKeys:
sourceKeys, @"sourceKeys",
destinationKeys, @"destinationKeys",
nil];
//{destinationKeys = (code); sourceKeys = (countryCode); }
}
@end
@implementation EOEntity (EOEntitySQLExpression)
- (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression
{
return [self notImplemented: _cmd]; //TODO
}
+ (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression
{
return [self notImplemented: _cmd]; //TODO
}
@end
@implementation EOEntity (MethodSet11)
- (NSException *)validateObjectForDelete: (id)object
{
//OK ??
NSArray *relationships = nil;
NSEnumerator *relEnum = nil;
EORelationship *relationship = nil;
NSMutableArray *expArray = nil;
relationships = [self relationships];
relEnum = [relationships objectEnumerator];
while ((relationship = [relEnum nextObject]))
{
//classproperties
//rien pour nullify
if ([relationship deleteRule] == EODeleteRuleDeny)
{
if (!expArray)
expArray = [NSMutableArray arrayWithCapacity:5];
[expArray addObject:
[NSException validationExceptionWithFormat:
@"delete operation for relationship key %@ refused",
[relationship name]]];
}
}
if (expArray)
return [NSException aggregateExceptionWithExceptions:expArray];
else
return nil;
}
/** Retain an array of name of all EOAttributes **/
- (NSArray*) classPropertyAttributeNames
{
//Should be OK
if (!_classPropertyAttributeNames)
{
int i=0;
NSArray *classProperties = [self classProperties];
int count = [classProperties count];
_classPropertyAttributeNames = [NSMutableArray new];
for (i = 0; i < count; i++)
{
EOAttribute *property = [classProperties objectAtIndex: i];
if ([property isKindOfClass: GDL2_EOAttributeClass])
[(NSMutableArray*)_classPropertyAttributeNames
addObject: [property name]];
};
EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyAttributeNames=%@",
_classPropertyAttributeNames);
}
return _classPropertyAttributeNames;
}
- (NSArray*) classPropertyToManyRelationshipNames
{
//Should be OK
if (!_classPropertyToManyRelationshipNames)
{
NSArray *classProperties = [self classProperties];
int i, count = [classProperties count];
Class relClass = [EORelationship class];
_classPropertyToManyRelationshipNames = [NSMutableArray new];
for (i = 0; i < count; i++)
{
EORelationship *property = [classProperties objectAtIndex: i];
if ([property isKindOfClass: relClass]
&& [property isToMany])
[(NSMutableArray*)_classPropertyToManyRelationshipNames
addObject: [property name]];
}
}
return _classPropertyToManyRelationshipNames;
}
- (NSArray*) classPropertyToOneRelationshipNames
{
//Should be OK
if (!_classPropertyToOneRelationshipNames)
{
NSArray *classProperties = [self classProperties];
int i, count = [classProperties count];
Class relClass = [EORelationship class];
_classPropertyToOneRelationshipNames = [NSMutableArray new]; //or GC ?
for (i = 0; i <count; i++)
{
EORelationship *property = [classProperties objectAtIndex: i];
if ([property isKindOfClass: relClass]
&& ![property isToMany])
[(NSMutableArray*)_classPropertyToOneRelationshipNames
addObject: [property name]];
}
}
return _classPropertyToOneRelationshipNames;
}
- (id) qualifierForDBSnapshot:(id)param0
{
return [self notImplemented: _cmd]; //TODO
}
- (void) _addAttributesToFetchForRelationshipPath: (NSString*)relPath
atts: (NSMutableDictionary*)attributes
{
NSArray *parts = nil;
EORelationship *rel = nil;
NSAssert([relPath length] > 0, @"Empty relationship path");
//Verify when multi part path and not _relationshipPathIsToMany:path
parts = [relPath componentsSeparatedByString: @"."];
rel = [self relationshipNamed: [parts objectAtIndex: 0]];
if (!rel)
{
NSEmitTODO(); //TODO
//TODO
}
else
{
NSArray *joins = [rel joins];
int count = [joins count];
if (count>0)
{
int i=0;
IMP joinsOAI=NULL;
IMP attributesSOFK=NULL;
for (i = 0; i < count; i++)
{
EOJoin *join = GDL2_ObjectAtIndexWithImpPtr(joins,&joinsOAI,i);
EOAttribute *attribute = [join sourceAttribute];
GDL2_SetObjectForKeyWithImpPtr(attributes,&attributesSOFK,
attribute,[attribute name]);
}
};
}
}
- (NSArray*) dbSnapshotKeys
{
//OK
if (!_dbSnapshotKeys)
{
NSArray *attributesToFetch = [self _attributesToFetch];
EOFLOGObjectLevelArgs(@"EOEntity", @"attributesToFetch=%@",
attributesToFetch);
NSAssert3(!attributesToFetch
|| [attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[attributesToFetch class],
attributesToFetch);
ASSIGN(_dbSnapshotKeys,
[NSArray arrayWithArray: [attributesToFetch
resultsOfPerformingSelector:
@selector(name)]]);
}
return _dbSnapshotKeys;
}
- (NSArray*) flattenedAttributes
{
//OK
NSArray *flattenedAttributes = nil;
NSArray *attributesToFetch = [self _attributesToFetch];
int count = [attributesToFetch count];
NSAssert3(!attributesToFetch
|| [attributesToFetch isKindOfClass: [NSArray class]],
@"entity %@ attributesToFetch is not an NSArray but a %@\n%@",
[self name],
[attributesToFetch class],
attributesToFetch);
if (count>0)
{
int i=0;
IMP atfOAI=NULL;
IMP tAO=NULL;
NSMutableArray* tmpArray
= AUTORELEASE([GDL2_alloc(NSMutableArray) initWithCapacity: count]);
for (i = 0; i < count; i++)
{
EOAttribute *attribute = GDL2_ObjectAtIndexWithImpPtr(attributesToFetch,&atfOAI,i);
if ([attribute isFlattened])
GDL2_AddObjectWithImpPtr(tmpArray,&tAO,attribute);
};
flattenedAttributes=tmpArray;
}
else
flattenedAttributes=GDL2_NSArray;
return flattenedAttributes;
}
@end
@implementation EOEntity (EOEntityPrivateXX)
- (EOExpressionArray*) _parseDescription: (NSString*)description
isFormat: (BOOL)isFormat
arguments: (char*)param2
{
// definition = "(((text(code) || ' ') || upper(abbreviation)) || ' ')";
EOExpressionArray *expressionArray = nil;
const char *s = NULL;
const char *start = NULL;
id objectToken = nil;
id pool = nil;
EOFLOGObjectLevelArgs(@"EOEntity", @"expression=%@", description);
expressionArray = AUTORELEASE([EOExpressionArray new]);
s = [description cString];
if (s)
{
IMP eaAO=NULL;
pool = [NSAutoreleasePool new];
NS_DURING
{
/* Divide the expression string in alternating substrings that obey the
following simple grammar:
I = [a-zA-Z0-9@_#]([a-zA-Z0-9@_.#$])+
O = \'.*\' | \".*\" | [^a-zA-Z0-9@_#]+
S -> I S | O S | nothing
*/
while (s && *s)
{
/* Determines an I token. */
if (isalnum(*s) || *s == '@' || *s == '_' || *s == '#')
{
EOExpressionArray *expr = nil;
start = s;
for (++s; *s; s++)
if (!isalnum(*s) && *s != '@' && *s != '_'
&& *s != '.' && *s != '#' && *s != '$')
break;
objectToken = GDL2_StringWithCStringAndLength(start,
(unsigned)(s - start));
EOFLOGObjectLevelArgs(@"EOEntity", @"objectToken: '%@'",
objectToken);
expr = [self _parsePropertyName: objectToken];
EOFLOGObjectLevelArgs(@"EOEntity", @"expr: '%@'",
expr);
if (expr)
objectToken = expr;
EOFLOGObjectLevelArgs(@"EOEntity", @"addObject I Token: '%@'",
objectToken);
GDL2_AddObjectWithImpPtr(expressionArray,&eaAO,objectToken);
}
/* Determines an O token. */
start = s;
for (; *s && !isalnum(*s) && *s != '@' && *s != '_' && *s != '#';
s++)
{
if (*s == '\'' || *s == '"')
{
char quote = *s;
for (++s; *s; s++)
if (*s == quote)
break;
else if (*s == '\\')
s++; /* Skip the escaped characters */
if (!*s)
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: unterminated character string",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self];
}
}
if (s != start)
{
objectToken = GDL2_StringWithCStringAndLength(start,
(unsigned)(s - start));
EOFLOGObjectLevelArgs(@"EOEntity", @"addObject O Token: '%@'",
objectToken);
GDL2_AddObjectWithImpPtr(expressionArray,&eaAO,objectToken);
}
}
}
NS_HANDLER
{
RETAIN(localException);
NSLog(@"exception in EOEntity _parseDescription:isFormat:arguments:");
NSLog(@"exception=%@", localException);
[pool release];//Release the pool !
AUTORELEASE(localException);
[localException raise];
}
NS_ENDHANDLER;
[pool release];
}
// return nil if expressionArray is empty
if ([expressionArray count] == 0)
expressionArray = nil;
// if expressionArray contains only one element and this element is a expressionArray, use it (otherwise, isFlatten will not be accurate)
else if ([expressionArray count] == 1)
{
id expr = [expressionArray lastObject];
if ([expr isKindOfClass: [EOExpressionArray class]])
expressionArray = expr;
}
EOFLOGObjectLevelArgs(@"EOEntity",
@"expressionArray=%@\nexpressionArray count=%d isFlattened=%s\n",
expressionArray,
[expressionArray count],
([expressionArray isFlattened] ? "YES" : "NO"));
return expressionArray;
}
- (EOExpressionArray*) _parseRelationshipPath: (NSString*)path
{
EOEntity *entity = self;
EOExpressionArray *expressionArray = nil;
NSArray *components = nil;
int i, count = 0;
EOFLOGObjectLevelArgs(@"EOEntity",@"self=%p (name=%@) path=%@",
self,[self name],path);
NSAssert1([path length] > 0, @"Path is empty (%p)", path);
expressionArray = [EOExpressionArray expressionArrayWithPrefix: nil
infix: @"."
suffix: nil];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@",
self, expressionArray);
components = [path componentsSeparatedByString: @"."];
count = [components count];
for (i = 0; i < count; i++)
{
NSString *part = [components objectAtIndex: i];
EORelationship *relationship;
NSAssert1([part length] > 0, @"part is empty (path=%@)", path);
relationship = [entity anyRelationshipNamed: part];
EOFLOGObjectLevelArgs(@"EOEntity", @"part=%@ relationship=%@",
part, relationship);
if (relationship)
{
NSAssert2([relationship isKindOfClass: [EORelationship class]],
@"relationship is not a EORelationship but a %@. relationship:\n%@",
[relationship class],
relationship);
if ([relationship isFlattened])
{
EOExpressionArray *definitionArray=[relationship _definitionArray];
NSDebugMLog(@"entityName=%@ path=%@",[self name],path);
NSDebugMLog(@"relationship=%@",relationship);
NSDebugMLog(@"relationship definitionArray=%@",definitionArray);
// For flattened relationships, we add relationship definition array
[expressionArray addObjectsFromArray:definitionArray];
// Use last relationship to find destinationEntity,...
relationship=[expressionArray lastObject];
}
else
{
[expressionArray addObject: relationship];
}
entity = [relationship destinationEntity];
}
else
{
NSDebugMLog(@"self %p name=%@: relationship \"%@\" used in \"%@\" doesn't exist in entity \"%@\"",
self,
[self name],
part,
path,
[entity name]);
//EOF don't throw exception. But we do !
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: entity name=%@: relationship \"%@\" used in \"%@\" doesn't exist in entity \"%@\"",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
[self name],
part,
path,
[entity name]];
}
}
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@",
self, expressionArray);
// return nil if expressionArray is empty
if ([expressionArray count] == 0)
expressionArray = nil;
// if expressionArray contains only one element and this element is a expressionArray, use it (otherwise, isFlatten will not be accurate)
else if ([expressionArray count] == 1)
{
id expr = [expressionArray lastObject];
if ([expr isKindOfClass: [EOExpressionArray class]])
expressionArray = expr;
}
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@",
self, expressionArray);
return expressionArray;
}
- (id) _parsePropertyName: (NSString*)propertyName
{
EOEntity *entity = self;
EOExpressionArray *expressionArray = nil;
NSArray *components = nil;
int i, count = 0;
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p self name=%@ propertyName=%@",
self, [self name], propertyName);
expressionArray = [EOExpressionArray expressionArrayWithPrefix: nil
infix: @"."
suffix: nil];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@",
self, expressionArray);
components = [propertyName componentsSeparatedByString: @"."];
count = [components count];
for (i = 0; i < count; i++)
{
NSString *part = [components objectAtIndex: i];
EORelationship *relationship = [entity anyRelationshipNamed: part];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p entity name=%@ part=%@ relationship=%@ relationship name=%@",
self, [entity name], part, relationship,
[relationship name]);
if (relationship)
{
NSAssert2([relationship isKindOfClass: [EORelationship class]],
@"relationship is not a EORelationship but a %@. relationship:\n%@",
[relationship class],
relationship);
if ([relationship isFlattened])
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];//TODO
}
else
{
EOFLOGObjectLevelArgs(@"EOEntity",@"self=%p expressionArray addObject=%@ (name=%@)",
self, relationship, [relationship name]);
[expressionArray addObject: relationship];
}
entity = [relationship destinationEntity];
}
else
{
EOAttribute *attribute = [entity anyAttributeNamed: part];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p entity name=%@ part=%@ attribute=%@ attribute name=%@",
self, [entity name], part, attribute,
[attribute name]);
if (attribute)
[expressionArray addObject: attribute];
else if (i < (count - 1))
{
//EOF don't throw exception ? But we do !
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: attribute \"%@\" used in \"%@\" doesn't exist in entity %@",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
propertyName,
part,
entity];
}
}
}
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@",
self, expressionArray);
// return nil if expression is empty
if ([expressionArray count] == 0)
expressionArray = nil;
else if ([expressionArray count] == 1)
expressionArray = [expressionArray objectAtIndex: 0];
EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=\"%@\"",
self, expressionArray);
return expressionArray;
}
@end
@implementation EOEntity (Deprecated)
+ (EOEntity *)entity
{
return AUTORELEASE([[self alloc] init]);
}
+ (EOEntity *)entityWithPropertyList: (NSDictionary *)propertyList
owner: (id)owner
{
return AUTORELEASE([[self alloc] initWithPropertyList: propertyList
owner: owner]);
}
@end
@implementation EOEntityClassDescription
- (id)initWithEntity: (EOEntity *)entity
{
if ((self = [super init]))
{
ASSIGN(_entity, entity);
}
return self;
}
- (void) dealloc
{
//OK
EOFLOGObjectLevelArgs(@"EOEntity", @"Deallocate EOEntityClassDescription %p",
self);
fflush(stdout);
fflush(stderr);
DESTROY(_entity);
[super dealloc];
}
- (NSString *) description
{
return [NSString stringWithFormat: @"<%s %p - Entity: %@>",
object_getClassName(self),
self,
[self entityName]];
}
- (EOEntity *)entity
{
return _entity;
}
- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)name
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];
return nil;
}
- (NSString *)entityName
{
return [_entity name];
}
- (NSArray *)attributeKeys
{
//OK
return [_entity classPropertyAttributeNames];
}
- (void)awakeObject: (id)object
fromFetchInEditingContext: (EOEditingContext *)context
{
//OK
[super awakeObject: object
fromFetchInEditingContext: context];
//nothing to do
}
/**
* Overrides [EOClassDescription-awakeObject:fromInsertionInEditingContext:]
* to initialize the class property relationships. The toMany relationships
* properties are initialized with a mutable array, while toOne relationships
* which propagate the primary key of the object get instantiated with a
* freshly initialzed instance. Whether a relationship is manditory or not
* is irrelevant at this point.
*/
- (void)awakeObject: (id)object
fromInsertionInEditingContext: (EOEditingContext *)context
{
NSArray *relationships;
NSArray *classProperties;
EORelationship *relationship;
int i, count;
IMP relOAI=NULL;
IMP objectSVFK=NULL;
IMP objectTSVFK=NULL;
IMP objectVFK=NULL;
[super awakeObject: object
fromInsertionInEditingContext: context];
relationships = [_entity relationships];
classProperties = [_entity classProperties];
count = [relationships count];
for (i = 0; i < count; i++)
{
relationship = GDL2_ObjectAtIndexWithImpPtr(relationships,&relOAI,i);
if ([classProperties containsObject: relationship])
{
if ([relationship isToMany])
{
NSString *name = [relationship name];
id relationshipValue =
GDL2_StoredValueForKeyWithImpPtr(object,&objectSVFK,name);
/* We put a value only if there's not already one */
if (relationshipValue == nil)
{
/* [Ref: Assigns empty arrays to to-many
relationship properties of newly inserted
enterprise objects] */
GDL2_TakeStoredValueForKeyWithImpPtr(object,&objectTSVFK,
[EOCheapCopyMutableArray array],
name);
}
}
else
{
if ([relationship propagatesPrimaryKey])
{
NSString *name = [relationship name];
id relationshipValue
= GDL2_ValueForKeyWithImpPtr(object,&objectVFK,name);
if (relationshipValue == nil)
{
EOEntity *destinationEntity
= [relationship destinationEntity];
EOClassDescription *classDescription
= [destinationEntity classDescriptionForInstances];
relationshipValue
= [classDescription createInstanceWithEditingContext:
context
globalID: nil
zone: NULL];
[object addObject: relationshipValue
toBothSidesOfRelationshipWithKey: name];
[context insertObject: relationshipValue];
}
}
}
}
}
}
- (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey
{
EOClassDescription *cd = nil;
EOEntity *destEntity = nil;
EORelationship *rel = nil;
EOFLOGObjectLevelArgs(@"EOEntity", @"detailKey=%@", detailKey);
EOFLOGObjectLevelArgs(@"EOEntity", @"_entity name=%@", [_entity name]);
rel = [_entity relationshipNamed: detailKey];
EOFLOGObjectLevelArgs(@"EOEntity", @"rel=%@", rel);
destEntity = [rel destinationEntity];
EOFLOGObjectLevelArgs(@"EOEntity", @"destEntity name=%@", [destEntity name]);
cd = [destEntity classDescriptionForInstances];
EOFLOGObjectLevelArgs(@"EOEntity", @"cd=%@", cd);
return cd;
}
- (id)createInstanceWithEditingContext: (EOEditingContext *)editingContext
globalID: (EOGlobalID *)globalID
zone: (NSZone *)zone
{
id obj = nil;
Class objectClass;
NSAssert1(_entity, @"No _entity in %@", self);
objectClass = [_entity classForObjectWithGlobalID: (EOKeyGlobalID*)globalID];
NSAssert2(objectClass, @"No objectClass for globalID=%@. EntityName=%@",
globalID, [_entity name]);
if (objectClass)
{
obj = AUTORELEASE([[objectClass allocWithZone:zone]
initWithEditingContext: editingContext
classDescription: self
globalID: globalID]);
}
return obj;
}
- (NSFormatter *)defaultFormatterForKey: (NSString *)key
{
[self notImplemented: _cmd];
return nil;
}
- (NSFormatter *)defaultFormatterForKeyPath: (NSString *)keyPath
{
[self notImplemented: _cmd];
return nil; //TODO
}
- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey
{
EORelationship *rel = nil;
EODeleteRule deleteRule = 0;
rel = [_entity relationshipNamed: relationshipKey];
EOFLOGObjectLevelArgs(@"EOEntity", @"relationship %p=%@", rel, rel);
deleteRule = [rel deleteRule];
EOFLOGObjectLevelArgs(@"EOEntity", @"deleteRule=%d", (int)deleteRule);
return deleteRule;
}
- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey
{
//Ayers: Review
//Near OK
NSString *inverseName = nil;
EORelationship *relationship = [_entity relationshipNamed: relationshipKey];
//EOEntity *parentEntity = [_entity parentEntity];
//TODO what if parentEntity
EORelationship *inverseRelationship = [relationship inverseRelationship];
if (inverseRelationship)
{
EOEntity *inverseEntity = [inverseRelationship entity];
NSArray *classPropertieNames = [inverseEntity classPropertyNames];
inverseName = [inverseRelationship name];
if (![classPropertieNames containsObject: inverseName])
inverseName = nil;
}
return inverseName;
}
- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString*)relationshipKey
{
//OK
return [[_entity relationshipNamed: relationshipKey] ownsDestination];
}
- (NSArray *)toManyRelationshipKeys
{
//OK
return [_entity classPropertyToManyRelationshipNames];
}
- (NSArray *)toOneRelationshipKeys
{
//OK
return [_entity classPropertyToOneRelationshipNames];
}
- (EORelationship *)relationshipNamed: (NSString *)relationshipName
{
//OK
return [_entity relationshipNamed:relationshipName];
}
- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipName
{
return [_entity anyRelationshipNamed:relationshipName];
}
- (NSException *) validateObjectForDelete: (id)object
{
return [_entity validateObjectForDelete:object];
}
- (NSException *)validateObjectForSave: (id)object
{
return nil; //Does Nothing ? works is done in record
}
- (NSException *)validateValue: (id *)valueP
forKey: (NSString *)key
{
NSException *exception = nil;
EOAttribute *attr;
EORelationship *relationship;
NSAssert(valueP, @"No value pointer");
attr = [_entity attributeNamed: key];
if (attr)
{
exception = [attr validateValue: valueP];
}
else
{
relationship = [_entity relationshipNamed: key];
if (relationship)
{
exception = [relationship validateValue: valueP];
}
else
{
NSEmitTODO(); //TODO
}
}
return exception;
}
@end
@implementation EOEntityClassDescription (GDL2Extenstions)
/** returns a new autoreleased mutable dictionary to store properties
returns nil if there's no key in the instanceDictionaryInitializer
**/
- (EOMutableKnownKeyDictionary*) dictionaryForInstanceProperties
{
EOMutableKnownKeyDictionary* dict = nil;
NSAssert(_entity,@"No entity");
dict = [_entity _dictionaryForInstanceProperties];
return dict;
}
@end
@implementation EOEntityClassDescription (Deprecated)
+ (EOEntityClassDescription*)entityClassDescriptionWithEntity: (EOEntity *)entity
{
return AUTORELEASE([[self alloc] initWithEntity: entity]);
}
@end
@implementation NSString (EODatabaseNameConversion)
+ (NSString *)nameForExternalName: (NSString *)externalName
separatorString: (NSString *)separatorString
initialCaps: (BOOL)initialCaps
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];
return nil;
}
+ (NSString *)externalNameForInternalName: (NSString *)internalName
separatorString: (NSString *)separatorString
useAllCaps: (BOOL)allCaps
{
NSEmitTODO(); //TODO
[self notImplemented: _cmd];
return nil;
}
@end
@implementation NSObject (EOEntity)
/** should returns a set of property names to exclude from entity
instanceDictionaryInitializer **/
+ (NSArray *)_instanceDictionaryInitializerExcludedPropertyNames
{
// default implementation returns nil
return nil;
}
@end