mirror of
https://github.com/gnustep/libs-gdl2.git
synced 2025-02-16 00:11:15 +00:00
* 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:
parent
551011134a
commit
879c15cae4
5 changed files with 256 additions and 168 deletions
16
ChangeLog
16
ChangeLog
|
@ -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>
|
||||
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m:
|
||||
fix newValueForDateTypeLengthAttribute
|
||||
|
|
|
@ -96,7 +96,9 @@ typedef enum {
|
|||
unsigned int isParentAnEOEntity:1;
|
||||
unsigned int protoOverride:EOATTRIBUTE_PROTO_OVERRIDE_BITS_COUNT;
|
||||
unsigned int isAttributeValueInitialized:1;
|
||||
unsigned int unused : 10;
|
||||
unsigned int isNonUpdateable;
|
||||
unsigned int isNonUpdateableInitialized;
|
||||
unsigned int unused : 8;
|
||||
} _flags;
|
||||
|
||||
unsigned int extraRefCount;
|
||||
|
|
|
@ -1035,6 +1035,7 @@ static NSArray* staticPrototypeKeys=nil;
|
|||
[self willChange];
|
||||
_flags.isReadOnly = yn;
|
||||
[self _setOverrideForKeyEnum: EOAttributeProtoOverrideBits_readOnly];
|
||||
_flags.isNonUpdateableInitialized = NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2211,6 +2212,25 @@ More details:
|
|||
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
|
||||
|
||||
|
|
|
@ -65,6 +65,9 @@ typedef enum _EOAttributeProtoOverrideBits
|
|||
- (void)_setValuesFromTargetAttribute;
|
||||
-(void)_setSourceToDestinationKeyMap:(NSDictionary*)map;
|
||||
-(NSDictionary*) _sourceToDestinationKeyMap;
|
||||
|
||||
-(BOOL)_isNonUpdateable;
|
||||
-(BOOL)_isPrimaryKeyClassProperty;
|
||||
@end
|
||||
|
||||
@interface EOAttribute (EOAttributePrivate2)
|
||||
|
|
|
@ -712,14 +712,8 @@ May raise an exception if transaction has began or if you want pessimistic lock
|
|||
editingContext: (EOEditingContext *)context
|
||||
isComplete: (BOOL)isComplete
|
||||
{
|
||||
//OK
|
||||
EOAccessFaultHandler *handler;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NSAssert(globalID, @"No globalID");
|
||||
NSAssert1([globalID isKindOfClass: [EOKeyGlobalID class]],
|
||||
@"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
|
||||
fault: object];
|
||||
|
||||
|
||||
//TODO: use isComplete
|
||||
}
|
||||
|
||||
|
@ -5496,20 +5489,69 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
|
|||
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
|
||||
row: (NSDictionary*)row
|
||||
entity: (EOEntity*)entity
|
||||
editingContext: (EOEditingContext*)context
|
||||
{
|
||||
//really near ok
|
||||
NSArray *relationships = nil;
|
||||
NSArray *classPropertyAttributeNames = nil;
|
||||
NSUInteger count = 0;
|
||||
NSArray *classPropertyAttributeNames = [entity classPropertyAttributeNames];
|
||||
NSUInteger count = [classPropertyAttributeNames count];
|
||||
IMP rowObjectForKeyIMP=NULL;
|
||||
|
||||
classPropertyAttributeNames = [entity classPropertyAttributeNames];
|
||||
count = [classPropertyAttributeNames count];
|
||||
|
||||
//row is usuallly a EOMutableKnownKeyDictionary so will use EOMKKD_objectForKeyWithImpPtr
|
||||
|
||||
if (count>0)
|
||||
|
@ -5521,143 +5563,54 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
|
|||
@"Object is a fault. call -methodForSelector: on it is a bad idea");
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
id key = GDL2_ObjectAtIndexWithImp(classPropertyAttributeNames,oaiIMP,i);
|
||||
id value = nil;
|
||||
|
||||
|
||||
value = EOMKKD_objectForKeyWithImpPtr(row,&rowObjectForKeyIMP,key);
|
||||
|
||||
if (value == GDL2_EONull)
|
||||
value = nil;
|
||||
|
||||
[object takeStoredValue:value
|
||||
forKey:key];
|
||||
}
|
||||
{
|
||||
id key = GDL2_ObjectAtIndexWithImp(classPropertyAttributeNames,oaiIMP,i);
|
||||
id value = EOMKKD_objectForKeyWithImpPtr(row,&rowObjectForKeyIMP,key);
|
||||
|
||||
if (value == GDL2_EONull)
|
||||
value = nil;
|
||||
|
||||
[object takeStoredValue:value
|
||||
forKey:key];
|
||||
}
|
||||
};
|
||||
|
||||
relationships = [entity _relationshipsToFaultForRow: row];
|
||||
|
||||
|
||||
|
||||
relationships = [entity _relationshipsToFaultForRow: row];
|
||||
count = [relationships count];
|
||||
|
||||
if (count>0)
|
||||
{
|
||||
NSUInteger i=0;
|
||||
IMP oaiIMP=[relationships methodForSelector:@selector(objectAtIndex:)];
|
||||
|
||||
NSAssert(!_isFault(object),
|
||||
@"Object is a fault. call -methodForSelector: on it is a bad idea");
|
||||
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
id relObject = nil;
|
||||
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
|
||||
NSString *relName = [relationship name];
|
||||
NSUInteger i=0;
|
||||
IMP oaiIMP=[relationships methodForSelector:@selector(objectAtIndex:)];
|
||||
|
||||
NSAssert(!_isFault(object),
|
||||
@"Object is a fault. call -methodForSelector: on it is a bad idea");
|
||||
|
||||
if ([relationship isToMany])
|
||||
{
|
||||
EOGlobalID *gid = [entity globalIDForRow: row];
|
||||
|
||||
relObject = [self arrayFaultWithSourceGlobalID: gid
|
||||
relationshipName: relName
|
||||
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
|
||||
{
|
||||
EOMutableKnownKeyDictionary *foreignKeyForSourceRow = nil;
|
||||
|
||||
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];
|
||||
|
||||
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
|
||||
forKey:relName];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
id relObject = nil;
|
||||
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
|
||||
NSString *relName = [relationship name];
|
||||
|
||||
if ([relationship isToMany])
|
||||
{
|
||||
EOGlobalID *gid = [entity globalIDForRow: row];
|
||||
|
||||
relObject = [self arrayFaultWithSourceGlobalID: gid
|
||||
relationshipName: relName
|
||||
editingContext: context];
|
||||
}
|
||||
else
|
||||
{
|
||||
relObject=[self _objectFaultWithSnapshot: row
|
||||
relationship: relationship
|
||||
editingContext: context];
|
||||
}
|
||||
|
||||
[object takeStoredValue:relObject
|
||||
forKey:relName];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)forgetAllLocks
|
||||
|
@ -5745,11 +5698,19 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
|
|||
- (EODatabaseChannel*) _obtainOpenChannel
|
||||
{
|
||||
EODatabaseChannel *channel = [self availableChannel];
|
||||
|
||||
if (![self _openChannelWithLoginPanel: channel])
|
||||
if (channel==nil)
|
||||
{
|
||||
NSEmitTODO();
|
||||
[self notImplemented: _cmd];//TODO
|
||||
[NSException raise: @"NSIllegalStateException"
|
||||
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;
|
||||
|
@ -5757,21 +5718,69 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
|
|||
|
||||
- (BOOL) _openChannelWithLoginPanel: (EODatabaseChannel*)databaseChannel
|
||||
{
|
||||
// veridy: LoginPanel ???
|
||||
BOOL result=NO;
|
||||
EOAdaptorChannel *adaptorChannel = [databaseChannel adaptorChannel];
|
||||
|
||||
if (![adaptorChannel isOpen]) //??
|
||||
if ([adaptorChannel isOpen])
|
||||
result=YES;
|
||||
else
|
||||
{
|
||||
[adaptorChannel openChannel];
|
||||
}
|
||||
NSException* exception=nil;
|
||||
NS_DURING
|
||||
{
|
||||
[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
|
||||
{ // TODO
|
||||
NSEmitTODO();
|
||||
[self notImplemented: _cmd];
|
||||
{
|
||||
EOAdaptorContext* adaptorContext = [self adaptorContext];
|
||||
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
|
||||
|
@ -5795,25 +5804,63 @@ compareUsingEntityNames(id left, id right, void* vpSortOrders)
|
|||
|
||||
- (void) _verifyNoChangesToReadonlyEntity: (EODatabaseOperation*)dbOpe
|
||||
{
|
||||
//TODO
|
||||
EOEntity *entity = nil;
|
||||
|
||||
|
||||
|
||||
entity = [dbOpe entity];
|
||||
|
||||
|
||||
|
||||
EOEntity* entity = [dbOpe entity];
|
||||
if ([entity isReadOnly])
|
||||
{
|
||||
//?? exception I presume
|
||||
switch([dbOpe databaseOperator])
|
||||
{
|
||||
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
|
||||
else if ([dbOpe databaseOperator] == EOAdaptorUpdateOperator
|
||||
&& [entity hasNonUpdateableAttributes])
|
||||
{
|
||||
[dbOpe databaseOperator]; //SoWhat
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue