* EOAccess/EODatabaseContext.m

implement _objectFaultWithSnapshot:relationship:editingContext:
  fix -initializeObject:row:entity:editingContext:
  finish implementation of -_obtainOpenChannel
  implement -_forceDisconnect
  fix -_openChannelWithLoginPanel:
  implement -_verifyNoChangesToReadonlyEntity:
* EOAccess/EOAttributePriv.h
  add -_isNonUpdateable
  add -_isPrimaryKeyClassProperty
  add _flags.isNonUpdateable
  add _flags.isNonUpdateableInitialized
* EOAccess/EOAttribute.m
  add -_isNonUpdateable
  add -_isPrimaryKeyClassProperty


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@37905 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Manuel Guesdon 2014-05-22 18:31:05 +00:00
parent 551011134a
commit 879c15cae4
5 changed files with 256 additions and 168 deletions

View file

@ -1,3 +1,19 @@
2014-05-22 Manuel Guesdon <mguesdon@orange-concept.com>
* EOAccess/EODatabaseContext.m
implement _objectFaultWithSnapshot:relationship:editingContext:
fix -initializeObject:row:entity:editingContext:
finish implementation of -_obtainOpenChannel
implement -_forceDisconnect
fix -_openChannelWithLoginPanel:
implement -_verifyNoChangesToReadonlyEntity:
* EOAccess/EOAttributePriv.h
add -_isNonUpdateable
add -_isPrimaryKeyClassProperty
add _flags.isNonUpdateable
add _flags.isNonUpdateableInitialized
* EOAccess/EOAttribute.m
add -_isNonUpdateable
add -_isPrimaryKeyClassProperty
2014-05-22 Manuel Guesdon <mguesdon@orange-concept.com> 2014-05-22 Manuel Guesdon <mguesdon@orange-concept.com>
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m: * EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m:
fix newValueForDateTypeLengthAttribute fix newValueForDateTypeLengthAttribute

View file

@ -96,7 +96,9 @@ typedef enum {
unsigned int isParentAnEOEntity:1; unsigned int isParentAnEOEntity:1;
unsigned int protoOverride:EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT; unsigned int protoOverride:EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT;
unsigned int isAttributeValueInitialized:1; unsigned int isAttributeValueInitialized:1;
unsigned int unused : 10; unsigned int isNonUpdateable;
unsigned int isNonUpdateableInitialized;
unsigned int unused : 8;
} _flags; } _flags;
unsigned int extraRefCount; unsigned int extraRefCount;

View file

@ -1035,6 +1035,7 @@ static NSArray* staticPrototypeKeys=nil;
[self willChange]; [self willChange];
_flags.isReadOnly = yn; _flags.isReadOnly = yn;
[self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_readOnly]; [self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_readOnly];
_flags.isNonUpdateableInitialized = NO;
} }
} }
@ -2211,6 +2212,25 @@ More details:
return _sourceToDestinationKeyMap; return _sourceToDestinationKeyMap;
} }
-(BOOL)_isNonUpdateable
{
if (!_flags.isNonUpdateableInitialized)
{
_flags.isNonUpdateable = ([self isReadOnly] || [self _isPrimaryKeyClassProperty]);
_flags.isNonUpdateableInitialized = YES;
}
return _flags.isNonUpdateable;
}
-(BOOL)_isPrimaryKeyClassProperty
{
NSArray* pkAttrs = [_parent primaryKeyAttributes];
if ([pkAttrs containsObject:self]
&& [[_parent classProperties]containsObject:self])
return YES;
else
return NO;
}
@end @end

View file

@ -65,6 +65,9 @@ typedef enum _EOAttributeProtoOverrideBits
- (void)_setValuesFromTargetAttribute; - (void)_setValuesFromTargetAttribute;
-(void)_setSourceToDestinationKeyMap:(NSDictionary*)map; -(void)_setSourceToDestinationKeyMap:(NSDictionary*)map;
-(NSDictionary*) _sourceToDestinationKeyMap; -(NSDictionary*) _sourceToDestinationKeyMap;
-(BOOL)_isNonUpdateable;
-(BOOL)_isPrimaryKeyClassProperty;
@end @end
@interface EOAttribute (EOAttributePrivate2) @interface EOAttribute (EOAttributePrivate2)

View file

