diff --git a/ChangeLog b/ChangeLog index 0bcdb79..c812a8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,112 @@ +2014-04-26 Manuel Guesdon + * EOAccess/EOAdaptorChannel.m + call delegate -adaptorChannel:willPerformOperations: + * EOAccess/EODatabaseContext.m: + propagate delegate to channel + fix objectsForSourceGlobalID:relationshipName:editingContext: + isToManyToOne case + * EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m: + call delegate methods + adding assert to catch bad dates + use adaptor -primaryKeySequenceNameFormat + * EOAccess/EOrelationship.m + implement -isParentRelationship + verify/clean -isReciprocalToRelationship: + implement -qualifierWithSourceRow: + small fix on -removeJoin: + use batch faulting when -setNumberOfToManyFaultsToBatchFetch: + improve -setIsMandatory + fix exception message -validateValue: + clean -_intermediateAttributes + clean -isMultiHop + implement -primaryKeyForTargetRowFromSourceDBSnapshot: + implement -_setSourceToDestinationKeyMap: + implement -qualifierForDBSnapshot: + fix/implement -isToManyToOne + fix -foreignKeyInDestination + implement -isPropagatesPrimaryKeyPossible + implement -qualifierOmittingAuxiliaryQualifierWithSourceRow + implement -auxiliaryQualifier + implement -setAuxiliaryQualifier: + clean -_sourceRowToForeignKeyMapping + add comment in -_sourceAttributeNames + fix -joinForAttribute: + fix -_flushCache + fix -_stringFromDeleteRule: + implement -_rightSideKeyMap + implement -_leftSideKeyMap + implement -_substitutionRelationshipForRow: + fix -isFlattened + remove _componentRelationships + * EOAccess/EORelationship.h + remove _componentRelationships + * EOAccess/EOEntityPriv.[hm] + fix _hiddenRelationships return type + * EOAccess/Entity.m: + implement -_mapAttribute:toDestinationAttributeInLastComponentOfRelationshipPath: + implement -_inverseRelationshipPathForPath: + implement -_relationshipPathHasIdenticalKeys: + rewrite & fix -_keyMapForRelationshipPath: + rewrite & fix -_keyMapForIdenticalKeyRelationshipPath: + implement -valueForSQLExpression: + fix -validateObjectForDelete: + implement -qualifierForDBSnapshot: + fix -_addAttributesToFetchForRelationshipPath:atts: + fix -_parsePropertyName: + implement -fetchSpecificationNamed: + implement +externalNameForInternalName:separatorString:useAllCaps: + implement +nameForExternalName:separatorString:initialCaps: + implement -stringByMarkingUpcaseTransitionsWithDelimiter + implement -snapshotKeyForAttributeName: + implement -_flattenedAttNameToSnapshotKeyMapping + fix -_attributesToFetch + fix -_attributesToSave + * EOAccess/Entity.h: + fix _inverseRelationshipPathForPath: + fix -_relationshipPathHasIdenticalKey: + add _flgas.isSingleTableEntity + * EOAccess/EntityPriv.h: + fix -qualifierForDBSnapshot: + * EOAccess/EOPrivate.[hm] + add GDL2_EORelationshipClass + add GDL2_EOEntityClass + * EOAccess/EOModel.m: + cache [EOEntity class] + add -propertyListForEntity:name: to enable subclassing + * EOAccess/EOAttribute.m + fix -isFlattened + implement -targetAttribute + implement -relationshipPath + fix -_setDefinitionWithoutFlushingCaches: + fix -_normalizeDefinition:path: + fix -isReadOnly + implement -_setOverrideForKeyEnum: + implement -_hasAnyOverrides + implement -_isKeyEnumOverriden: + implement -_prototypeKeys + fix -initWithPropertyList:owner: + fix -readFormat + fix -writeFormat + fix -scale + fix -precision + fix -width + fix -allowsNull + fix -isReadOnly + fix -valueClassName + fix -externalType + fix -valueType + implement -_setValuesFromTargetAttribute + * EOAccess/EOAttribute.h + declare -targetAttribute + declare -relationshipPath + * EOAccess/EOAttributePriv.h + declare EOAttributeProtoOverrideBits enum + fix method arguments + declare _setValuesFromTargetAttribute() + * EOAccess/EOExpressionArray.h + declare -_isPropertyPath + * EOAccess/EOExpressionArray.m + implement -_isPropertyPath 2014-03-09 Sebastian Reitenbach * EOControl/EOCheapArray.m * EOControl/EODebug.m diff --git a/EOAccess/EOAdaptorChannel.m b/EOAccess/EOAdaptorChannel.m index 51ffedf..32220f3 100644 --- a/EOAccess/EOAdaptorChannel.m +++ b/EOAccess/EOAdaptorChannel.m @@ -599,6 +599,10 @@ prepareInsertExpressionWithRow:changedValues int i = 0; int count = 0; + if (_delegateRespondsTo.willPerformOperations) + adaptorOperations=[_delegate adaptorChannel: self + willPerformOperations: adaptorOperations]; + count=[adaptorOperations count]; for(i = 0; i < count; i++) diff --git a/EOAccess/EOAttribute.h b/EOAccess/EOAttribute.h index f7da6a9..dce9054 100644 --- a/EOAccess/EOAttribute.h +++ b/EOAccess/EOAttribute.h @@ -68,7 +68,7 @@ typedef enum { EOInOutParameter } EOParameterDirection; - +#define EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT 18 @interface EOAttribute : NSObject { NSString *_name; @@ -94,7 +94,7 @@ typedef enum { unsigned int allowsNull:1; unsigned int isReadOnly:1; unsigned int isParentAnEOEntity:1; - unsigned int protoOverride:18; + unsigned int protoOverride:EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT; unsigned int isAttributeValueInitialized:1; unsigned int unused : 10; } _flags; @@ -107,6 +107,7 @@ typedef enum { NSString *_docComment; id _parent; /* unretained */ + NSString *_prototypeName; EOAttribute *_prototype; EOExpressionArray *_definitionArray; EOAttribute *_realAttribute; // if the attribute is flattened //Not in EOF ! @@ -166,8 +167,6 @@ typedef enum { - (NSString *)docComment; -- (BOOL)isKeyDefinedByPrototype: (NSString *)key; - /** * Returns YES if the attribute references aProperty, NO otherwise. */ @@ -176,6 +175,12 @@ typedef enum { - (void)setParent: (id)parent; +- (void)setEntity:(EOEntity*)entity; + +- (NSString*)relationshipPath; + +- (EOAttribute*)targetAttribute; + @end @@ -219,8 +224,8 @@ typedef enum { - (void)setDocComment: (NSString *)docComment; -- (id)_normalizeDefinition: (EOExpressionArray *)definition - path: (id)path; +- (id)_normalizeDefinition: (id)definition + path: (NSArray *)path; @end diff --git a/EOAccess/EOAttribute.m b/EOAccess/EOAttribute.m index 9b0b4e5..a654ee9 100644 --- a/EOAccess/EOAttribute.m +++ b/EOAccess/EOAttribute.m @@ -64,6 +64,7 @@ RCS_ID("$Id$") #include #include #include +#include #include #include @@ -79,6 +80,7 @@ RCS_ID("$Id$") #include "EOEntityPriv.h" #include "EOAttributePriv.h" +static NSArray* staticPrototypeKeys=nil; @implementation EOAttribute @@ -88,7 +90,21 @@ RCS_ID("$Id$") if (!initialized) { initialized=YES; - + //Order is important (Cf overide ProtoOverrideBits) + ASSIGN(staticPrototypeKeys, + ([NSArray arrayWithObjects: + @"externalType", @"columnName", @"readOnly", + @"valueClassName", @"valueType", @"width", + @"precision", @"scale", @"writeFormat", + @"readFormat",@"userInfo", @"serverTimeZone", + @"valueFactoryMethodName", + @"adaptorValueConversionMethodName", + @"factoryMethodArgumentType", @"allowsNull", + @"parameterDirection", @"_internalInfo", nil])); + NSAssert(EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT==EOAttributeProtoOverrideBits__count, + @"Mismatch ProtoOverrideBits count"); + NSAssert(EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT==[staticPrototypeKeys count], + @"Mismatch ProtoOverrideBits keys count"); GDL2_EOAccessPrivateInit(); } } @@ -105,11 +121,12 @@ RCS_ID("$Id$") { EOAttribute * attr = [[[self alloc] init] autorelease]; - if (attr) { - [attr setName: def]; - [attr setParent: parent]; - [attr setDefinition: def]; - } + if (attr) + { + [attr setName: def]; + [attr setParent: parent]; + [attr setDefinition: def]; + } return attr; } @@ -124,13 +141,24 @@ RCS_ID("$Id$") // set this first so the name can validate against the parent. [self setParent: owner]; + [self setName: [propertyList objectForKey: @"name"]]; + //Next set prototyName so prototype override can work + tmpString = [propertyList objectForKey: @"prototypeName"]; + if (tmpString) + { + EOAttribute *attr = [[_parent model] prototypeAttributeNamed: tmpString]; + + if (attr) + [self setPrototype: attr]; + } + [self setExternalType: [propertyList objectForKey: @"externalType"]]; tmpString = [propertyList objectForKey: @"allowsNull"]; - if (tmpString) - [self setAllowsNull: [tmpString boolValue]]; + if (tmpString || _prototypeName==nil) + [self setAllowsNull: tmpString!=nil && [tmpString boolValue]]; [self setValueType: [propertyList objectForKey: @"valueType"]]; [self setValueClassName: [propertyList objectForKey: @"valueClassName"]]; @@ -251,33 +279,26 @@ RCS_ID("$Id$") - (void)awakeWithPropertyList: (NSDictionary *)propertyList { - //Seems OK - NSString *definition; - NSString *columnName; - NSString *tmpString; - - definition = [propertyList objectForKey: @"definition"]; - + NSString *definition = [propertyList objectForKey: @"definition"]; if (definition) - [self setDefinition: definition]; - - columnName = [propertyList objectForKey: @"columnName"]; - - if (columnName) - [self setColumnName: columnName]; - - tmpString = [propertyList objectForKey: @"prototypeName"]; - - if (tmpString) { - EOAttribute *attr = [[_parent model] prototypeAttributeNamed: tmpString]; - - if (attr) - [self setPrototype: attr]; + [self _setDefinitionWithoutFlushingCaches: definition]; + [_parent _setIsEdited]; + } + else + { + NSString *columnName=[propertyList objectForKey: @"columnName"]; + if (columnName) + [self setColumnName: columnName]; + else + { + NSString *externalName=[propertyList objectForKey: @"externalName"]; + if ([externalName isKindOfClass:[NSString class]]) + [self setColumnName: externalName]; + else if ([externalName isKindOfClass:[NSDictionary class]]) + ASSIGN(_definitionArray,[self _objectForPList:(NSDictionary*)externalName]); + } } - - EOFLOGObjectLevelArgs(@"gsdb", @"Attribute %@ awakeWithPropertyList:%@", - self, propertyList); } - (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList @@ -303,7 +324,7 @@ RCS_ID("$Id$") if (_valueFactoryMethodName) { - NSString *methodArg; + NSString *methodArg = nil; [propertyList setObject: _valueFactoryMethodName forKey: @"valueFactoryMethodName"]; @@ -371,6 +392,7 @@ RCS_ID("$Id$") - (void)dealloc { DESTROY(_name); + DESTROY(_prototypeName); DESTROY(_prototype); DESTROY(_columnName); DESTROY(_externalType); @@ -454,27 +476,17 @@ RCS_ID("$Id$") - (NSString *)definition { - NSString *definition = nil; - - definition = [_definitionArray valueForSQLExpression: nil]; - - return definition; + return [_definitionArray valueForSQLExpression: nil]; } - (NSString *)readFormat { - if (_readFormat) - return _readFormat; - - return [_prototype readFormat]; + return _readFormat; } - (NSString *)writeFormat { - if (_writeFormat) - return _writeFormat; - - return [_prototype writeFormat]; + return _writeFormat; } - (NSDictionary *)userInfo @@ -482,6 +494,11 @@ RCS_ID("$Id$") return _userInfo; } +- (NSDictionary *)internalInfo +{ + return _internalInfo; +} + - (NSString *)docComment { return _docComment; @@ -496,35 +513,17 @@ RCS_ID("$Id$") */ - (int)scale { - if (_scale) - return _scale; - - if (_prototype) - return [_prototype scale]; - - return 0; + return _scale; } - (unsigned)precision { - if (_precision) - return _precision; - - if (_prototype) - return [_prototype precision]; - - return 0; + return _precision; } - (unsigned)width { - if (_width) - return _width; - - if (_prototype) - return [_prototype width]; - - return 0; + return _width; } - (id)parent @@ -549,18 +548,7 @@ RCS_ID("$Id$") - (BOOL)allowsNull { - if (_flags.allowsNull) - return _flags.allowsNull; - - if (_prototype) - return [_prototype allowsNull]; - - return NO; -} - -- (BOOL)isKeyDefinedByPrototype:(NSString *)key -{ - return NO; // TODO + return _flags.allowsNull; } - (EOStoredProcedure *)storedProcedure @@ -573,14 +561,12 @@ RCS_ID("$Id$") - (BOOL)isReadOnly { -//call isDerived if (_flags.isReadOnly) - return _flags.isReadOnly; - - if (_prototype) - return [_prototype isReadOnly]; - - return NO; + return YES; + else if ([self isDerived] && ![self isFlattened]) + return YES; + else + return NO; } /** @@ -592,11 +578,7 @@ RCS_ID("$Id$") **/ - (BOOL)isDerived { - //Seems OK - if(_definitionArray) - return YES; - - return NO; + return (_definitionArray==nil ? NO : YES); } @@ -608,12 +590,28 @@ RCS_ID("$Id$") **/ - (BOOL)isFlattened { - BOOL isFlattened = NO; - // Seems OK - - if(_definitionArray) - isFlattened = [_definitionArray isFlattened]; - + //TODO cahe result ? + BOOL isFlattened=NO; + if (_definitionArray!=nil) + { + int definitionArrayCount=[_definitionArray count]; + if (definitionArrayCount>=2) + { + BOOL cont=YES; + int i=0; + for(i=0;i0) + [s appendString:@"."]; + [s appendString:[[_definitionArray objectAtIndex:i] name]]; + } + return [NSString stringWithString:s]; + } + else + return nil; +} + +- (EOAttribute*)targetAttribute +{ + if([self isFlattened]) + return [_definitionArray lastObject]; + else + return nil; } @end @@ -735,11 +765,8 @@ RCS_ID("$Id$") NSString *value=nil; if (sqlExpression != nil) - { - return [sqlExpression sqlStringForAttribute:self]; - } - - if (_definitionArray) + value=[sqlExpression sqlStringForAttribute:self]; + else if (_definitionArray) value = [_definitionArray valueForSQLExpression: sqlExpression]; else value = [self name]; @@ -756,8 +783,11 @@ RCS_ID("$Id$") const char *p, *s = [name cString]; int exc = 0; - if ([_name isEqual:name]) return nil; - if (!name || ![name length]) exc++; + if ([_name isEqual:name]) + return nil; + + if (!name || ![name length]) + exc++; if (!exc) { @@ -832,83 +862,143 @@ RCS_ID("$Id$") { if ([_name isEqual: name]==NO) { - NSString *oldName = nil; [[self validateName: name] raise]; - oldName = AUTORELEASE(RETAIN(_name)); + AUTORELEASE(RETAIN(_name)); [self willChange]; ASSIGNCOPY(_name, name); if (_flags.isParentAnEOEntity) - { - [_parent _setIsEdited]; - } + [_parent _setIsEdited]; } - } - (void)setPrototype: (EOAttribute *)prototype { - [self willChange]; - ASSIGN(_prototype, prototype); + if(_prototype != prototype + && ![_prototypeName isEqualToString:[prototype name]]) + { + [self willChange]; + _flags.protoOverride = 0; + ASSIGN(_prototypeName, [prototype name]); + if (_prototypeName != nil) + { + ASSIGN(_prototype,[[self _parentModel]prototypeAttributeNamed:_prototypeName]); + if(_prototype == nil) + ASSIGN(_prototype,prototype); + [self _updateFromPrototype]; + } + else + { + DESTROY(_prototype); + }; + }; } - (void)setColumnName: (NSString *)columnName { - //seems OK - [self willChange]; + if (columnName!=nil + || _columnName!=nil) + { + [self willChange]; - ASSIGNCOPY(_columnName, columnName); - DESTROY(_definitionArray); - - [_parent _setIsEdited]; - [self _setOverrideForKeyEnum:1]; + ASSIGNCOPY(_columnName, columnName); + DESTROY(_definitionArray); + + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_columnName]; + } } -- (void)_setDefinitionWithoutFlushingCaches: (NSString *)definition +-(id)_normalizeDefinition: (id)definition + path: (NSArray*)path { - EOExpressionArray *expressionArray=nil; - - [self willChange]; - expressionArray = [_parent _parseDescription: definition - isFormat: NO - arguments: NULL]; - - expressionArray = [self _normalizeDefinition: expressionArray - path: nil]; - /* - //TODO finish - l un est code - - entity primaryKeyAttributes (code) - ?? - - [self _removeFromEntityArray:code selector:setPrimaryKeyAttributes: - */ - - ASSIGN(_definitionArray, expressionArray); + id result=nil; + if ([definition isKindOfClass:[NSString class]]) + result=definition; + else if ([definition isKindOfClass:GDL2_EOAttributeClass]) + { + EOAttribute* attribute = (EOAttribute*)definition; + if (attribute == self) + result=nil; + else + { + if ([attribute isDerived]) + { + result = [self _normalizeDefinition:[attribute _definitionArray] + path:path]; + } + else if ([path count] == 0) + { + result = attribute; + } + else + { + EOExpressionArray* exprArray = [EOExpressionArray expressionArray]; + [exprArray setInfix:@"."]; + if (path!=nil) + [exprArray addObjectsFromArray:path]; + [exprArray addObject:attribute]; + result = exprArray; + } + } + } + else if ([(EOExpressionArray*)definition _isPropertyPath]) + { + int count = [(EOExpressionArray*)definition count]; + int i=0; + EOExpressionArray* exprArray = [EOExpressionArray expressionArray]; + [exprArray setInfix:@"."]; + if (path!=nil) + [exprArray addObjectsFromArray:path]; + + for(i=0; i < count-1; i++) + [exprArray addObject:[(EOExpressionArray*)definition objectAtIndex:i]]; + + EOAttribute* attribute = [(EOExpressionArray*)definition lastObject]; + if ([attribute isDerived]) + { + result=[self _normalizeDefinition:[attribute _definitionArray] + path:exprArray]; + } + else + { + [exprArray addObject:attribute]; + result = exprArray; + } + } + else + { + int count = [(EOExpressionArray*)definition count]; + int i=0; + EOExpressionArray* exprArray = [EOExpressionArray expressionArray]; + for(i = 0; i < count; i++) + { + id aDef = [self _normalizeDefinition:[(EOExpressionArray*)definition objectAtIndex:i] + path:path]; + if (aDef == nil) + { + result=nil; + break; + } + else if ([aDef isKindOfClass:[EOExpressionArray class]] + && ![(EOExpressionArray*)aDef _isPropertyPath]) + { + int aDefCount = [(EOExpressionArray*)aDef count]; + int j=0; + for(j=0;jSets the definition of a derived attribute.

