mirror of
https://github.com/gnustep/libs-gdl2.git
synced 2025-02-15 16:10:46 +00:00
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
4406 lines
121 KiB
Objective-C
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
|