@ -712,14 +712,8 @@ May raise an exception if transaction has began or if you want pessimistic lock
editingContext: (EOEditingContext *)context editingContext: (EOEditingContext *)context
isComplete: (BOOL)isComplete isComplete: (BOOL)isComplete
{ {
//OK
EOAccessFaultHandler *handler; EOAccessFaultHandler *handler;
NSAssert(globalID, @"No globalID"); NSAssert(globalID, @"No globalID");
NSAssert1([globalID isKindOfClass: [EOKeyGlobalID class]], NSAssert1([globalID isKindOfClass: [EOKeyGlobalID class]],
@"globalID is not a EOKeyGlobalID but a %@", @"globalID is not a EOKeyGlobalID but a %@",
@ -748,7 +742,6 @@ May raise an exception if transaction has began or if you want pessimistic lock
[self _addBatchForGlobalID: (EOKeyGlobalID*)globalID [self _addBatchForGlobalID: (EOKeyGlobalID*)globalID
fault: object]; fault: object];
//TODO: use isComplete //TODO: use isComplete
} }
@ -5496,20 +5489,69 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
return result; return result;
} }
-(id)_fetchSingleObjectForEntity:(EOEntity*)entity
globalID:(EOGlobalID*)gid
editingContext:(EOEditingContext*)context
{
id object=nil;
NSDictionary* pk = [entity primaryKeyForGlobalID:gid];
EOFetchSpecification* fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName:[entity name]
qualifier: [entity qualifierForPrimaryKey:pk]
sortOrderings: nil];
[fetchSpec setFetchLimit:1];
NSArray* objects = [self objectsWithFetchSpecification:fetchSpec
editingContext: context];
if ([objects count]==0)
{
[NSException raise: @"NSIllegalStateException"
format:@"The object with globalID %@ could not be found in the database. This could be result of a referential integrity problem with the database. An empty fault could not be created because the object's class could not be determined (e.g. the GID is temporary or it is for an abstract entity).",
gid];
}
else
object=[objects objectAtIndex:0];
return object;
}
-(id)_objectFaultWithSnapshot:(NSDictionary*) snapshot
relationship:(EORelationship*) relationship
editingContext:(EOEditingContext*)context
{
id objectFault=nil;
EOMutableKnownKeyDictionary *foreignKeyForSourceRow =
[relationship _foreignKeyForSourceRow: snapshot];
if ([foreignKeyForSourceRow containsObjectsNotIdenticalTo: GDL2_EONull])
{
EOEntity *destinationEntity = [relationship destinationEntity];
EOGlobalID *relRowGid = [destinationEntity
globalIDForRow: foreignKeyForSourceRow];
if ([[destinationEntity subEntities]count] > 0)
{
objectFault=[self _fetchSingleObjectForEntity:destinationEntity
globalID:relRowGid
editingContext:context];
}
else
{
objectFault=[context faultForGlobalID: relRowGid
editingContext: context];
}
}
return objectFault;
}
- (void)initializeObject: (id)object - (void)initializeObject: (id)object
row: (NSDictionary*)row row: (NSDictionary*)row
entity: (EOEntity*)entity entity: (EOEntity*)entity
editingContext: (EOEditingContext*)context editingContext: (EOEditingContext*)context
{ {
//really near ok
NSArray *relationships = nil; NSArray *relationships = nil;
NSArray *classPropertyAttributeNames = nil; NSArray *classPropertyAttributeNames = [entity classPropertyAttributeNames];
NSUInteger count = 0; NSUInteger count = [classPropertyAttributeNames count];
IMP rowObjectForKeyIMP=NULL; IMP rowObjectForKeyIMP=NULL;
classPropertyAttributeNames = [entity classPropertyAttributeNames];
count = [classPropertyAttributeNames count];
//row is usuallly a EOMutableKnownKeyDictionary so will use EOMKKD_objectForKeyWithImpPtr //row is usuallly a EOMutableKnownKeyDictionary so will use EOMKKD_objectForKeyWithImpPtr
if (count>0) if (count>0)
@ -5523,10 +5565,7 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
id key = GDL2_ObjectAtIndexWithImp(classPropertyAttributeNames,oaiIMP,i); id key = GDL2_ObjectAtIndexWithImp(classPropertyAttributeNames,oaiIMP,i);
id value = nil; id value = EOMKKD_objectForKeyWithImpPtr(row,&rowObjectForKeyIMP,key);
value = EOMKKD_objectForKeyWithImpPtr(row,&rowObjectForKeyIMP,key);
if (value == GDL2_EONull) if (value == GDL2_EONull)
value = nil; value = nil;
@ -5537,9 +5576,6 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
}; };
relationships = [entity _relationshipsToFaultForRow: row]; relationships = [entity _relationshipsToFaultForRow: row];
count = [relationships count]; count = [relationships count];
if (count>0) if (count>0)
@ -5550,14 +5586,12 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
NSAssert(!_isFault(object), NSAssert(!_isFault(object),
@"Object is a fault. call -methodForSelector: on it is a bad idea"); @"Object is a fault. call -methodForSelector: on it is a bad idea");
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
id relObject = nil; id relObject = nil;
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i); EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
NSString *relName = [relationship name]; NSString *relName = [relationship name];
if ([relationship isToMany]) if ([relationship isToMany])
{ {
EOGlobalID *gid = [entity globalIDForRow: row]; EOGlobalID *gid = [entity globalIDForRow: row];
@ -5566,98 +5600,17 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
relationshipName: relName relationshipName: relName
editingContext: context]; editingContext: context];
} }
else if ([relationship isFlattened])
{
// to one flattened relationship like aRelationship.anotherRelationship...
// I don't know how to handle this case.... May be we shouldn't treat this as real property ??
NSEmitTODO();
relObject = nil;
}
else else
{ {
EOMutableKnownKeyDictionary *foreignKeyForSourceRow = nil; relObject=[self _objectFaultWithSnapshot: row
relationship: relationship
foreignKeyForSourceRow = [relationship _foreignKeyForSourceRow: row];
if (![foreignKeyForSourceRow
containsObjectsNotIdenticalTo: GDL2_EONull])
{
NSEmitTODO();//TODO: what to do if rel is mandatory ?
relObject = nil;
}
else
{
EOEntity *destinationEntity = [relationship destinationEntity];
EOGlobalID *relRowGid = [destinationEntity
globalIDForRow: foreignKeyForSourceRow];
if ([(EOKeyGlobalID*)relRowGid areKeysAllNulls])
NSWarnLog(@"All key of relRowGid %p (%@) are nulls",
relRowGid,
relRowGid);
relObject = [context faultForGlobalID: relRowGid
editingContext: context]; editingContext: context];
NSDebugMLLog(@"EODatabaseContext", @"relObject=%p (%@)",
relObject, [relObject class]);
//end
/*
NSArray *joins = [(EORelationship *)prop joins];
EOJoin *join;
NSMutableDictionary *row;
EOGlobalID *faultGID;
int h, count;
id value, realValue = nil;
row = [NSMutableDictionary dictionaryWithCapacity:4];
count = [joins count];
for (h=0; h<count; h++)
{
join = [joins objectAtIndex:h];
value = [snapshot objectForKey:[[join sourceAttribute]
name]];
if (value == null)
realValue = nil;
else
realValue = value;
[[prop validateValue:&realValue] raise];
[row setObject:value
forKey:[[join destinationAttribute]
name]];
}
if (realValue || [prop isMandatory] == YES)
{
faultGID = [[(EORelationship *)prop destinationEntity]
globalIDForRow:row];
fault = [context objectForGlobalID:faultGID];
if (fault == nil)
fault = [context faultForGlobalID:faultGID
editingContext:context];
}
else
fault = nil;
*/
}
} }
[object takeStoredValue:relObject [object takeStoredValue:relObject
forKey:relName]; forKey:relName];
} }
}; }
} }
- (void)forgetAllLocks - (void)forgetAllLocks
@ -5745,11 +5698,19 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
- (EODatabaseChannel*) _obtainOpenChannel - (EODatabaseChannel*) _obtainOpenChannel
{ {
EODatabaseChannel *channel = [self availableChannel]; EODatabaseChannel *channel = [self availableChannel];
if (channel==nil)
if (![self _openChannelWithLoginPanel: channel])
{ {
NSEmitTODO(); [NSException raise: @"NSIllegalStateException"
[self notImplemented: _cmd];//TODO format:@"%s: no database channel is available",
__PRETTY_FUNCTION__];
}
else if (![self _openChannelWithLoginPanel: channel])
{
[NSException raise: @"NSIllegalStateException"
format:@"%s: failed to open database channel",
__PRETTY_FUNCTION__];
} }
return channel; return channel;
@ -5757,21 +5718,69 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
- (BOOL) _openChannelWithLoginPanel: (EODatabaseChannel*)databaseChannel - (BOOL) _openChannelWithLoginPanel: (EODatabaseChannel*)databaseChannel
{ {
// veridy: LoginPanel ??? BOOL result=NO;
EOAdaptorChannel *adaptorChannel = [databaseChannel adaptorChannel]; EOAdaptorChannel *adaptorChannel = [databaseChannel adaptorChannel];
if (![adaptorChannel isOpen]) //?? if ([adaptorChannel isOpen])
result=YES;
else
{
NSException* exception=nil;
NS_DURING
{ {
[adaptorChannel openChannel]; [adaptorChannel openChannel];
} }
NS_HANDLER
{
if (![[localException name] isEqualToString:EOGeneralAdaptorException])
[localException raise];
else
NSLog(@"%@",localException);
}
NS_ENDHANDLER;
return [adaptorChannel isOpen]; if ([adaptorChannel isOpen])
result=YES;
else
[exception raise];
}
return result;
} }
- (void) _forceDisconnect - (void) _forceDisconnect
{ // TODO {
NSEmitTODO(); EOAdaptorContext* adaptorContext = [self adaptorContext];
[self notImplemented: _cmd]; NSArray* channels = [adaptorContext channels];
NSArray* registeredChannels = [self registeredChannels];
int i = 0;
int c=[channels count];
for(i=0;i<c;i++)
{
NS_DURING
{
[[channels objectAtIndex:i] closeChannel];
}
NS_HANDLER
{
NSLog(@"%@",localException);
}
NS_ENDHANDLER;
}
c=[registeredChannels count];
for(i=0;i<c;i++)
{
NS_DURING
{
[self unregisterChannel:[registeredChannels objectAtIndex:i]];
}
NS_HANDLER
{
NSLog(@"%@",localException);
}
NS_ENDHANDLER;
}
} }
@end @end
@ -5795,25 +5804,63 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
- (void) _verifyNoChangesToReadonlyEntity: (EODatabaseOperation*)dbOpe - (void) _verifyNoChangesToReadonlyEntity: (EODatabaseOperation*)dbOpe
{ {
//TODO EOEntity* entity = [dbOpe entity];
EOEntity *entity = nil;
entity = [dbOpe entity];
if ([entity isReadOnly]) if ([entity isReadOnly])
{ {
//?? exception I presume switch([dbOpe databaseOperator])
}
else
{ {
[dbOpe databaseOperator]; //SoWhat case EOAdaptorInsertOperator:
[NSException raise: @"NSIllegalStateException"
format:@"cannot insert object: %@ that corresponds to read-only entity: %@ in databaseContext %@",
[dbOpe object],
[entity name],
self];
break;
case EOAdaptorDeleteOperator:
[NSException raise: @"NSIllegalStateException"
format:@"cannot insert delete: %@ that corresponds to read-only entity: %@ in databaseContext %@",
[dbOpe object],
[entity name],
self];
break;
case EOAdaptorUpdateOperator:
if (![[dbOpe dbSnapshot] isEqual:[dbOpe newRow]])
{
[NSException raise: @"NSIllegalStateException"
format:@"cannot update '%@' keys on object %@ that corresponds to read-only entity: %@ in databaseContext %@",
[[dbOpe rowDiffsForAttributes:[entity attributes]] allKeys],
[dbOpe object],
[entity name],
self];
}
break;
}
}
else if ([dbOpe databaseOperator] == EOAdaptorUpdateOperator
&& [entity hasNonUpdateableAttributes])
{
NSArray* dbSnapshotKeys = [entity dbSnapshotKeys];
NSDictionary* dbSnapshot = [dbOpe dbSnapshot];
NSMutableDictionary* newRow = [dbOpe newRow];
int i=0;
int c=[dbSnapshotKeys count];
for(i=0;i<c;i++)
{
NSString* key = [dbSnapshotKeys objectAtIndex:i];
EOAttribute* attribute = [entity attributeNamed:key];
if ([attribute _isNonUpdateable]
&& ![[dbSnapshot objectForKey:key] isEqual:[newRow objectForKey:key]])
{
[NSException raise: @"NSIllegalStateException"
format:@"cannot update %@ '%@' on object: %@ that corresponds to read-onlywof entity: %@ in databaseContext %@",
([attribute isReadOnly] ? @"read-only key" : @"primary-key"),
key,
[dbOpe object],
[entity name],
self];
}
}
} }
} }
- (void) _cleanUpAfterSave - (void) _cleanUpAfterSave