@@ -922,52 +1012,62 @@ return nexexp */ - (void)setDefinition:(NSString *)definition { - if(definition) + if (definition!=nil + || _definitionArray!=nil) { [self willChange]; [self _setDefinitionWithoutFlushingCaches: definition]; - DESTROY(_columnName); [_parent _setIsEdited]; } } - (void)setReadOnly: (BOOL)yn { - if(!yn && ([self isDerived] && ![self isFlattened])) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p: cannot set to NO while the attribute is derived but not flattened.", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self]; - - [self willChange]; - _flags.isReadOnly = yn; + if (yn!=_flags.isReadOnly) + { + if(!yn && ([self isDerived] && ![self isFlattened])) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p: cannot set to NO while the attribute is derived but not flattened.", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + [self willChange]; + _flags.isReadOnly = yn; + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_readOnly]; + } } - (void)setExternalType: (NSString *)type { - //OK - [self willChange]; + if (_externalType==nil + || ![_externalType isEqualToString:type]) + { + [self willChange]; - ASSIGNCOPY(_externalType, type); - - [_parent _setIsEdited]; - [self _setOverrideForKeyEnum: 0];//TODO + ASSIGNCOPY(_externalType, type); + + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_externalType]; + } } - (void)setValueType: (NSString *)type { - //OK - [self willChange]; + if (_valueType==nil + || ![_valueType isEqualToString:type]) + { + [self willChange]; - ASSIGNCOPY(_valueType, type); - - if ([_valueType length]==1) - _valueTypeCharacter = [_valueType characterAtIndex:0]; - else - _valueTypeCharacter = '\0'; - - [self _setOverrideForKeyEnum: 4];//TODO + ASSIGNCOPY(_valueType, type); + + if ([_valueType length]==1) + _valueTypeCharacter = [_valueType characterAtIndex:0]; + else + _valueTypeCharacter = '\0'; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_valueType]; + } } - (void)setValueClassName: (NSString *)name @@ -980,53 +1080,66 @@ return nexexp _flags.isAttributeValueInitialized = NO; - [self _setOverrideForKeyEnum: 3];//TODO + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_valueClassName]; } - (void)setWidth: (unsigned)length { [self willChange]; _width = length; + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_width]; } - (void)setPrecision: (unsigned)precision { [self willChange]; _precision = precision; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_precision]; } - (void)setScale: (int)scale { [self willChange]; _scale = scale; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_scale]; } - (void)setAllowsNull: (BOOL)allowsNull { - //OK - [self willChange]; + if (allowsNull!=_flags.allowsNull) + { + [self willChange]; - _flags.allowsNull = allowsNull; - - [self _setOverrideForKeyEnum: 15];//TODO + _flags.allowsNull = allowsNull; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_allowsNull]; + } } - (void)setWriteFormat: (NSString *)string { [self willChange]; ASSIGNCOPY(_writeFormat, string); + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_writeFormat]; } - (void)setReadFormat: (NSString *)string { [self willChange]; ASSIGNCOPY(_readFormat, string); + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_readFormat]; } - (void)setParameterDirection: (EOParameterDirection)parameterDirection { [self willChange]; _parameterDirection = parameterDirection; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_parameterDirection]; } - (void)setUserInfo: (NSDictionary *)dictionary @@ -1037,7 +1150,7 @@ return nexexp ASSIGN(_userInfo, dictionary); [_parent _setIsEdited]; - [self _setOverrideForKeyEnum: 10];//TODO + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_userInfo]; } - (void)setInternalInfo: (NSDictionary *)dictionary @@ -1046,7 +1159,7 @@ return nexexp [self willChange]; ASSIGN(_internalInfo, dictionary); [_parent _setIsEdited]; - [self _setOverrideForKeyEnum: 10]; //TODO + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_internalInfo]; } - (void)setDocComment: (NSString *)docComment @@ -1128,6 +1241,8 @@ return nexexp { [self willChange]; ASSIGN(_serverTimeZone, tz); + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_serverTimeZone]; } @end @@ -1152,7 +1267,8 @@ return nexexp NSData *value = nil; Class valueClass = [self _valueClass]; - if (valueClass != Nil && valueClass != GDL2_NSDataClass) + if (valueClass != Nil + && valueClass != GDL2_NSDataClass) { switch (_argumentType) { @@ -1161,7 +1277,7 @@ return nexexp //For efficiency reasons, the returned value is NOT autoreleased ! value = [GDL2_alloc(NSData) initWithBytes: bytes length: length]; - // If we have a value factiry method, call it to get the final value + // If we have a value factory method, call it to get the final value if(_valueFactoryMethod != NULL) { NSData* tmp = value; @@ -1261,7 +1377,7 @@ return nexexp length: length encoding: encoding]; - // If we have a value factiry method, call it to get the final value + // If we have a value factory method, call it to get the final value if(_valueFactoryMethod != NULL) { value = [((id)valueClass) performSelector: _valueFactoryMethod @@ -1593,6 +1709,8 @@ See also: -setFactoryMethodArgumentType: [self willChange]; ASSIGNCOPY(_valueFactoryMethodName, factoryMethodName); _valueFactoryMethod = NSSelectorFromString(_valueFactoryMethodName); + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_valueFactoryMethodName]; } /** @@ -1609,6 +1727,8 @@ See also: -setFactoryMethodArgumentType: _adaptorValueConversionMethod = NSSelectorFromString(_adaptorValueConversionMethodName); + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_adaptorValueConversionMethodName]; } /** Set the type of argument needed by the factoryMethod. @@ -1631,6 +1751,8 @@ See also: -setValueFactoryMethodName:, -factoryMethodArgumentType { [self willChange]; _argumentType = argumentType; + + [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_factoryMethodArgumentType]; } @end @@ -1935,42 +2057,228 @@ More details: return valueTypeCharacter; }; +- (void)_setDefinitionWithoutFlushingCaches: (NSString *)definition +{ + if (_parent != nil) + { + [self willChange]; + DESTROY(_columnName); + if (definition==nil) + { + DESTROY(_definitionArray); + } + else + { + EOExpressionArray* exprArray = [_parent _parseDescription: definition + isFormat: NO + arguments: NULL]; + if (exprArray!=nil) + { + if (![exprArray isKindOfClass:[EOExpressionArray class]]) + exprArray=[EOExpressionArray arrayWithObject:exprArray]; + exprArray = [self _normalizeDefinition: exprArray + path: nil]; + } + ASSIGN(_definitionArray,exprArray); + [self _removeFromEntityArray:[_parent primaryKeyAttributes] + selector:@selector(setPrimaryKeyAttributes:)]; + } + } +} + +- (EOModel*)_parentModel +{ + return [_parent model]; +} + +- (void)_removeFromEntityArray:(NSArray*)entityArray + selector:(SEL)setSelector +{ + if ([entityArray indexOfObject:self]!=NSNotFound) + { + NSMutableArray* a = AUTORELEASE([entityArray mutableCopy]); + [a removeObjectIdenticalTo:self]; + [[self entity] performSelector:setSelector + withObject:a]; + } +} + +-(EOExpressionArray*)_objectForPList:(NSDictionary*)pList +{ + EOExpressionArray* result=nil; + if ([pList isKindOfClass:[NSString class]]) + result=(EOExpressionArray*)pList; + else if(![pList isKindOfClass:[NSDictionary class]]) + result=nil; + else + { + NSDictionary* pListDict = (NSDictionary*)pList; + NSString* tmpString=nil; + + tmpString=[pListDict objectForKey:@"name"]; + if (tmpString!=nil) + result=[[self entity] _parsePropertyName:tmpString]; + else + { + tmpString=[pListDict objectForKey:@"path"]; + if (tmpString!=nil) + result=[[self entity]_parsePropertyName:tmpString]; + else + { + NSArray* array=[pListDict objectForKey:@"array"]; + if (array==nil) + result=nil; + else + { + int count = [array count]; + EOExpressionArray* exprArray = [EOExpressionArray expressionArray]; + + tmpString=[pListDict objectForKey:@"prefix"]; + if (tmpString!=nil) + [exprArray setPrefix:tmpString]; + + tmpString=[pListDict objectForKey:@"infix"]; + if (tmpString!=nil) + [exprArray setInfix:tmpString]; + + tmpString=[pListDict objectForKey:@"suffix"]; + if (tmpString!=nil) + [exprArray setSuffix:tmpString]; + + if (count>0) + { + int i=0; + for(i=0;i #include #endif +#include #include #include @@ -81,6 +82,7 @@ RCS_ID("$Id$") #include #include #include +#include #include "EOPrivate.h" #include "EOEntityPriv.h" @@ -556,7 +558,6 @@ NSString *EONextPrimaryKeyProcedureOperation = @"EONextPrimaryKeyProcedureOperat - (id) init { - //OK if ((self = [super init])) { _attributes = [NSMutableArray new]; @@ -591,9 +592,9 @@ static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL select performSelectorOnArrayWithEachObjectOfClass(_subEntities, @selector(_setParentEntity:), nil, [EOEntity class]); performSelectorOnArrayWithEachObjectOfClass(_attributes, @selector(setParent:), - nil, [EOAttribute class]); + nil, GDL2_EOAttributeClass); performSelectorOnArrayWithEachObjectOfClass(_relationships, @selector(setEntity:), - nil, [EORelationship class]); + nil, GDL2_EORelationshipClass); if (_classDescription) [[EOClassDescription class] invalidateClassDescriptionCache]; @@ -607,6 +608,7 @@ static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL select DESTROY(_attributesByName); DESTROY(_attributesToFetch); DESTROY(_attributesToSave); + DESTROY(_flattenedAttNameToSnapshotKeyMapping); DESTROY(_attributesUsedForLocking); DESTROY(_classDescription); DESTROY(_classForInstances); @@ -980,7 +982,7 @@ static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL select { NSDictionary *relPList = [relationshipPLists objectAtIndex: i]; - if ([relPList isKindOfClass: [EORelationship class]]) + if ([relPList isKindOfClass: GDL2_EORelationshipClass]) continue; { @@ -1445,7 +1447,7 @@ static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL select id thePropertyName; if (!([property isKindOfClass: GDL2_EOAttributeClass] - || [property isKindOfClass: [EORelationship class]])) + || [property isKindOfClass: GDL2_EORelationshipClass])) return NO; thePropertyName = [(EOAttribute *)property name]; @@ -2750,9 +2752,8 @@ createInstanceWithEditingContext:globalID:zone: [self notImplemented: _cmd]; } -- (NSArray*) _hiddenRelationships +- (NSMutableArray*) _hiddenRelationships { - //OK if (!_hiddenRelationships) _hiddenRelationships = [NSMutableArray new]; @@ -2761,7 +2762,6 @@ createInstanceWithEditingContext:globalID:zone: - (NSArray*) _propertyNames { - //OK NSMutableArray *propertyNames = nil; NSArray *attributes = [self attributes]; NSArray *attributeNames = [attributes resultsOfPerformingSelector: @@ -2776,36 +2776,51 @@ createInstanceWithEditingContext:globalID:zone: return propertyNames; } -- (id) _flattenAttribute: (id)param0 - relationshipPath: (id)param1 - currentAttributes: (id)param2 +- (EOAttribute*) _flattenAttribute: (EOAttribute*)attribute + relationshipPath: (NSString*)relationshipPath + currentAttributes: (NSDictionary*)currentAttributes { - //TODO - return [self notImplemented: _cmd]; + EOAttribute* flattenAttribute=nil; + + //Find first available attribute name like NeededByEOF%d + NSMutableString* aName = [NSMutableString stringWithCapacity:14];//NeededByEOF+some space + int i = 0; + do + { + [aName appendFormat:@"NeededByEOF%d",i]; + if ([currentAttributes objectForKey:aName]==nil) + break; + else + [aName setString:@""]; + } while(1); + + //Now create temporary attribute + flattenAttribute = AUTORELEASE([EOAttribute new]); + [flattenAttribute setName:aName]; + [flattenAttribute setEntity:self]; + [flattenAttribute _setDefinitionWithoutFlushingCaches: + [[relationshipPath stringByAppendingString:@"."] + stringByAppendingString:[attribute name]]]; + [flattenAttribute setEntity:nil]; + [flattenAttribute _setValuesFromTargetAttribute]; + [flattenAttribute setEntity:self]; + return flattenAttribute; } - (NSString*) snapshotKeyForAttributeName: (NSString*)attributeName { - NSString *attName = [self _flattenedAttNameToSnapshotKeyMapping]; - - if (attName) - { - NSEmitTODO(); //TODO - [self notImplemented: _cmd]; - } - else - attName = attributeName; //TODO-VERIFY - - return attName; + NSDictionary* map = [self _flattenedAttNameToSnapshotKeyMapping]; + NSString* key = [map objectForKey:attributeName]; + if (key==nil) + key=attributeName; + return key; } -- (id) _flattenedAttNameToSnapshotKeyMapping +- (NSDictionary*) _flattenedAttNameToSnapshotKeyMapping { - // NSArray *attributesToSave = [self _attributesToSave]; - - //NSEmitTODO(); //TODO - - return nil; //[self notImplemented:_cmd]; //TODO + if (_flattenedAttNameToSnapshotKeyMapping==nil) + [self _attributesToSave];//Build the map + return _flattenedAttNameToSnapshotKeyMapping; } - (EOMKKDSubsetMapping*) _snapshotToAdaptorRowSubsetMapping @@ -2886,7 +2901,7 @@ returns nil if there's no key in the instanceDictionaryInitializer { EORelationship *classProperty = [classProperties objectAtIndex: i]; - if ([classProperty isKindOfClass: [EORelationship class]]) + if ([classProperty isKindOfClass: GDL2_EORelationshipClass]) { EORelationship *relsubs = [classProperty _substitutionRelationshipForRow: row]; @@ -2933,16 +2948,20 @@ returns nil if there's no key in the instanceDictionaryInitializer - (NSArray*) _attributesToSave { - //Near OK EOFLOGObjectLevelArgs(@"EOEntity", @"START Entity _attributesToSave entityname=%@", [self name]); if (!_attributesToSave) { + EOAttribute* attribute=nil; NSArray *attributesToFetch = [self _attributesToFetch]; - int i, count = [attributesToFetch count]; - NSMutableArray *attributesToSave = [NSMutableArray arrayWithCapacity:count]; + int attributesToFetchCount = [attributesToFetch count]; + int i=0; + NSMutableString* aName = [NSMutableString stringWithCapacity:128]; + NSMutableDictionary* attrToSaveByName = [NSMutableDictionary dictionaryWithCapacity:attributesToFetchCount]; + NSMutableDictionary* flattenAttrByPath = nil; + NSMutableSet* processedPathes = nil; NSAssert3(!attributesToFetch || [attributesToFetch isKindOfClass: [NSArray class]], @@ -2951,35 +2970,135 @@ returns nil if there's no key in the instanceDictionaryInitializer [_attributesToFetch class], _attributesToFetch); - for (i = 0; i < count; i++) - { - EOAttribute *attribute = [attributesToFetch objectAtIndex: i]; - BOOL isFlattened = [attribute isFlattened]; + for(i=attributesToFetchCount-1;i>=0;i--) + { + attribute = [attributesToFetch objectAtIndex:i]; + [attrToSaveByName setObject:attribute + forKey:[attribute name]]; + if ([attribute isFlattened]) + { + if(flattenAttrByPath == nil) + flattenAttrByPath = [NSMutableDictionary dictionary]; + [aName setString:@""]; + [aName appendString:[attribute relationshipPath]]; + [aName appendString:@"."]; + [aName appendString:[[attribute targetAttribute]name]]; + [flattenAttrByPath setObject:attribute + forKey:[NSString stringWithString:aName]]; + }; + } - if (!isFlattened) - [attributesToSave addObject: attribute]; - } - ASSIGN(_attributesToSave, attributesToSave); + //Also build _flattenedAttNameToSnapshotKeyMapping ! + if (_flattenedAttNameToSnapshotKeyMapping) + [_flattenedAttNameToSnapshotKeyMapping removeAllObjects]; + else + _flattenedAttNameToSnapshotKeyMapping=[NSMutableDictionary new]; + + //We may modify the dictionary so enumerate on -allValues + NSEnumerator* objectEnumerator=[[attrToSaveByName allValues]objectEnumerator]; + while((attribute=[objectEnumerator nextObject])) + { + if ([attribute isFlattened]) + { + NSString* relationshipPath = [attribute relationshipPath]; + if (![processedPathes containsObject:relationshipPath]) + { + if (processedPathes == nil) + processedPathes = [NSMutableSet set]; + + [processedPathes addObject:relationshipPath]; + + EOEntity* destinationEntity = [[self relationshipForPath:relationshipPath] destinationEntity]; + NSArray* dstPKAttrs = [destinationEntity primaryKeyAttributes]; + int dstPKAttrsCount = [dstPKAttrs count]; + + if(dstPKAttrs == nil) + { + [NSException raise: @"NSIllegalStateException" + format: @"%@: entity '%@' has no primary key", + NSStringFromSelector(_cmd), + [destinationEntity name]]; + } + + + for(i=dstPKAttrsCount-1;i>=0;i--) + { + EOAttribute* dstPKAttr = [dstPKAttrs objectAtIndex:i]; + [aName setString:@""]; + [aName appendString:relationshipPath]; + [aName appendString:@"."]; + [aName appendString:[dstPKAttr name]]; + if ([flattenAttrByPath objectForKey:aName]==nil) + { + EOAttribute* flattenAttr = [self _flattenAttribute: dstPKAttr + relationshipPath: relationshipPath + currentAttributes: attrToSaveByName]; + [attrToSaveByName setObject:flattenAttr + forKey:[flattenAttr name]]; + + [flattenAttrByPath setObject:flattenAttr + forKey:[NSString stringWithString:aName]]; + + NSDictionary* map = [attribute _sourceToDestinationKeyMap]; + NSArray* destinationKeys = [map objectForKey:@"destinationKeys"]; + if (destinationKeys != nil) + { + NSUInteger index=[destinationKeys indexOfObject:[dstPKAttr name]]; + if (index!=NSNotFound) + { + NSString* sourceKey = [[map objectForKey:@"sourceKeys"] objectAtIndex:index]; + [_flattenedAttNameToSnapshotKeyMapping setObject:sourceKey + forKey:[flattenAttr name]]; + } + } + } + } + } + } + }; + ASSIGN(_attributesToSave,([[attrToSaveByName allValues] sortedArrayUsingSelector:@selector(eoCompareOnName:)])); } - - EOFLOGObjectLevelArgs(@"EOEntity", @"STOP Entity _attributesToSave entityname=%@ attrs:%@", - [self name], _attributesToSave); - return _attributesToSave; } +-(NSArray*) _extraSingleTableAttributesToFetch:(NSArray*)alreadyFetchedAttributes +{ + NSMutableArray* extraAttributes = [NSMutableArray array]; + NSArray* subEntities = [self subEntities]; + int subEntitiesCount = [subEntities count]; + if (subEntitiesCount>0) + { + NSMutableSet* seenAttributeNames = + [NSMutableSet setWithArray:[alreadyFetchedAttributes + resultsOfPerformingSelector:@selector(name)]]; + int i=0; + for(i=0;i0) + { + int j=0; + for(j=0;j0) + { + NSMutableSet* processed = [NSMutableSet set]; + NSEnumerator* enumerator = [flattenAttrsAndRels objectEnumerator]; + id propertyName=nil; + while((propertyName=[enumerator nextObject])) + { + id property=[self anyAttributeNamed:propertyName]; + if (property==nil) + property=[self anyRelationshipNamed:propertyName]; + NSString* relationshipPath = [property relationshipPath]; + NSAssert1(relationshipPath,@"No relationshipPath for %@",property); + if (![processed containsObject:relationshipPath]) + { + [self _addAttributesToFetchForRelationshipPath:relationshipPath + atts: attrsByName]; + [processed addObject:relationshipPath]; + } + } + } + + if (_flags.isSingleTableEntity) + { + NSArray* attributesToFetch = [[attrsByName allValues]sortedArrayUsingSelector:@selector(eoCompareOnName:)]; + NSArray* extraAttrs = [self _extraSingleTableAttributesToFetch:attributesToFetch]; + int extraAttrsCount = [extraAttrs count]; + if (extraAttrsCount>0) + { + for(i=0;i0) + { + EOEntity* entity = self; + int i=0; + for(i=0;i0) + joins = [relationship joins]; + joinsCount = [joins count]; + if (joinsCount>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 = + for(i=joinsCount-1;i>=0;i--) + { + EOJoin* join = [joins objectAtIndex: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; + [sourceKeys addObject:[sourceAttribute name]]; + [destinationKeys addObject:[destinationAttribute name]]; + } + } + return [NSDictionary dictionaryWithObjectsAndKeys: + sourceKeys, @"sourceKeys", + destinationKeys, @"destinationKeys", + nil, nil]; } +- (NSDictionary *)_keyMapForRelationshipPath: (NSString *)path +{ + NSDictionary* keyMap=nil; + NSMutableArray* sourceKeys = nil; + NSMutableArray* destinationKeys = nil; + + NSRange dotPos=[path rangeOfString:@"." + options:NSBackwardsSearch]; + if (dotPos.length==0)//Not multihop relationshipPath + { + EORelationship* relationship = [self anyRelationshipNamed:path]; + NSArray* joins = [relationship joins]; + int i=0; + sourceKeys = [NSMutableArray array]; + destinationKeys = [NSMutableArray array]; + for(i=[joins count]-1;i>=0;i--) + { + EOJoin* join = [joins objectAtIndex:i]; + [sourceKeys addObject:[[join sourceAttribute] name]]; + [destinationKeys addObject:[[join destinationAttribute] name]]; + } + } + else + { + if ([self _relationshipPathHasIdenticalKeys:path]) + keyMap=[self _keyMapForIdenticalKeyRelationshipPath:path]; + else + { + NSArray* attributesToFetch = [self _attributesToFetch]; + int attributesToFetchCount=[attributesToFetch count]; + EORelationship* relationship = [self relationshipForPath:path]; + NSArray* joins = [relationship joins]; + int joinsCount = [joins count]; + int i = 0; + + sourceKeys = [NSMutableArray array]; + destinationKeys = [NSMutableArray array]; + + //Path without last component + NSString* beginingPath = [path substringToIndex:dotPos.location]; + + for(i=joinsCount-1;i>=0;i--) + { + EOJoin* join = [joins objectAtIndex:i]; + EOAttribute* sourceAttribute = [join sourceAttribute]; + EOAttribute* destinationAttribute = [join destinationAttribute]; + EOAttribute* finalSourceAttribute = nil; + int j=0; + for(j=attributesToFetchCount-1;j>=0;j--) + { + finalSourceAttribute = [attributesToFetch objectAtIndex:j]; + if ([finalSourceAttribute targetAttribute] == sourceAttribute + && [[finalSourceAttribute relationshipPath] isEqualToString:beginingPath] + && ![finalSourceAttribute isReadOnly]) + break; + } + + if (finalSourceAttribute == nil) + { + [NSException raise: @"NSIllegalStateException" + format: @"%@ entity '%@' is unable to build internal key map for relationship path '%@'", + NSStringFromSelector(_cmd), + [self name], + path]; + } + [sourceKeys addObject:[finalSourceAttribute name]]; + [destinationKeys addObject:[destinationAttribute name]]; + } + } + } + if (!keyMap) + { + keyMap=[NSDictionary dictionaryWithObjectsAndKeys: + sourceKeys, @"sourceKeys", + destinationKeys, @"destinationKeys", + nil]; + } + return keyMap; + } + - (EOAttribute *)_mapAttribute: (EOAttribute *)attribute toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path { + EOAttribute* resultAttribute=attribute; 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]; + int componentsCount=[components count]; + if (componentsCount>0) + { + EOEntity *entity = self; + int i=0; + for(i=0;i0) { - 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++) + EOEntity* entity = self; + NSArray* destinationAttributes = nil; + int i = 0; + for(i=0;i0) { - 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]); + NSArray* sourceAttributes = [relationship sourceAttributes]; + if(![destinationAttributes containsIdenticalObjectsWithArray:sourceAttributes]); + { + has=NO; + break; + } } - }; + destinationAttributes = [relationship destinationAttributes]; + entity = [relationship destinationEntity]; + } } - - return [NSDictionary dictionaryWithObjectsAndKeys: - sourceKeys, @"sourceKeys", - destinationKeys, @"destinationKeys", - nil]; -//{destinationKeys = (code); sourceKeys = (countryCode); } + return has; } - + @end @implementation EOEntity (EOEntitySQLExpression) - (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression { - return [self notImplemented: _cmd]; //TODO -} - -+ (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression -{ - return [self notImplemented: _cmd]; //TODO + if (sqlExpression == nil) + return _externalName; + else + return [sqlExpression sqlStringForSchemaObjectName:_externalName]; } @end @@ -3435,34 +3624,53 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path - (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])) + NSMutableArray* exceptions = nil; + NSArray* relationships = [self relationships]; + int relationshipsCount = [relationships count]; + if (relationshipsCount>0) { -//classproperties - -//rien pour nullify - if ([relationship deleteRule] == EODeleteRuleDeny) + NSArray* classProperties = [self classProperties]; + int i=0; + for(i=0;i0) + { + if (!exceptions) + exceptions = [NSMutableArray arrayWithCapacity:5]; - [expArray addObject: - [NSException validationExceptionWithFormat: - @"delete operation for relationship key %@ refused", - [relationship name]]]; - } + [exceptions addObject: + [NSException validationExceptionWithFormat: + @"Removal of '%@' object denied: in its '%@' relationship because there are related objects", + [object entityName], + [relationship name]]]; + } + } + else + { + if (!exceptions) + exceptions = [NSMutableArray arrayWithCapacity:5]; + + [exceptions addObject: + [NSException validationExceptionWithFormat: + @"Removal of '%@' object denied: in its '%@' relationship because there is a related object", + [object entityName], + [relationship name]]]; + } + } + } + } } - - if (expArray) - return [NSException aggregateExceptionWithExceptions:expArray]; + if (exceptions) + return [NSException aggregateExceptionWithExceptions:exceptions]; else return nil; } @@ -3470,7 +3678,6 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path /** Retain an array of name of all EOAttributes **/ - (NSArray*) classPropertyAttributeNames { - //Should be OK if (!_classPropertyAttributeNames) { int i=0; @@ -3487,9 +3694,6 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path [(NSMutableArray*)_classPropertyAttributeNames addObject: [property name]]; }; - - EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyAttributeNames=%@", - _classPropertyAttributeNames); } return _classPropertyAttributeNames; @@ -3497,12 +3701,10 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path - (NSArray*) classPropertyToManyRelationshipNames { - //Should be OK if (!_classPropertyToManyRelationshipNames) { NSArray *classProperties = [self classProperties]; int i, count = [classProperties count]; - Class relClass = [EORelationship class]; _classPropertyToManyRelationshipNames = [NSMutableArray new]; @@ -3510,7 +3712,7 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path { EORelationship *property = [classProperties objectAtIndex: i]; - if ([property isKindOfClass: relClass] + if ([property isKindOfClass:GDL2_EORelationshipClass] && [property isToMany]) [(NSMutableArray*)_classPropertyToManyRelationshipNames addObject: [property name]]; @@ -3522,12 +3724,10 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path - (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 ? @@ -3535,7 +3735,7 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path { EORelationship *property = [classProperties objectAtIndex: i]; - if ([property isKindOfClass: relClass] + if ([property isKindOfClass:GDL2_EORelationshipClass] && ![property isToMany]) [(NSMutableArray*)_classPropertyToOneRelationshipNames addObject: [property name]]; @@ -3545,56 +3745,78 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path return _classPropertyToOneRelationshipNames; } -- (id) qualifierForDBSnapshot:(id)param0 +- (EOQualifier*) qualifierForDBSnapshot:(NSDictionary*)dbSnapshot { - return [self notImplemented: _cmd]; //TODO + return [self qualifierForPrimaryKey:dbSnapshot]; } - (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) + NSRange r=[relPath rangeOfString:@"."]; + BOOL isMultiHopRelPath = (r.length>0); + if (!isMultiHopRelPath + || [self _relationshipPathIsToMany:relPath] + || [self _relationshipPathHasIdenticalKeys:relPath]) { - NSEmitTODO(); //TODO - //TODO + NSString* firstPathComponent = + (isMultiHopRelPath ? [relPath substringToIndex:r.location] : relPath); + EORelationship* relationship = [self relationshipNamed:firstPathComponent]; + NSArray* joins = [relationship joins]; + int joinsCount = [joins count]; + if (joinsCount>0) + { + int i = 0; + for(i=0;i0) - { - 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]); - } - }; + EORelationship* relationship = [self relationshipForPath:relPath]; + NSRange rLast=[relPath rangeOfString:@"." + options:NSBackwardsSearch]; + NSString* firstPathComponents = [relPath substringToIndex:rLast.location]; + NSArray* joins = [relationship joins]; + int joinsCount = [joins count]; + if (joinsCount>0) + { + EOAttribute* attribute = nil; + int i = 0; + for(i=0;i 0, @"Path is empty (%p)", path); expressionArray = [EOExpressionArray expressionArrayWithPrefix: nil @@ -3833,7 +4046,7 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path if (relationship) { - NSAssert2([relationship isKindOfClass: [EORelationship class]], + NSAssert2([relationship isKindOfClass: GDL2_EORelationshipClass], @"relationship is not a EORelationship but a %@. relationship:\n%@", [relationship class], relationship); @@ -3898,8 +4111,6 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", self, expressionArray); - - return expressionArray; } @@ -3910,8 +4121,6 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path NSArray *components = nil; int i, count = 0; - - EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p self name=%@ propertyName=%@", self, [self name], propertyName); @@ -3936,15 +4145,14 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path if (relationship) { - NSAssert2([relationship isKindOfClass: [EORelationship class]], + NSAssert2([relationship isKindOfClass: GDL2_EORelationshipClass], @"relationship is not a EORelationship but a %@. relationship:\n%@", [relationship class], relationship); if ([relationship isFlattened]) { - NSEmitTODO(); //TODO - [self notImplemented: _cmd];//TODO + [expressionArray addObjectsFromArray: [relationship _definitionArray]]; } else { @@ -4029,13 +4237,6 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path - (void) dealloc { - //OK - EOFLOGObjectLevelArgs(@"EOEntity", @"Deallocate EOEntityClassDescription %p", - self); - - fflush(stdout); - fflush(stderr); - DESTROY(_entity); [super dealloc]; @@ -4056,9 +4257,7 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path - (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)name { - NSEmitTODO(); //TODO - [self notImplemented: _cmd]; - return nil; + return [_entity fetchSpecificationNamed:name]; } - (NSString *)entityName @@ -4170,26 +4369,9 @@ fromInsertionInEditingContext: (EOEditingContext *)context - (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); - - - + EORelationship *rel = [_entity relationshipNamed: detailKey]; + EOEntity *destEntity = [rel destinationEntity]; + EOClassDescription *cd = [destEntity classDescriptionForInstances]; return cd; } @@ -4208,12 +4390,12 @@ fromInsertionInEditingContext: (EOEditingContext *)context globalID, [_entity name]); if (objectClass) - { - obj = AUTORELEASE([[objectClass allocWithZone:zone] - initWithEditingContext: editingContext - classDescription: self - globalID: globalID]); - } + { + obj = AUTORELEASE([[objectClass allocWithZone:zone] + initWithEditingContext: editingContext + classDescription: self + globalID: globalID]); + } return obj; } @@ -4232,18 +4414,8 @@ fromInsertionInEditingContext: (EOEditingContext *)context - (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); - - + EORelationship *rel = [_entity relationshipNamed: relationshipKey]; + EODeleteRule deleteRule = [rel deleteRule]; return deleteRule; } @@ -4378,22 +4550,112 @@ returns nil if there's no key in the instanceDictionaryInitializer separatorString: (NSString *)separatorString initialCaps: (BOOL)initialCaps { - NSEmitTODO(); //TODO - [self notImplemented: _cmd]; - return nil; + NSString* name=nil; + NSRange dotPos=[externalName rangeOfString:@"."]; + if (dotPos.length==0 + && ![externalName isEqualToString:[externalName lowercaseString]] + && ![externalName isEqualToString:[externalName uppercaseString]]) + { + if(!initialCaps + && uni_toupper([externalName characterAtIndex:0])==[externalName characterAtIndex:0])//is uppercase first character ? + { + name=[[[externalName substringToIndex:1] lowercaseString] + stringByAppendingString:[externalName substringFromIndex:1]]; + } + else + name=externalName; + } + else + { + name=[NSMutableString stringWithCapacity:[externalName length]]; + NSArray* parts = [externalName componentsSeparatedByString: separatorString]; + int partsCount = [parts count]; + int i=0; + BOOL isFirst = YES; + for(i = 0; i < partsCount; i++) + { + NSString* part = [parts objectAtIndex:i]; + if ([part length]>0) + { + if(!initialCaps + && isFirst) + { + part = [part lowercaseString]; + isFirst = NO; + } + else + { + part = [part capitalizedString]; + } + [(NSMutableString*)name appendString:part]; + } + } + name=[NSString stringWithString:name]; + } + return name; +} + +- (NSString*)stringByMarkingUpcaseTransitionsWithDelimiter:(NSString*)delimiter +{ + NSString* result=nil; + int len = [self length]; + if (len==0) + result=[NSString string]; + else + { + int sepLen = [delimiter length]; + int i, outlen = 0; + unichar* selfChars=malloc(sizeof(unichar)); + unichar* resultChars=NULL; + BOOL lastWasLower = NO; + + NSAssert(selfChars,@"Can't alloc"); + + resultChars=malloc(sizeof(unichar)*len*(sepLen+1)); + if (resultChars==NULL) + { + free(selfChars); + NSAssert(NO,@"Can't alloc"); + } + + + [self getCharacters:selfChars]; + + // We insert separator at all lower to upper transitions + for (i = 0; i < len; i++) + { + unichar c = selfChars[i]; + if (c==uni_toupper(c)) + { + if (lastWasLower + && i != 0) + { + // lower to UPPER transition! + [delimiter getCharacters:resultChars+outlen]; + outlen += sepLen; + } + lastWasLower = NO; + } + else + lastWasLower = YES; + resultChars[outlen++] = c; + } + result = [NSString stringWithCharacters:resultChars + length:outlen]; + } + return result; } + (NSString *)externalNameForInternalName: (NSString *)internalName separatorString: (NSString *)separatorString useAllCaps: (BOOL)allCaps { - NSEmitTODO(); //TODO - [self notImplemented: _cmd]; - return nil; + NSString* s = [internalName stringByMarkingUpcaseTransitionsWithDelimiter:separatorString]; + return (allCaps ? [s uppercaseString] : [s lowercaseString]); } -@end +@end @implementation NSObject (EOEntity) /** should returns a set of property names to exclude from entity diff --git a/EOAccess/EOEntityPriv.h b/EOAccess/EOEntityPriv.h index 396bc21..e0fbbe1 100644 --- a/EOAccess/EOEntityPriv.h +++ b/EOAccess/EOEntityPriv.h @@ -63,13 +63,13 @@ - (NSArray *)relationshipsPlist; - (id)rootParent; - (void)_setParent: (id)param0; -- (NSArray *)_hiddenRelationships; +- (NSMutableArray *)_hiddenRelationships; - (NSArray *)_propertyNames; -- (id)_flattenAttribute: (id)param0 - relationshipPath: (id)param1 - currentAttributes: (id)param2; +- (EOAttribute*) _flattenAttribute: (EOAttribute*)attribute + relationshipPath: (NSString*)relationshipPath + currentAttributes: (NSDictionary*)currentAttributes; - (NSString *)snapshotKeyForAttributeName: (NSString *)attributeName; -- (id)_flattenedAttNameToSnapshotKeyMapping; +- (NSDictionary*)_flattenedAttNameToSnapshotKeyMapping; - (EOMKKDSubsetMapping *)_snapshotToAdaptorRowSubsetMapping; - (EOMutableKnownKeyDictionary *)_dictionaryForPrimaryKey; - (EOMutableKnownKeyDictionary *)_dictionaryForProperties; @@ -93,19 +93,18 @@ @end @interface EOEntity (EOEntityRelationshipPrivate) -- (EORelationship *)_inverseRelationshipPathForPath: (NSString *)path; +- (NSString *)_inverseRelationshipPathForPath: (NSString *)path; - (NSDictionary *)_keyMapForRelationshipPath: (NSString *)path; - (NSDictionary*)_keyMapForIdenticalKeyRelationshipPath: (NSString *)path; - (EOAttribute*)_mapAttribute: (EOAttribute*)attribute toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path; - (BOOL)_relationshipPathIsToMany: (NSString *)relPath; -- (BOOL)_relationshipPathHasIdenticalKeys: (id)param0; +- (BOOL)_relationshipPathHasIdenticalKeys: (NSString*)path; @end @interface EOEntity (EOEntitySQLExpression) - (NSString *)valueForSQLExpression: (EOSQLExpression *)sqlExpression; -+ (NSString *)valueForSQLExpression: (EOSQLExpression *)sqlExpression; @end @interface EOEntity (EOEntityPrivateXX) @@ -123,7 +122,7 @@ toDestinationAttributeInLastComponentOfRelationshipPath: (NSString *)path; - (NSArray *)classPropertyAttributeNames; - (NSArray *)classPropertyToManyRelationshipNames; - (NSArray *)classPropertyToOneRelationshipNames; -- (id)qualifierForDBSnapshot: (id)param0; +- (EOQualifier*) qualifierForDBSnapshot:(NSDictionary*)dbSnapshot; - (void)_addAttributesToFetchForRelationshipPath: (NSString *)path atts: (NSMutableDictionary *)atts; - (NSArray *)dbSnapshotKeys; diff --git a/EOAccess/EOExpressionArray.h b/EOAccess/EOExpressionArray.h index 23bb5a1..43d1868 100644 --- a/EOAccess/EOExpressionArray.h +++ b/EOAccess/EOExpressionArray.h @@ -98,6 +98,8 @@ - (NSString *)valueForSQLExpression: (EOSQLExpression *)sqlExpression; +- (BOOL)_isPropertyPath; + @end /* EOExpressionArray */ diff --git a/EOAccess/EOExpressionArray.m b/EOAccess/EOExpressionArray.m index fbb2d73..a76a809 100644 --- a/EOAccess/EOExpressionArray.m +++ b/EOAccess/EOExpressionArray.m @@ -66,6 +66,7 @@ RCS_ID("$Id$") #include #include #include +#include "EOPrivate.h" static SEL eqSel; @@ -164,7 +165,7 @@ static SEL eqSel; - (NSString *)expressionValueForContext: (id)ctx { if (ctx && [self count] - && [[self objectAtIndex: 0] isKindOfClass: [EORelationship class]]) + && [[self objectAtIndex: 0] isKindOfClass: GDL2_EORelationshipClass]) return [ctx expressionValueForAttributePath: self]; else { @@ -334,17 +335,10 @@ static SEL eqSel; - (BOOL)_isPropertyPath { -/* - int i=0; - int count=0; - - count=[self count]; -objectAtIndex:i -if it's a string return NO -*/ -//TODO - - return NO; + if ([self count]<=0) + return NO; + else + return [[self objectAtIndex:0] isKindOfClass:GDL2_EORelationshipClass]; } - (NSString *)valueForSQLExpression: (EOSQLExpression*)sqlExpression diff --git a/EOAccess/EOModel.m b/EOAccess/EOModel.m index 73e8109..c7d597a 100644 --- a/EOAccess/EOModel.m +++ b/EOAccess/EOModel.m @@ -91,9 +91,17 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; @end /* EOModel (EOModelPrivate) */ - @implementation EOModel ++ (void)initialize +{ + static BOOL initialized=NO; + if (!initialized) + { + initialized=YES; + }; +}; + + (EOModel*) model { return AUTORELEASE([[self alloc] init]); @@ -199,8 +207,6 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; - (id)init { - - if ((self = [super init])) { // Turbocat @@ -219,7 +225,6 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; name: EOClassDescriptionNeededNotification object: nil]; - //No ? [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_classDescriptionNeeded:) @@ -1344,7 +1349,7 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; for (; refIdx < refCount; refIdx++) { id refObj = [references objectAtIndex:refIdx]; - if ([refObj class] == [EOAttribute class]) + if ([refObj class] == GDL2_EOAttributeClass) { [[(EOAttribute*) refObj entity] removeAttribute:refObj]; } else { @@ -1404,7 +1409,7 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; NSString *entityName = nil; NSString *entityClassName = nil; - if ([entity isKindOfClass: [EOEntity class]]) + if ([entity isKindOfClass:GDL2_EOEntityClass]) { entityName = [entity name]; entityClassName = [entity className]; @@ -1895,17 +1900,49 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; return returnPath; } +-(NSDictionary*)propertyListForEntity:(id)entity + name:(NSString*)name +{ + NSDictionary* propList=nil; + + NSString* plistPathName = [[[self path] stringByAppendingPathComponent: name] + stringByAppendingPathExtension: @"plist"]; + + EOFLOGObjectLevelArgs(@"gsdb", @"entity plistPathName =%@", + plistPathName); + + propList = [NSDictionary dictionaryWithContentsOfFile: plistPathName]; + EOFLOGObjectLevelArgs(@"gsdb", @"entity propList=%@", propList); + + if (!propList) + { + if ([[NSFileManager defaultManager] + fileExistsAtPath: plistPathName]) + { + NSAssert1(NO, + @"%@ is not a dictionary or is not readable.", + plistPathName); + } + else + { + propList = entity; + NSWarnLog(@"%@ doesn't exists. Using %@", + plistPathName, propList); + } + } + return propList; +} + - (EOEntity *) _verifyBuiltEntityObject: (id)entity named: (NSString*)name { - if ([entity isKindOfClass: [EOEntity class]] == NO) + if ([entity isKindOfClass:GDL2_EOEntityClass] == NO) { [EOObserverCenter suppressObserverNotification]; NS_DURING { NSString *basePath = nil; - NSString *plistPathName = nil; NSDictionary *propList = nil; EOFLOGObjectLevelArgs(@"gsdb", @"name=%@", name); @@ -1928,32 +1965,8 @@ NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; } else { - plistPathName = [[basePath stringByAppendingPathComponent: name] - stringByAppendingPathExtension: @"plist"]; - - EOFLOGObjectLevelArgs(@"gsdb", @"entity plistPathName =%@", - plistPathName); - - propList - = [NSDictionary dictionaryWithContentsOfFile: plistPathName]; - EOFLOGObjectLevelArgs(@"gsdb", @"entity propList=%@", propList); - - if (!propList) - { - if ([[NSFileManager defaultManager] - fileExistsAtPath: plistPathName]) - { - NSAssert1(NO, - @"%@ is not a dictionary or is not readable.", - plistPathName); - } - else - { - propList = entity; - NSWarnLog(@"%@ doesn't exists. Using %@", - plistPathName, propList); - } - } + propList=[self propertyListForEntity:entity + name:name]; } [self _removeEntity: entity]; diff --git a/EOAccess/EOModelGroup.h b/EOAccess/EOModelGroup.h index eaf871b..e33332d 100644 --- a/EOAccess/EOModelGroup.h +++ b/EOAccess/EOModelGroup.h @@ -50,7 +50,7 @@ { NSMutableDictionary *_modelsByName; id _delegate; - +@public //EORelationship need access to relationshipForRow struct { unsigned int entityNamed:1; unsigned int relationshipForRow:1; diff --git a/EOAccess/EOPrivate.h b/EOAccess/EOPrivate.h index 23a67fd..fddd40a 100644 --- a/EOAccess/EOPrivate.h +++ b/EOAccess/EOPrivate.h @@ -38,6 +38,8 @@ // ==== Classes ==== GDL2ACCESS_EXPORT Class GDL2_EODatabaseContextClass; GDL2ACCESS_EXPORT Class GDL2_EOAttributeClass; +GDL2ACCESS_EXPORT Class GDL2_EORelationshipClass; +GDL2ACCESS_EXPORT Class GDL2_EOEntityClass; // ==== IMPs ==== GDL2ACCESS_EXPORT IMP GDL2_EODatabaseContext_snapshotForGlobalIDIMP; diff --git a/EOAccess/EOPrivate.m b/EOAccess/EOPrivate.m index 83b7fd3..a1edae1 100644 --- a/EOAccess/EOPrivate.m +++ b/EOAccess/EOPrivate.m @@ -44,6 +44,7 @@ RCS_ID("$Id$") #include #include #include +#include #include #include "EOPrivate.h" @@ -51,6 +52,8 @@ RCS_ID("$Id$") // ==== Classes ==== Class GDL2_EODatabaseContextClass=Nil; Class GDL2_EOAttributeClass=Nil; +Class GDL2_EORelationshipClass=Nil; +Class GDL2_EOEntityClass=Nil; // ==== IMPs ==== IMP GDL2_EODatabaseContext_snapshotForGlobalIDIMP=NULL; @@ -69,6 +72,8 @@ void GDL2_EOAccessPrivateInit() // ==== Classes ==== GDL2_EODatabaseContextClass = [EODatabaseContext class]; GDL2_EOAttributeClass = [EOAttribute class]; + GDL2_EORelationshipClass = [EORelationship class]; + GDL2_EOEntityClass = [EOEntity class]; GDL2_EODatabaseContext_snapshotForGlobalIDIMP=[GDL2_EODatabaseContextClass instanceMethodForSelector:@selector(snapshotForGlobalID:)]; diff --git a/EOAccess/EORelationship.h b/EOAccess/EORelationship.h index 9043fbd..7f5837f 100644 --- a/EOAccess/EORelationship.h +++ b/EOAccess/EORelationship.h @@ -95,7 +95,6 @@ typedef enum { /* Computed values */ NSArray *_sourceAttributes; NSArray *_destinationAttributes; - NSMutableArray *_componentRelationships;//Used ???? } + (id)relationshipWithPropertyList: (NSDictionary *)propertyList @@ -192,9 +191,9 @@ typedef enum { - (EORelationship *)firstRelationship; - (EOEntity*) intermediateEntity; - (BOOL)isMultiHop; -- (void)_setSourceToDestinationKeyMap: (id)param0; -- (id)qualifierForDBSnapshot: (id)param0; -- (id)primaryKeyForTargetRowFromSourceDBSnapshot: (id)param0; +- (void)_setSourceToDestinationKeyMap:(NSDictionary *)sourceToDestinationKeyMap; +- (EOQualifier*)qualifierForDBSnapshot:(NSDictionary *)dbSnapshot; +- (NSDictionary *)primaryKeyForTargetRowFromSourceDBSnapshot:(NSDictionary *)dbSnapshot; - (NSString *)relationshipPath; - (BOOL)isToManyToOne; - (NSDictionary *)_sourceToDestinationKeyMap; @@ -203,9 +202,9 @@ typedef enum { @interface EORelationship (EORelationshipPrivate2) - (BOOL)isPropagatesPrimaryKeyPossible; -- (id)qualifierOmittingAuxiliaryQualifierWithSourceRow: (id)param0; -- (id)auxiliaryQualifier; -- (void)setAuxiliaryQualifier: (id)param0; +- (EOQualifier*)qualifierOmittingAuxiliaryQualifierWithSourceRow: (NSDictionary *)row; +- (EOQualifier*)auxiliaryQualifier; +- (void)setAuxiliaryQualifier: (EOQualifier*)qualifier; - (EOMutableKnownKeyDictionary *)_foreignKeyForSourceRow: (NSDictionary *)row; - (EOMKKDSubsetMapping *)_sourceRowToForeignKeyMapping; - (NSArray *)_sourceAttributeNames; diff --git a/EOAccess/EORelationship.m b/EOAccess/EORelationship.m index 36b1a5d..2d192a8 100644 --- a/EOAccess/EORelationship.m +++ b/EOAccess/EORelationship.m @@ -56,6 +56,7 @@ RCS_ID("$Id$") #include #include +#include #include #include #include @@ -201,24 +202,18 @@ RCS_ID("$Id$") //Near OK if ((self = [self init])) { - NSString *joinSemanticString = nil; - EOModel *model; + EOModel* model = [owner model]; + NSString* relationshipName = [propertyList objectForKey: @"name"]; + NSString* joinSemanticString = nil; NSString* destinationEntityName = nil; EOEntity* destinationEntity = nil; NSString* deleteRuleString = nil; - NSString* relationshipName; - - - - model = [owner model]; - relationshipName = [propertyList objectForKey: @"name"]; /* so setName: can validate against the owner */ [self setEntity: owner]; [self setName: relationshipName]; destinationEntityName = [propertyList objectForKey: @"destination"]; - if (destinationEntityName) //If not, this is because it's a definition { destinationEntity = [model entityNamed: destinationEntityName]; @@ -295,14 +290,7 @@ RCS_ID("$Id$") - (void)awakeWithPropertyList: (NSDictionary *)propertyList //TODO { - //OK for definition - NSString *definition; - - - - EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); - - definition = [propertyList objectForKey: @"definition"]; + NSString *definition = [propertyList objectForKey: @"definition"]; EOFLOGObjectLevelArgs(@"EORelationship", @"definition=%@", definition); @@ -334,40 +322,32 @@ RCS_ID("$Id$") for (i = 0; i < count; i++) { - NSDictionary *joinPList; - NSString *joinSemantic; - NSString *sourceAttributeName; - EOAttribute *sourceAttribute; - EOEntity *destinationEntity; - NSString *destinationAttributeName = nil; - EOAttribute *destinationAttribute = nil; + NSDictionary *joinPList = + [joins objectAtIndex: i]; + /*NSString *joinSemantic = + [joinPList objectForKey: @"joinSemantic"];*/ + NSString *sourceAttributeName = + [joinPList objectForKey:@"sourceAttribute"]; + EOAttribute *sourceAttribute = + [_entity attributeNamed:sourceAttributeName]; + EOEntity *destinationEntity = + [self destinationEntity]; + NSString *destinationAttributeName = + [joinPList objectForKey:@"destinationAttribute"]; + EOAttribute *destinationAttribute = + [destinationEntity attributeNamed:destinationAttributeName]; EOJoin *join = nil; - joinPList = [joins objectAtIndex: i]; - joinSemantic = [joinPList objectForKey: @"joinSemantic"]; - - sourceAttributeName = [joinPList objectForKey: - @"sourceAttribute"]; - sourceAttribute = [_entity attributeNamed: - sourceAttributeName]; - NSAssert4(sourceAttribute, @"No sourceAttribute named \"%@\" in entity \"%@\" in relationship %@\nEntity: %@", sourceAttributeName, [_entity name], self, _entity); - destinationEntity = [self destinationEntity]; NSAssert3(destinationEntity,@"No destination entity for relationship named '%@' in entity named '%@': %@", [self name], [[self entity]name], self); - destinationAttributeName = [joinPList - objectForKey: - @"destinationAttribute"]; - destinationAttribute = [destinationEntity - attributeNamed: - destinationAttributeName]; NSAssert4(destinationAttribute, @"No destinationAttribute named \"%@\" in entity \"%@\" in relationship %@\nEntity: %@", destinationAttributeName, @@ -621,12 +601,20 @@ destination entity of the last relationship in definition. **/ - (BOOL) isParentRelationship { - BOOL isParentRelationship = NO; - /*EOEntity *destinationEntity = [self destinationEntity]; - EOEntity *parentEntity = [_entity parentEntity];*///nil - - NSEmitTODO(); //TODO - // [self notImplemented:_cmd]; //TODO... + BOOL isParentRelationship=NO; + EOEntity *destinationEntity = [self destinationEntity]; + if(destinationEntity != nil + && destinationEntity == [_entity parentEntity]) + { + NSArray* attributes = [self sourceAttributes]; + NSArray* pkAttributes = [_entity primaryKeyAttributes]; + if([attributes containsIdenticalObjectsWithArray:pkAttributes]) + { + attributes = [self destinationAttributes]; + pkAttributes = [_destination primaryKeyAttributes]; + isParentRelationship=[attributes containsIdenticalObjectsWithArray:pkAttributes]; + } + } return isParentRelationship; } @@ -636,10 +624,7 @@ destination entity of the last relationship in definition. **/ **/ - (BOOL)isFlattened { - if (_definitionArray) - return [_definitionArray isFlattened]; - else - return NO; + return (_definitionArray==nil ? NO : YES); } /** return YES if the relation if a to-many one, NO otherwise (please read books @@ -664,7 +649,6 @@ to know what to-many mean :-) **/ - (NSArray *)sourceAttributes { - //OK if (!_sourceAttributes) { int i, count = [_joins count]; @@ -684,7 +668,6 @@ to know what to-many mean :-) **/ - (NSArray *)destinationAttributes { - //OK if (!_destinationAttributes) { int i, count = [_joins count]; @@ -723,19 +706,7 @@ to know what to-many mean :-) **/ */ - (NSArray *)componentRelationships { - /* FIXME:TODO: Have this method deterimne the components dynamically - without caching them in the ivar. Possibly add some tracing code to - see if caching the values can actually improve performance. - (Unlikely that it's worth the trouble this may cause for entity - edititng). */ - if (!_componentRelationships) - { - return _definitionArray; //OK ?????? - NSEmitTODO(); //TODO - [self notImplemented: _cmd]; //TODO - } - - return _componentRelationships; + return _definitionArray; } - (NSDictionary *)userInfo @@ -829,16 +800,9 @@ to know what to-many mean :-) **/ - (BOOL)isReciprocalToRelationship: (EORelationship *)relationship { - //Should be OK - //Ayers: Review BOOL isReciprocal = NO; - EOEntity *entity; - EOEntity *relationshipDestinationEntity = nil; - - - - entity = [self entity]; //OK - relationshipDestinationEntity = [relationship destinationEntity]; + EOEntity *entity = [self entity]; + EOEntity *relationshipDestinationEntity = [relationship destinationEntity]; EOFLOGObjectLevelArgs(@"EORelationship", @"entity %p name=%@", entity, [entity name]); @@ -847,11 +811,11 @@ to know what to-many mean :-) **/ relationshipDestinationEntity, [relationshipDestinationEntity name]); - if (entity == relationshipDestinationEntity) //Test like that ? + if (entity == relationshipDestinationEntity) { - if ([self isFlattened]) //OK + if ([self isFlattened]) { - if ([relationship isFlattened]) //OK + if ([relationship isFlattened]) { //Now compare each components in reversed order NSArray *selfComponentRelationships = @@ -887,25 +851,10 @@ to know what to-many mean :-) **/ isReciprocal = YES; } } - else - { - //Just do nothing and try another relationship. - // Is it the good way ? - /* - NSEmitTODO(); //TODO - NSDebugMLog(@"entity %p name=%@ self name=%@ relationship name=%@ relationshipDestinationEntity %p name=%@", - entity, [entity name], - [self name], - [relationship name], - relationshipDestinationEntity, - [relationshipDestinationEntity name]); - [self notImplemented: _cmd]; //TODO - */ - } } else { - //WO doens't test inverses entity + //WO doesn't test inverses entity; we does. EOEntity *relationshipEntity = [relationship entity]; EOEntity *destinationEntity = [self destinationEntity]; @@ -984,8 +933,6 @@ to know what to-many mean :-) **/ } } - - return isReciprocal; } @@ -993,21 +940,11 @@ to know what to-many mean :-) **/ relationships. Nil if none" **/ - (EORelationship *)inverseRelationship { - //OK - - if (!_inverseRelationship) { - EOEntity *destinationEntity; - NSArray *destinationEntityRelationships; - - destinationEntity = [self destinationEntity]; - NSDebugLog(@"destinationEntity name=%@", [destinationEntity name]); - - destinationEntityRelationships = [destinationEntity relationships]; - - NSDebugLog(@"destinationEntityRelationships=%@", - destinationEntityRelationships); + EOEntity* destinationEntity = [self destinationEntity]; + NSArray* destinationEntityRelationships = + [destinationEntity relationships]; if ([destinationEntityRelationships count] > 0) { @@ -1018,20 +955,14 @@ relationships. Nil if none" **/ EORelationship *testRelationship = [destinationEntityRelationships objectAtIndex: i]; - NSDebugLog(@"testRelationship=%@", testRelationship); - if ([self isReciprocalToRelationship: testRelationship]) { ASSIGN(_inverseRelationship, testRelationship); } } } - - NSDebugLog(@"_inverseRelationship=%@", _inverseRelationship); } - - return _inverseRelationship; } @@ -1043,8 +974,6 @@ relationships. Nil if none" **/ NSString *name = nil; int i, count; - - NSAssert([self isFlattened], @"Not Flatten Relationship"); EOFLOGObjectLevel(@"EORelationship", @"add joins"); @@ -1084,21 +1013,16 @@ relationships. Nil if none" **/ [inverseRelationship _setInverseRelationship: self]; - - return inverseRelationship; } - (EORelationship*) _makeInverseRelationship { - //OK EORelationship *inverseRelationship; NSString *name; NSArray *joins = nil; unsigned int i, count; - - NSAssert(![self isFlattened], @"Flatten Relationship"); inverseRelationship = [[EORelationship new] autorelease]; @@ -1137,15 +1061,11 @@ relationships. Nil if none" **/ /* call this last to avoid calls to [_destination _setIsEdited] */ [inverseRelationship setEntity: _destination]; - return inverseRelationship; } - (EORelationship*) hiddenInverseRelationship { - //OK - - if (!_hiddenInverseRelationship) { if ([self isFlattened]) @@ -1154,14 +1074,11 @@ relationships. Nil if none" **/ _hiddenInverseRelationship = [self _makeInverseRelationship]; } - - return _hiddenInverseRelationship; } - (EORelationship *)anyInverseRelationship { - //OK EORelationship *inverseRelationship = [self inverseRelationship]; if (!inverseRelationship) @@ -1182,8 +1099,19 @@ relationships. Nil if none" **/ - (EOQualifier *)qualifierWithSourceRow: (NSDictionary *)sourceRow { - [self notImplemented: _cmd];//TODO - return nil; + EOQualifier* q = nil; + EOQualifier* q1 = [self qualifierOmittingAuxiliaryQualifierWithSourceRow:sourceRow]; + EOQualifier* q2 = [self auxiliaryQualifier]; + if (q1 != nil) + { + if (q2!=nil) + q=[EOAndQualifier qualifierWithQualifiers:q1,q2,nil]; + else + q=q1; + } + else + q=q2; + return q; } @end /* EORelationship */ @@ -1193,12 +1121,13 @@ relationships. Nil if none" **/ - (NSException *)validateName: (NSString *)name { - //Seems OK const char *p, *s = [name cString]; int exc = 0; NSArray *storedProcedures = nil; - if ([_name isEqual:name]) return nil; + if ([_name isEqual:name]) + return nil; + if (!name || ![name length]) exc++; if (!exc) @@ -1272,7 +1201,6 @@ relationships. Nil if none" **/ - (void)setToMany: (BOOL)flag { - //OK if ([self isFlattened]) [NSException raise: NSInvalidArgumentException format: @"%@ -- %@ 0x%p: receiver is a flattened relationship", @@ -1290,7 +1218,6 @@ relationships. Nil if none" **/ - (void)setName: (NSString *)name { - //OK [[self validateName: name] raise]; [self willChange]; [_entity _setIsEdited]; @@ -1300,9 +1227,6 @@ relationships. Nil if none" **/ - (void)setDefinition: (NSString *)definition { - //Near OK - - EOFLOGObjectLevelArgs(@"EORelationship", @"definition=%@", definition); [self _flushCache]; @@ -1334,7 +1258,7 @@ relationships. Nil if none" **/ { EORelationship *rel = [_definitionArray objectAtIndex: i]; - if ([rel isKindOfClass: [EORelationship class]]) + if ([rel isKindOfClass: GDL2_EORelationshipClass]) { if ([rel isToMany]) _flags.isToMany = YES; @@ -1366,7 +1290,6 @@ relationships. Nil if none" **/ */ - (void)setEntity: (EOEntity *)entity { - //OK if (entity != _entity) { [self _flushCache]; @@ -1374,18 +1297,12 @@ relationships. Nil if none" **/ if (_entity) { - NSString *relationshipName; - EORelationship *relationship; - /* Check if we are still in the entities arrays to avoid recursive loop when removeRelationship: calls this method. */ - relationshipName = [self name]; - relationship = [_entity relationshipNamed: relationshipName]; - if (self == relationship) - { - [_entity removeRelationship: self]; - } + NSString *relationshipName = [self name]; + if (self == [_entity relationshipNamed: relationshipName]) + [_entity removeRelationship: self]; } _entity = entity; } @@ -1395,7 +1312,6 @@ relationships. Nil if none" **/ - (void)setUserInfo: (NSDictionary *)dictionary { - //OK [self willChange]; ASSIGN(_userInfo, dictionary); /* Ayers: Not sure what justifies this. */ @@ -1404,7 +1320,6 @@ relationships. Nil if none" **/ - (void)setInternalInfo: (NSDictionary *)dictionary { - //OK [self willChange]; ASSIGN(_internalInfo, dictionary); /* Ayers: Not sure what justifies this. */ @@ -1413,7 +1328,6 @@ relationships. Nil if none" **/ - (void)setDocComment: (NSString *)docComment { - //OK [self willChange]; ASSIGNCOPY(_docComment, docComment); /* Ayers: Not sure what justifies this. */ @@ -1422,7 +1336,6 @@ relationships. Nil if none" **/ - (void)setPropagatesPrimaryKey: (BOOL)flag { - //OK if (_flags.propagatesPrimaryKey != flag) [self willChange]; @@ -1431,7 +1344,6 @@ relationships. Nil if none" **/ - (void)setIsBidirectional: (BOOL)flag { - //OK if (_flags.isBidirectional != flag) [self willChange]; @@ -1447,187 +1359,171 @@ relationships. Nil if none" **/ } - (void)addJoin: (EOJoin *)join -{ - EOAttribute *sourceAttribute = nil; - EOAttribute *destinationAttribute = nil; - - - +{ EOFLOGObjectLevelArgs(@"EORelationship", @"Add join: %@\nto %@", join, self); if ([self isFlattened] == YES) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p: receiver is a flattened relationship", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self]; - else - { - EOEntity *destinationEntity = [self destinationEntity]; - EOEntity *sourceEntity = [self entity]; - - EOFLOGObjectLevelArgs(@"EORelationship", @"destinationEntity=%@", destinationEntity); - - if (!destinationEntity) { -#warning checkme: do we need this? -- dw - //NSEmitTODO(); //TODO - //EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); - //TODO ?? - }; - - sourceAttribute = [join sourceAttribute]; - - NSAssert3(sourceAttribute, @"No source attribute in join %@ in relationship %@ of entity %@", - join, - self, - sourceEntity); - - destinationAttribute = [join destinationAttribute]; - - NSAssert3(destinationAttribute, @"No destination attribute in join %@ in relationship %@ of entity %@", - join, - self, - sourceEntity); - - if ([sourceAttribute isFlattened] == YES - || [destinationAttribute isFlattened] == YES) [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p: join's attributes are flattened", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self]; - else - { - EOEntity *joinDestinationEntity = [destinationAttribute entity]; - EOEntity *joinSourceEntity = [sourceAttribute entity]; - - /* if (destinationEntity && ![[destinationEntity name] isEqual:[joinSourceEntity name]]) - { - [NSException raise:NSInvalidArgumentException - format:@"%@ -- %@ 0x%x: join source entity (%@) is not equal to last join entity (%@)", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self, - [joinSourceEntity name], - [destinationEntity name]]; - }*/ - - if (sourceEntity - && ![[joinSourceEntity name] isEqual: [sourceEntity name]]) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p (%@): join source entity (%@) is not equal to relationship entity (%@)", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self, - [self name], - [joinSourceEntity name], - [sourceEntity name]]; - else if (destinationEntity - && ![[joinDestinationEntity name] - isEqual: [destinationEntity name]]) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p (%@): join destination entity (%@) is not equal to relationship destination entity (%@)", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self, - [self name], - [joinDestinationEntity name], - [destinationEntity name]]; - else - { - if ([_sourceAttributes count]) - { - EOAttribute *sourceAttribute = [join sourceAttribute]; - EOAttribute *destinationAttribute; - - destinationAttribute = [join destinationAttribute]; - - if (([_sourceAttributes indexOfObject: sourceAttribute] - != NSNotFound) - && ([_destinationAttributes - indexOfObject: destinationAttribute] - != NSNotFound)) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p: TODO", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self]; - } - - [self _flushCache]; - // do we still need willChange when we are not putting EORelationships into ECs? -- dw - [self willChange]; - // needed for KV bbserving - [self willChangeValueForKey:@"joins"]; - - EOFLOGObjectLevel(@"EORelationship", @"really add"); - EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", - _joins, [_joins class]); - - if (!_joins) - _joins = [NSMutableArray new]; - - [(NSMutableArray *)_joins addObject: join]; - - EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", - _joins, [_joins class]); - - EOFLOGObjectLevel(@"EORelationship", @"added"); - - [self _joinsChanged]; - [self didChangeValueForKey:@"joins"]; - - /* Ayers: Not sure what justifies this. */ - [_entity _setIsEdited]; - } + format: @"%@ -- %@ 0x%p: receiver is a flattened relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + else + { + EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *sourceEntity = [self entity]; + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"destinationEntity=%@", destinationEntity); + + NSAssert3(sourceAttribute, @"No source attribute in join %@ in relationship %@ of entity %@", + join, + self, + sourceEntity); + + NSAssert3(destinationAttribute, @"No destination attribute in join %@ in relationship %@ of entity %@", + join, + self, + sourceEntity); + + if ([sourceAttribute isFlattened] == YES + || [destinationAttribute isFlattened] == YES) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p: join's attributes are flattened", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + else + { + EOEntity *joinDestinationEntity = [destinationAttribute entity]; + EOEntity *joinSourceEntity = [sourceAttribute entity]; + + /* if (destinationEntity && ![[destinationEntity name] isEqual:[joinSourceEntity name]]) + { + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: join source entity (%@) is not equal to last join entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [joinSourceEntity name], + [destinationEntity name]]; + }*/ + + if (sourceEntity + && ![[joinSourceEntity name] isEqual: [sourceEntity name]]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p (%@): join source entity (%@) is not equal to relationship entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [joinSourceEntity name], + [sourceEntity name]]; + } + else if (destinationEntity + && ![[joinDestinationEntity name] + isEqual: [destinationEntity name]]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p (%@): join destination entity (%@) is not equal to relationship destination entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [joinDestinationEntity name], + [destinationEntity name]]; + } + else + { + if ([_sourceAttributes count]) + { + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute; + + destinationAttribute = [join destinationAttribute]; + + if (([_sourceAttributes indexOfObject: sourceAttribute] + != NSNotFound) + && ([_destinationAttributes + indexOfObject: destinationAttribute] + != NSNotFound)) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p: TODO", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + } + + [self _flushCache]; + // do we still need willChange when we are not putting EORelationships into ECs? -- dw + [self willChange]; + // needed for KV bbserving + [self willChangeValueForKey:@"joins"]; + + EOFLOGObjectLevel(@"EORelationship", @"really add"); + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + if (!_joins) + _joins = [NSMutableArray new]; + + [(NSMutableArray *)_joins addObject: join]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + EOFLOGObjectLevel(@"EORelationship", @"added"); + + [self _joinsChanged]; + [self didChangeValueForKey:@"joins"]; + + /* Ayers: Not sure what justifies this. MGuesdon: EOF seems to do it */ + [_entity _setIsEdited]; + } + } } - } - - } - (void)removeJoin: (EOJoin *)join { - - - [self _flushCache]; - if ([self isFlattened] == YES) - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%p: receiver is a flattened relationship", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self]; + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%p: receiver is a flattened relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } else { + [self _flushCache]; + [self willChangeValueForKey:@"joins"]; [self willChange]; [(NSMutableArray *)_joins removeObject: join]; - /*NO: will be recomputed [(NSMutableArray *)_sourceAttributes - removeObject:[join sourceAttribute]]; - [(NSMutableArray *)_destinationAttributes - removeObject:[join destinationAttribute]]; - */ - EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", _joins, [_joins class]); [self _joinsChanged]; - /* Ayers: Not sure what justifies this. */ + /* Ayers: Not sure what justifies this. MGuesdon: EOF seems to do it */ [_entity _setIsEdited]; [self didChangeValueForKey:@"joins"]; } - - } - (void)setJoinSemantic: (EOJoinSemantic)joinSemantic { - //OK [self willChange]; _joinSemantic = joinSemantic; } @@ -1680,6 +1576,7 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ - (void)setNumberOfToManyFaultsToBatchFetch: (unsigned int)size { [self willChange]; + _flags.useBatchFaulting=YES; _batchCount = size; } @@ -1695,8 +1592,8 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ - (void)setIsMandatory: (BOOL)isMandatory { - //OK - [self willChange]; + if (_flags.isMandatory!=isMandatory) + [self willChange]; _flags.isMandatory = isMandatory; } @@ -1715,33 +1612,44 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ */ - (NSException *)validateValue: (id*)valueP { - //OK NSException *exception = nil; - - NSAssert(valueP, @"No value pointer"); if ([self isMandatory]) { BOOL isToMany = [self isToMany]; - if ((isToMany == NO && _isNilOrEONull(*valueP)) - || (isToMany == YES && [*valueP count] == 0)) - { - EOEntity *destinationEntity = [self destinationEntity]; - EOEntity *entity = [self entity]; - - exception = [NSException validationExceptionWithFormat: - @"The %@ property of %@ must have a %@ assigned", - [self name], - [entity name], - [destinationEntity name]]; - } + if (isToMany == NO) + { + if (_isNilOrEONull(*valueP)) + { + EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *entity = [self entity]; + + exception = [NSException validationExceptionWithFormat: + @"The %@ property of %@ must have a %@ assigned", + [self name], + [entity name], + [destinationEntity name]]; + } + } + else + { + if ([*valueP count] == 0) + { + EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *entity = [self entity]; + + exception = [NSException validationExceptionWithFormat: + @"The %@ property of %@ must have at least one %@", + [self name], + [entity name], + [destinationEntity name]]; + } + } } - - return exception; } @@ -1768,26 +1676,16 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ - (NSArray*) _intermediateAttributes { - //Verify !! - NSMutableArray *intermediateAttributes; - EORelationship *rel; - NSArray *joins; + NSMutableArray *intermediateAttributes=[NSMutableArray array]; + NSArray* firstRelJoins=[[self firstRelationship] joins]; + NSArray* lastRelJoins=[[self lastRelationship] joins]; - //all this works on flattened and non flattened relationship. - intermediateAttributes = [NSMutableArray array]; - rel = [self firstRelationship]; - joins = [rel joins]; - //?? [intermediateAttributes addObjectsFromArray: - [joins resultsOfPerformingSelector: + [firstRelJoins resultsOfPerformingSelector: @selector(destinationAttribute)]]; - rel = [self lastRelationship]; - joins = [rel joins]; - // attribute = [joins sourceAttribute]; - //?? [intermediateAttributes addObjectsFromArray: - [joins resultsOfPerformingSelector: + [lastRelJoins resultsOfPerformingSelector: @selector(sourceAttribute)]]; return [NSArray arrayWithArray: intermediateAttributes]; @@ -1833,7 +1731,6 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ - (EOEntity*) intermediateEntity { - //TODO verify id intermediateEntity = nil; if ([self isToManyToOne]) @@ -1854,41 +1751,99 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ - (BOOL) isMultiHop { - //TODO verify - BOOL isMultiHop = NO; + return [self isFlattened]; +} - if ([self isFlattened]) +- (void) _setSourceToDestinationKeyMap: (NSDictionary*)sourceToDestinationKeyMap +{ + ASSIGN(_sourceToDestinationKeyMap,sourceToDestinationKeyMap); +} + +- (EOQualifier*) qualifierForDBSnapshot: (NSDictionary*)dbSnapshot +{ + EOQualifier* qualifier = nil; + + EORelationship* relationship = self; + NSMutableArray* qualifiers = nil; + BOOL isFlattenedToMany = NO; + NSString* relationshipPath = nil; + + if([self isFlattened]) { - isMultiHop = YES; + if ([self isToMany]) + { + relationshipPath = [[self anyInverseRelationship]relationshipPath]; + isFlattenedToMany = true; + relationship = [self firstRelationship]; + } + else + relationship = [self lastRelationship]; } - return isMultiHop; + NSDictionary* sourceToDestinationKeyMap = [self _sourceToDestinationKeyMap]; + NSArray* sourceKeys = [sourceToDestinationKeyMap objectForKey:@"sourceKeys"]; + NSArray* destinationKeys = [sourceToDestinationKeyMap objectForKey:@"destinationKeys"]; + NSArray* joins = [relationship joins]; + int joinsCount=[joins count]; + int i = 0; + + for(i=0;i0) + { + if ([qualifiers count] > 1) + qualifier = [EOAndQualifier qualifierWithQualifierArray:qualifiers]; + else + qualifier = [qualifiers objectAtIndex:0]; + } + return qualifier; + } -- (void) _setSourceToDestinationKeyMap: (id)param0 +- (NSDictionary*) primaryKeyForTargetRowFromSourceDBSnapshot:(NSDictionary*)dbSnapshot { - [self notImplemented: _cmd]; // TODO -} - -- (id) qualifierForDBSnapshot: (id)param0 -{ - return [self notImplemented: _cmd]; // TODO -} - -- (id) primaryKeyForTargetRowFromSourceDBSnapshot: (id)param0 -{ - return [self notImplemented:_cmd]; // TODO + NSDictionary* sourceToDestinationKeyMap = [self _sourceToDestinationKeyMap]; + NSArray* sourceKeys = [sourceToDestinationKeyMap objectForKey:@"sourceKeys"]; + NSArray* destinationKeys = [sourceToDestinationKeyMap objectForKey:@"destinationKeys"]; + NSMutableDictionary* pk = [NSMutableDictionary dictionaryWithDictionary:dbSnapshot + keys:sourceKeys]; + [pk translateFromKeys:sourceKeys + toKeys:destinationKeys]; + return pk; } /** Return relationship path (like toRel1.toRel2) if self is flattened, slef name otherwise. **/ - (NSString*)relationshipPath { - //Seems OK NSString *relationshipPath = nil; - - if ([self isFlattened]) { int i, count = [_definitionArray count]; @@ -1909,8 +1864,6 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ else relationshipPath = [self name]; - - return relationshipPath; } @@ -1918,72 +1871,47 @@ becomes "name", and "FIRST_NAME" becomes "firstName".*/ { BOOL isToManyToOne = NO; - - if ([self isFlattened]) { - BOOL isToMany = YES; + int l=0; int count = [_definitionArray count]; - - if (count >= 2) - { - EORelationship *firstRelationship = [_definitionArray - objectAtIndex: 0]; - - isToMany = [firstRelationship isToMany]; - - if (!isToMany) + int i=0; + for(i=0;i 0 && primaryKeyAttributesCount > 0) + if([self isToMany]) + foreignKeyInDestination=YES; + else { - NSUInteger i; - - for (i = 0; - !foreignKeyInDestination && i < destAttributesCount; - i++) + NSArray* sourceAttributes = [self sourceAttributes]; + NSArray* pkAttributes = [_entity primaryKeyAttributes]; + int sourceAttributesCount=[sourceAttributes count]; + int pkAttributesCount=[pkAttributes count]; + if (sourceAttributesCount==pkAttributesCount) { - EOAttribute *attribute = [destAttributes objectAtIndex: i]; - NSUInteger pkAttrIndex = [primaryKeyAttributes - indexOfObjectIdenticalTo: attribute]; - - foreignKeyInDestination = (pkAttrIndex == NSNotFound); + foreignKeyInDestination=YES; + int i=0; + for(i=0;foreignKeyInDestination && i0) { - EOJoin *aJoin = [_joins objectAtIndex: i]; - EOAttribute *sourceAttribute = [aJoin sourceAttribute]; - - if ([attribute isEqual: sourceAttribute]) - join = aJoin; + int i=0; + for (i = 0; !join && i < count; i++) + { + EOJoin *aJoin = [_joins objectAtIndex: i]; + if ([attribute isEqual: [aJoin sourceAttribute]] + || [attribute isEqual: [aJoin destinationAttribute]]) + { + join = aJoin; + } + } } return join; @@ -2203,15 +2078,22 @@ dst entity primaryKeyAttributeNames - (void) _flushCache { - //VERIFY - //[self notImplemented:_cmd]; // TODO DESTROY(_sourceAttributes); DESTROY(_destinationAttributes); - DESTROY(_inverseRelationship); - DESTROY(_hiddenInverseRelationship); - DESTROY(_componentRelationships); - _destination = nil; + EORelationship* inverseRelationship=AUTORELEASE(RETAIN(_inverseRelationship)); + DESTROY(_inverseRelationship); + if (inverseRelationship!=nil) + [inverseRelationship _flushCache]; + + if (_hiddenInverseRelationship!=nil) + { + [[[self destinationEntity]_hiddenRelationships] removeObjectIdenticalTo:_hiddenInverseRelationship]; + DESTROY(_hiddenInverseRelationship); + } + + DESTROY(_sourceRowToForeignKeyMapping); + _destination = nil; } - (EOExpressionArray*) _definitionArray @@ -2226,16 +2108,16 @@ dst entity primaryKeyAttributeNames switch(deleteRule) { case EODeleteRuleNullify: - deleteRuleString = @""; + deleteRuleString = @"EODeleteRuleNullify"; break; case EODeleteRuleCascade: - deleteRuleString = @""; + deleteRuleString = @"EODeleteRuleCascade"; break; case EODeleteRuleDeny: - deleteRuleString = @""; + deleteRuleString = @"EODeleteRuleDeny"; break; case EODeleteRuleNoAction: - deleteRuleString = @""; + deleteRuleString = @"EODeleteRuleNoAction"; break; default: [NSException raise: NSInvalidArgumentException @@ -2279,29 +2161,38 @@ dst entity primaryKeyAttributeNames { NSDictionary *keyMap = nil; - NSEmitTODO(); //TODO - - [self notImplemented: _cmd]; // TODO - if ([self isToManyToOne]) - { - int count = [_definitionArray count]; - - if (count >= 2) //?? + { + int definitionArrayCount=[_definitionArray count]; + EOEntity* entity = nil; + NSMutableString* relationshipPath = nil; + int k = 0; + int i = 0; + for(i=0; i < definitionArrayCount; i++) { - EORelationship *rel0 = [_definitionArray objectAtIndex: 0]; - - if ([rel0 isToMany]) //?? + EORelationship* relationship = [_definitionArray objectAtIndex:i]; + switch(k) { - EOEntity *entity = [rel0 destinationEntity]; - EORelationship *rel1 = [_definitionArray objectAtIndex: 1]; - - keyMap = [entity _keyMapForIdenticalKeyRelationshipPath: - [rel1 name]]; + case 0: + if([relationship isToMany]) + { + k = 1; + entity=[relationship destinationEntity]; + } + break; + case 1: + if (relationshipPath) + [relationshipPath appendString: @"."]; + else + relationshipPath = [NSMutableString string]; + [relationshipPath appendString: [relationship name]]; + break; + default: + break; } } + keyMap=[entity _keyMapForIdenticalKeyRelationshipPath:relationshipPath]; } - return keyMap; } @@ -2309,26 +2200,24 @@ dst entity primaryKeyAttributeNames { NSDictionary *keyMap = nil; - NSEmitTODO(); //TODO - - [self notImplemented: _cmd]; // TODO - if ([self isToManyToOne]) - { - int count = [_definitionArray count]; - - if (count >= 2) //?? + { + int definitionArrayCount=[_definitionArray count]; + NSMutableString* relationshipPath = nil; + int i = 0; + for(i=0; i < definitionArrayCount; i++) { - EORelationship *rel = [_definitionArray objectAtIndex: 0]; - - if ([rel isToMany]) //?? - { - EOEntity *entity = [rel entity]; - - keyMap = [entity _keyMapForIdenticalKeyRelationshipPath: - [rel name]]; - } + EORelationship* relationship = [_definitionArray objectAtIndex:i]; + if (relationshipPath) + [relationshipPath appendString: @"."]; + else + relationshipPath = [NSMutableString string]; + [relationshipPath appendString: [relationship name]]; + if ([relationship isToMany]) + break; } + + keyMap=[[self entity]_keyMapForIdenticalKeyRelationshipPath:relationshipPath]; } return keyMap; @@ -2336,30 +2225,22 @@ dst entity primaryKeyAttributeNames - (EORelationship*)_substitutionRelationshipForRow: (NSDictionary*)row { - EOEntity *entity = [self entity]; - EOModel *model = [entity model]; - EOModelGroup *modelGroup = [model modelGroup]; - - if (modelGroup) + EOEntity* entity = [self entity]; + EOModelGroup* modelGroup = [[entity model]modelGroup]; + EORelationship* relationship = self; + if(modelGroup != nil + && modelGroup->_delegateRespondsTo.relationshipForRow) { - //?? - //NSEmitTODO(); //TODO + relationship = [[modelGroup delegate] entity:entity + relationshipForRow:row + relationship:self]; } - - return self; + return relationship; } - (void) _joinsChanged { - //VERIFIED DA - int count = [_joins count]; - - - - - EOFLOGObjectLevelArgs(@"EORelationship", @"_joinsChanged:%@\nin %@", _joins, self); - - if (count > 0) + if ([_joins count] > 0) { EOJoin *join = [_joins objectAtIndex: 0]; EOAttribute *destinationAttribute = [join destinationAttribute]; @@ -2371,8 +2252,6 @@ dst entity primaryKeyAttributeNames { _destination = nil; } - - } @end diff --git a/EOAccess/EOSQLExpression.m b/EOAccess/EOSQLExpression.m index a7cc23a..ebe54ca 100644 --- a/EOAccess/EOSQLExpression.m +++ b/EOAccess/EOSQLExpression.m @@ -2053,7 +2053,7 @@ else if([attribute isDerived] == YES) EOFLOGObjectLevelArgs(@"EOSQLExpression", @"[path objectAtIndex:%d]=%@", i, relationship); - NSAssert2([relationship isKindOfClass:[EORelationship class]], + NSAssert2([relationship isKindOfClass:GDL2_EORelationshipClass], @"'%@' is not a relationship but a %@", relationship, [relationship class]); diff --git a/EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m b/EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m index 1eb64ac..39f4582 100644 --- a/EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m +++ b/EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m @@ -320,7 +320,6 @@ newValueForNumberTypeLengthAttribute(const void *bytes, }; }; }; - return value; } @@ -397,11 +396,15 @@ newValueForDateTypeLengthAttribute (const void *bytes, { getDigits(&str[5],tmpString,2,&error); month = atoi(tmpString); + //Postgres can return bad dates sometimes (it accept bad date in insert/update) + NSCAssert2(month>0,@"Bad month in date %*s",length,bytes); if (length > 9) { getDigits(&str[8],tmpString,2,&error); day = atoi(tmpString); + //Postgres can return bad dates sometimes (it accept bad date in insert/update) + NSCAssert2(day>0,@"Bad day in date %*s",length,bytes); if (length > 12) { @@ -1140,13 +1143,29 @@ each key insertStatementForRow: nrow entity: entity]; - if ([self _evaluateExpression: sqlexpr withAttributes: nil] == 0) //call evaluateExpression: - [NSException raise: EOGeneralAdaptorException - format: @"%@ -- %@ 0x%p: cannot insert row for entity '%@'", - NSStringFromSelector(_cmd), - NSStringFromClass([self class]), - self, - [entity name]]; + if (!_delegateRespondsTo.shouldEvaluateExpression + || [_delegate adaptorChannel: self + shouldEvaluateExpression: sqlexpr]) + { + if ([self _evaluateExpression: sqlexpr + withAttributes: nil] == 0) + { + [NSException raise: EOGeneralAdaptorException + format: @"%@ -- %@ 0x%p: cannot insert row for entity '%@'", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [entity name]]; + } + else + { + if (_delegateRespondsTo.didEvaluateExpression) + { + [_delegate adaptorChannel: self + didEvaluateExpression: sqlexpr]; + } + } + } } [_adaptorContext autoCommitTransaction]; @@ -1191,8 +1210,19 @@ each key deleteStatementWithQualifier: qualifier entity: entity]; - rows = [self _evaluateExpression: sqlexpr withAttributes: nil]; - + if (!_delegateRespondsTo.shouldEvaluateExpression + || [_delegate adaptorChannel: self + shouldEvaluateExpression: sqlexpr]) + { + rows = [self _evaluateExpression: sqlexpr + withAttributes: nil]; + if (_delegateRespondsTo.didEvaluateExpression) + { + [_delegate adaptorChannel: self + didEvaluateExpression: sqlexpr]; + } + } + [adaptorContext autoCommitTransaction]; return rows; @@ -1262,8 +1292,18 @@ each key fetchSpecification: fetchSpecification entity: entity]; - [self _evaluateExpression: sqlExpr - withAttributes: attributes]; + if (!_delegateRespondsTo.shouldEvaluateExpression + || [_delegate adaptorChannel: self + shouldEvaluateExpression: sqlExpr]) + { + [self _evaluateExpression: sqlExpr + withAttributes: attributes]; + if (_delegateRespondsTo.didEvaluateExpression) + { + [_delegate adaptorChannel: self + didEvaluateExpression: sqlExpr]; + } + } [_adaptorContext autoCommitTransaction]; @@ -2198,6 +2238,7 @@ each key EOAttribute *primAttribute; NSString *sqlString; NSNumber *pkValue = nil; + NSString *sqlFormat = nil; const char *string = NULL; int length = 0; @@ -2211,9 +2252,12 @@ each key { return nil; // We support only number keys } - - sqlString = [NSString stringWithFormat: @"SELECT nextval('%@_SEQ')", - [entity primaryKeyRootName]]; + + sqlFormat=[NSString stringWithFormat: @"SELECT nextval('%@')", + [[[self adaptorContext]adaptor] primaryKeySequenceNameFormat]]; + + sqlString = [NSString stringWithFormat: sqlFormat, + [entity primaryKeyRootName]]; if ([self isDebugEnabled]) {