4 Copyright (C) 1996 Free Software Foundation, Inc.
6 Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
9 Author: Helge Hess <helge.hess@mdlink.de>
12 This file is part of the GNUstep Database Library.
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Library General Public
16 License as published by the Free Software Foundation; either
17 version 2 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Library General Public License for more details.
24 You should have received a copy of the GNU Library General Public
25 License along with this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation,
27 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #import "EOAttribute.h"
33 #import "EOFExceptions.h"
35 #import "EOPrimaryKeyDictionary.h"
36 #import "EOSQLQualifier.h"
37 #import "EORelationship.h"
38 #import <EOControl/EOKeyValueCoding.h>
39 #import <EOControl/EOKeyGlobalID.h>
41 static int _compareByName(id obj1, id obj2, void * context);
43 @interface NSObject(MappedArrayProtocol)
44 - (NSArray *)mappedArrayUsingSelector:(SEL)_selector;
47 @interface NSString(EntityBeautify)
48 - (NSString *)_beautifyEntityName;
51 @implementation EOEntity
54 if ((self = [super init])) {
55 self->attributes = [[NSArray alloc] init];
56 self->attributesByName = [[NSMutableDictionary alloc] init];
57 self->relationships = [[NSArray alloc] init];
58 self->relationshipsByName = [[NSMutableDictionary alloc] init];
59 self->classProperties = [[NSArray alloc] init];
65 - (void)resetAttributes {
66 [self->attributes makeObjectsPerformSelector:@selector(resetEntity)];
68 - (void)resetRelationships {
69 [self->relationships makeObjectsPerformSelector:@selector(resetEntities)];
74 RELEASE(self->qualifier);
75 [self resetAttributes];
76 RELEASE(self->attributes);
77 RELEASE(self->attributesByName);
78 [self resetRelationships];
79 RELEASE(self->relationships);
80 RELEASE(self->relationshipsByName);
81 RELEASE(self->primaryKeyAttributes);
82 RELEASE(self->classProperties);
83 RELEASE(self->attributesUsedForLocking);
84 RELEASE(self->attributesUsedForInsert);
85 RELEASE(self->attributesUsedForFetch);
86 RELEASE(self->relationsUsedForFetch);
87 RELEASE(self->name); self->name = nil;
88 RELEASE(self->className); self->className = nil;
89 RELEASE(self->externalName); self->externalName = nil;
90 RELEASE(self->externalQuery); self->externalQuery = nil;
91 RELEASE(self->userDictionary); self->userDictionary = nil;
92 RELEASE(self->primaryKeyAttributeNames);
93 self->primaryKeyAttributeNames = nil;
94 RELEASE(self->attributesNamesUsedForInsert);
95 self->attributesNamesUsedForInsert = nil;
96 RELEASE(self->classPropertyNames); self->classPropertyNames = nil;
100 // These methods should be here to let the library work with NeXT foundation
104 - (id)copyWithZone:(NSZone *)_zone {
108 // Is equal only if same name; used to make aliasing ordering stable
113 - (id)initWithName:(NSString *)_name {
119 - (BOOL)setName:(NSString *)_name {
120 if([model entityNamed:name]) return NO;
125 + (BOOL)isValidName:(NSString *)attributeName {
126 unsigned len = [attributeName cStringLength];
131 [attributeName getCString:buf];
133 if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#')
137 if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#' && *s != '$')
143 - (BOOL)addAttribute:(EOAttribute *)attribute {
144 NSString* attributeName = [attribute name];
146 if([self->attributesByName objectForKey:attributeName])
149 if([self->relationshipsByName objectForKey:attributeName])
152 if([self createsMutableObjects])
153 [(NSMutableArray*)self->attributes addObject:attribute];
155 id newAttributes = [self->attributes arrayByAddingObject:attribute];
156 ASSIGN(self->attributes, newAttributes);
159 [self->attributesByName setObject:attribute forKey:attributeName];
160 [attribute setEntity:self];
161 [self invalidatePropertiesCache];
165 - (void)removeAttributeNamed:(NSString *)attributeName {
166 id attribute = [self->attributesByName objectForKey:attributeName];
169 [attribute resetEntity];
170 if([self createsMutableObjects])
171 [(NSMutableArray*)attributes removeObject:attribute];
173 self->attributes = [AUTORELEASE(self->attributes) mutableCopy];
174 [(NSMutableArray*)self->attributes removeObject:attribute];
175 self->attributes = [AUTORELEASE(self->attributes) copy];
177 [self->attributesByName removeObjectForKey:attributeName];
178 [self invalidatePropertiesCache];
182 - (EOAttribute *)attributeNamed:(NSString *)attributeName {
183 return [self->attributesByName objectForKey:attributeName];
186 - (BOOL)addRelationship:(EORelationship *)relationship {
187 NSString* relationshipName = [relationship name];
189 if([self->attributesByName objectForKey:relationshipName])
192 if([self->relationshipsByName objectForKey:relationshipName])
195 if([self createsMutableObjects])
196 [(NSMutableArray*)relationships addObject:relationship];
198 id newRelationships = [self->relationships arrayByAddingObject:relationship];
199 ASSIGN(self->relationships, newRelationships);
202 [self->relationshipsByName setObject:relationship forKey:relationshipName];
203 [relationship setEntity:self];
204 [self invalidatePropertiesCache];
208 - (void)removeRelationshipNamed:(NSString*)relationshipName {
209 id relationship = [relationshipsByName objectForKey:relationshipName];
212 [relationship setEntity:nil];
213 if([self createsMutableObjects])
214 [(NSMutableArray*)self->relationships removeObject:relationship];
216 self->relationships = [AUTORELEASE(self->relationships) mutableCopy];
217 [(NSMutableArray*)self->relationships removeObject:relationship];
218 self->relationships = [AUTORELEASE(relationships) copy];
220 [self->relationshipsByName removeObjectForKey:relationship];
221 [self invalidatePropertiesCache];
225 - (EORelationship*)relationshipNamed:(NSString *)relationshipName {
226 if([relationshipName isNameOfARelationshipPath]) {
229 EOEntity *currentEntity = self;
230 NSString *relName = nil;
231 EORelationship *relationship = nil;
233 defArray = [relationshipName componentsSeparatedByString:@"."];
234 relName = [defArray objectAtIndex:0];
236 for(i = 0, count = [defArray count]; i < count; i++) {
237 if(![EOEntity isValidName:relName])
239 relationship = [currentEntity->relationshipsByName objectForKey:relName];
240 if(relationship == nil)
242 currentEntity = [relationship destinationEntity];
247 return [self->relationshipsByName objectForKey:relationshipName];
250 - (BOOL)setPrimaryKeyAttributes:(NSArray *)keys {
251 int i, count = [keys count];
253 for(i = 0; i < count; i++)
254 if(![self isValidPrimaryKeyAttribute:[keys objectAtIndex:i]])
257 RELEASE(self->primaryKeyAttributes);
258 RELEASE(self->primaryKeyAttributeNames);
260 if([keys isKindOfClass:[NSArray class]]
261 || [keys isKindOfClass:[NSMutableArray class]])
262 self->primaryKeyAttributes = [keys copy];
264 self->primaryKeyAttributes = [[NSArray alloc] initWithArray:keys];
266 self->primaryKeyAttributeNames = [NSMutableArray arrayWithCapacity:count];
267 for(i = 0; i < count; i++) {
268 id key = [keys objectAtIndex:i];
270 [(NSMutableArray*)self->primaryKeyAttributeNames
271 addObject:[(EOAttribute*)key name]];
273 self->primaryKeyAttributeNames
274 = RETAIN([self->primaryKeyAttributeNames
275 sortedArrayUsingSelector:@selector(compare:)]);
277 [self invalidatePropertiesCache];
282 - (BOOL)isValidPrimaryKeyAttribute:(EOAttribute*)anAttribute {
283 if(![anAttribute isKindOfClass:[EOAttribute class]])
286 if([self->attributesByName objectForKey:[anAttribute name]])
292 - (NSDictionary *)primaryKeyForRow:(NSDictionary *)_row {
293 return [EOPrimaryKeyDictionary dictionaryWithKeys:
294 self->primaryKeyAttributeNames
295 fromDictionary:_row];
298 - (NSDictionary *)snapshotForRow:(NSDictionary *)aRow {
301 NSMutableDictionary *dict;
303 array = [self attributesUsedForLocking];
305 dict = [NSMutableDictionary dictionaryWithCapacity:n];
307 for (i = 0; i < n; i++) {
308 EOAttribute *attribute;
309 NSString *columnName;
310 NSString *attributeName;
313 attribute = [array objectAtIndex:i];
314 columnName = [attribute columnName];
315 attributeName = [attribute name];
317 value = [aRow objectForKey:attributeName];
320 NSAssert1(columnName, @"missing column name in attribute %@ !", attribute);
321 NSAssert3(value, @"missing value for column '%@' (attr '%@') in row %@",
322 columnName, attribute, aRow);
325 [dict setObject:value forKey:attributeName];
330 /* Getting attributes used for database oprations */
332 - (NSArray*)attributesUsedForInsert
334 if (!flags.isPropertiesCacheValid)
335 [self validatePropertiesCache];
336 return self->attributesUsedForInsert;
339 - (NSArray *)attributesUsedForFetch {
340 if (!flags.isPropertiesCacheValid)
341 [self validatePropertiesCache];
342 return self->attributesUsedForFetch;
345 - (NSArray *)relationsUsedForFetch {
346 if (!flags.isPropertiesCacheValid)
347 [self validatePropertiesCache];
348 return self->relationsUsedForFetch;
351 - (NSArray *)attributesNamesUsedForInsert {
352 if (!flags.isPropertiesCacheValid)
353 [self validatePropertiesCache];
354 return self->attributesNamesUsedForInsert;
357 - (BOOL)setClassProperties:(NSArray *)properties {
358 int i, count = [properties count];
360 for(i = 0; i < count; i++)
361 if(![self isValidClassProperty:[properties objectAtIndex:i]])
364 RELEASE(self->classProperties); self->classProperties = nil;
365 RELEASE(self->classPropertyNames); self->classPropertyNames = nil;
367 if([properties isKindOfClass:[NSArray class]]
368 || [properties isKindOfClass:[NSMutableArray class]]) {
369 self->classProperties = [properties copyWithZone:[self zone]];
372 self->classProperties = [[NSArray allocWithZone:[self zone]]
373 initWithArray:properties];
376 self->classPropertyNames = [NSMutableArray arrayWithCapacity:count];
377 for(i = 0; i < count; i++) {
378 id property = [properties objectAtIndex:i];
379 [(NSMutableArray*)classPropertyNames addObject:[(EOAttribute*)property name]];
381 self->classPropertyNames = [self->classPropertyNames copyWithZone:[self zone]];
382 [self invalidatePropertiesCache];
387 - (BOOL)isValidClassProperty:(id)aProperty {
388 id thePropertyName = nil;
390 if(!([aProperty isKindOfClass:[EOAttribute class]]
391 || [aProperty isKindOfClass:[EORelationship class]]))
394 thePropertyName = [(EOAttribute*)aProperty name];
395 if([self->attributesByName objectForKey:thePropertyName]
396 || [self->relationshipsByName objectForKey:thePropertyName])
402 - (NSArray *)relationshipsNamed:(NSString *)_relationshipPath {
403 if([_relationshipPath isNameOfARelationshipPath]) {
404 NSMutableArray *myRelationships = [[NSMutableArray alloc] init];
405 NSArray *defArray = [_relationshipPath componentsSeparatedByString:@"."];
406 int i, count = [defArray count] - 1;
407 EOEntity *currentEntity = self;
408 NSString *relName = nil;
411 for(i = 0; i < count; i++) {
412 relName = [defArray objectAtIndex:i];
414 if([EOEntity isValidName:relName]) {
415 relation = [currentEntity relationshipNamed:relName];
417 [myRelationships addObject:relation];
418 currentEntity = [relation destinationEntity];
422 return AUTORELEASE(myRelationships);
427 - (id)propertyNamed:(NSString *)_name {
428 if([_name isNameOfARelationshipPath]) {
429 NSArray *defArray = [_name componentsSeparatedByString:@"."];
430 EOEntity *currentEntity = self;
431 NSString *propertyName;
432 int i = 0, count = [defArray count];
435 for(; i < count - 1; i++) {
436 propertyName = [defArray objectAtIndex:i];
437 if(![EOEntity isValidName:propertyName])
439 property = [currentEntity propertyNamed:propertyName];
443 currentEntity = [property destinationEntity];
445 propertyName = [defArray lastObject];
446 property = [currentEntity attributeNamed:propertyName];
451 id relationship = nil;
453 attribute = [self->attributesByName objectForKey:_name];
457 relationship = [self->relationshipsByName objectForKey:_name];
465 - (BOOL)setAttributesUsedForLocking:(NSArray *)_attributes {
466 int i, count = [_attributes count];
468 for(i = 0; i < count; i++)
469 if(![self isValidAttributeUsedForLocking:
470 [_attributes objectAtIndex:i]])
473 RELEASE(self->attributesUsedForLocking);
475 if([_attributes isKindOfClass:[NSArray class]]
476 || [_attributes isKindOfClass:[NSMutableArray class]])
477 self->attributesUsedForLocking = [_attributes copy];
479 self->attributesUsedForLocking = [[NSArray alloc] initWithArray:_attributes];
480 [self invalidatePropertiesCache];
485 - (BOOL)isValidAttributeUsedForLocking:(EOAttribute*)anAttribute {
486 if(!([anAttribute isKindOfClass:[EOAttribute class]]
487 && [self->attributesByName objectForKey:[anAttribute name]]))
493 - (void)setModel:(EOModel *)aModel {
494 self->model = aModel; /* non-retained */
500 return (self->model != nil) ? YES : NO;
503 - (void)setClassName:(NSString *)_name {
504 if(!_name) _name = @"EOGenericRecord";
505 ASSIGN(self->className, _name);
508 - (void)setReadOnly:(BOOL)flag
510 flags.isReadOnly = flag;
513 - (BOOL)referencesProperty:(id)property {
514 id propertyName = [(EOAttribute*)property name];
516 if([self->attributesByName objectForKey:propertyName]
517 || [self->relationshipsByName objectForKey:propertyName])
522 - (EOSQLQualifier*)qualifier {
523 if (self->qualifier == nil) {
524 self->qualifier = [[EOSQLQualifier allocWithZone:[self zone]]
526 qualifierFormat:nil];
528 return self->qualifier;
533 - (void)setExternalName:(NSString*)_name {
534 ASSIGN(externalName, _name);
536 - (NSString *)externalName {
537 return self->externalName;
540 - (void)setExternalQuery:(NSString*)query {
541 ASSIGN(externalQuery, query);
543 - (NSString *)externalQuery {
544 return self->externalQuery;
547 - (void)setUserDictionary:(NSDictionary*)dict {
548 ASSIGN(userDictionary, dict);
550 - (NSDictionary *)userDictionary {
551 return self->userDictionary;
558 return self->flags.isReadOnly;
560 - (NSString *)className {
561 return self->className;
563 - (NSArray *)attributesUsedForLocking {
564 return self->attributesUsedForLocking;
566 - (NSArray *)classPropertyNames {
567 return self->classPropertyNames;
569 - (NSArray *)classProperties {
570 return self->classProperties;
572 - (NSArray *)primaryKeyAttributes {
573 return self->primaryKeyAttributes;
575 - (NSArray *)primaryKeyAttributeNames {
576 return self->primaryKeyAttributeNames;
578 - (NSArray *)relationships {
579 return self->relationships;
584 - (NSArray *)attributes {
585 return self->attributes;
588 /* EOEntityCreation */
590 + (EOEntity *)entityFromPropertyList:(id)propertyList model:(EOModel *)_model {
591 NSDictionary *plist = propertyList;
594 NSEnumerator *enumerator;
596 id relationshipPList;
598 entity = [[[EOEntity alloc] init] autorelease];
599 [entity setCreateMutableObjects:YES];
601 entity->name = RETAIN([plist objectForKey:@"name"]);
602 entity->className = RETAIN([plist objectForKey:@"className"]);
603 entity->externalName = RETAIN([plist objectForKey:@"externalName"]);
604 entity->externalQuery = RETAIN([plist objectForKey:@"externalQuery"]);
605 entity->userDictionary = RETAIN([plist objectForKey:@"userDictionary"]);
607 array = [plist objectForKey:@"attributes"];
608 enumerator = [array objectEnumerator];
610 while ((attributePList = [enumerator nextObject])) {
611 EOAttribute *attribute;
613 attribute = [EOAttribute attributeFromPropertyList:attributePList];
615 if (![entity addAttribute:attribute]) {
616 NSLog(@"duplicate name for attribute '%@' in entity '%@'",
617 [attribute name], [entity name]);
618 [_model errorInReading];
622 entity->attributesUsedForLocking
623 = RETAIN([plist objectForKey:@"attributesUsedForLocking"]);
624 entity->classPropertyNames
625 = RETAIN([plist objectForKey:@"classProperties"]);
627 if ((attributePList = [plist objectForKey:@"primaryKeyAttributes"])) {
628 entity->primaryKeyAttributeNames
629 = RETAIN([attributePList sortedArrayUsingSelector:@selector(compare:)]);
633 if ((attributePList = [plist objectForKey:@"primaryKeyAttribute"]))
634 entity->primaryKeyAttributeNames
635 = RETAIN([NSArray arrayWithObject:attributePList]);
637 array = [plist objectForKey:@"relationships"];
638 enumerator = [array objectEnumerator];
639 while((relationshipPList = [enumerator nextObject])) {
640 EORelationship *relationship
641 = [EORelationship relationshipFromPropertyList:relationshipPList
644 if(![entity addRelationship:relationship]) {
645 NSLog(@"duplicate name for relationship '%@' in entity '%@'",
646 [relationship name], [entity name]);
647 [_model errorInReading];
651 [entity setCreateMutableObjects:NO];
656 - (void)replaceStringsWithObjects {
657 NSEnumerator *enumerator = nil;
658 EOAttribute *attribute = nil;
659 NSString *attributeName = nil;
660 NSString *propertyName = nil;
661 NSMutableArray *array = nil;
664 enumerator = [self->primaryKeyAttributeNames objectEnumerator];
665 RELEASE(self->primaryKeyAttributes);
666 self->primaryKeyAttributes = AUTORELEASE([NSMutableArray new]);
668 while ((attributeName = [enumerator nextObject])) {
669 attribute = [self attributeNamed:attributeName];
671 if((attribute == nil) || ![self isValidPrimaryKeyAttribute:attribute]) {
672 NSLog(@"invalid attribute name specified as primary key attribute "
673 @"'%s' in entity '%s'",
674 [attributeName cString], [name cString]);
675 [self->model errorInReading];
678 [(NSMutableArray*)self->primaryKeyAttributes addObject:attribute];
680 self->primaryKeyAttributes = [self->primaryKeyAttributes copy];
682 enumerator = [self->classPropertyNames objectEnumerator];
683 RELEASE(self->classProperties);
684 self->classProperties = AUTORELEASE([NSMutableArray new]);
685 while((propertyName = [enumerator nextObject])) {
688 property = [self propertyNamed:propertyName];
689 if(!property || ![self isValidClassProperty:property]) {
690 NSLog(@"invalid property '%s' specified as class property in "
692 [propertyName cString], [name cString]);
693 [self->model errorInReading];
696 [(NSMutableArray*)self->classProperties addObject:property];
698 self->classProperties = [self->classProperties copy];
700 array = AUTORELEASE([NSMutableArray new]);
701 [array setArray:self->attributesUsedForLocking];
702 RELEASE(self->attributesUsedForLocking);
703 count = [array count];
704 for(i = 0; i < count; i++) {
705 attributeName = [array objectAtIndex:i];
706 attribute = [self attributeNamed:attributeName];
707 if(!attribute || ![self isValidAttributeUsedForLocking:attribute]) {
708 NSLog(@"invalid attribute specified as attribute used for "
709 @"locking '%@' in entity '%@'", attributeName, name);
710 [self->model errorInReading];
713 [array replaceObjectAtIndex:i withObject:attribute];
715 self->attributesUsedForLocking = [array copy];
722 propertyList = [NSMutableDictionary dictionary];
723 [self encodeIntoPropertyList:propertyList];
727 - (void)setCreateMutableObjects:(BOOL)flag {
728 if(self->flags.createsMutableObjects == flag)
731 self->flags.createsMutableObjects = flag;
733 if(self->flags.createsMutableObjects) {
734 self->attributes = [AUTORELEASE(self->attributes) mutableCopy];
735 self->relationships = [AUTORELEASE(self->relationships) mutableCopy];
738 self->attributes = [AUTORELEASE(self->attributes) copy];
739 self->relationships = [AUTORELEASE(self->relationships) copy];
743 - (BOOL)createsMutableObjects {
744 return self->flags.createsMutableObjects;
748 static inline void _printIds(NSArray *a, const char *pfx, const char *indent) {
750 if (pfx == NULL) pfx = "";
751 if (indent == NULL) indent = " ";
753 for (i = 0; i < [a count]; i++)
754 printf("%s0x%08X\n", indent, (unsigned)[a objectAtIndex:i]);
758 static inline BOOL _containsObject(NSArray *a, id obj) {
759 id (*objAtIdx)(NSArray*, SEL, int idx);
762 objAtIdx = (void *)[a methodForSelector:@selector(objectAtIndex:)];
763 for (i = [a count] - 1; i >= 0; i--) {
766 o = objAtIdx(a, @selector(objectAtIndex:), i);
767 if (o == obj) return YES;
772 - (void)validatePropertiesCache
774 NSMutableArray *updAttr = [NSMutableArray new];
775 NSMutableArray *updName = [NSMutableArray new];
776 NSMutableArray *fetAttr = [NSMutableArray new];
777 NSMutableArray *fetRels = [NSMutableArray new];
781 [self invalidatePropertiesCache];
784 NSAssert((updAttr != nil) && (updName != nil) &&
785 (fetAttr != nil) && (fetRels != nil),
786 @"allocation of array failed !");
788 NSAssert(self->primaryKeyAttributes, @"no pkey attributes are set !");
789 NSAssert(self->attributesUsedForLocking, @"no locking attrs are set !");
790 NSAssert(self->classProperties, @"no class properties are set !");
793 //_printIds(self->attributes, "attrs:\n", " ");
794 //_printIds(self->attributesUsedForLocking, "lock:\n", " ");
796 for (i = ([self->attributes count] - 1); i >= 0; i--) {
797 EOAttribute *attr = [self->attributes objectAtIndex:i];
800 pk = _containsObject(self->primaryKeyAttributes, attr);
801 lk = _containsObject(self->attributesUsedForLocking, attr);
802 cp = _containsObject(self->classProperties, attr);
806 NSLog(@"attribute %@ pk=%i lk=%i cp=%i sa=%i",
807 [attr name], pk, lk, cp, sa);
810 if ((pk || lk || cp) && (!_containsObject(fetAttr, attr)))
811 [fetAttr addObject:attr];
813 if ((pk || lk || cp) && (sa) && (!_containsObject(updAttr, attr))) {
814 [updAttr addObject:attr];
815 [updName addObject:[attr name]];
819 for (i = [relationships count]-1; i >= 0; i--) {
820 id rel = [relationships objectAtIndex:i];
822 if (_containsObject(classProperties, rel))
823 [fetRels addObject:rel];
826 RELEASE(self->attributesUsedForInsert);
827 self->attributesUsedForInsert = [[NSArray alloc] initWithArray:updAttr];
828 RELEASE(self->relationsUsedForFetch);
829 self->relationsUsedForFetch = [[NSArray alloc] initWithArray:fetRels];
830 RELEASE(self->attributesUsedForFetch);
831 self->attributesUsedForFetch =
832 [[NSArray alloc] initWithArray:
833 [fetAttr sortedArrayUsingFunction:_compareByName context:nil]];
834 RELEASE(self->attributesNamesUsedForInsert);
835 attributesNamesUsedForInsert = [updName copy];
837 if ([self->attributesUsedForFetch count] == 0) {
838 NSLog(@"WARNING: entity %@ has no fetch attributes: "
841 [[(id)self->attributes mappedArrayUsingSelector:@selector(name)]
842 componentsJoinedByString:@","]);
845 RELEASE(updAttr); updAttr = nil;
846 RELEASE(fetAttr); fetAttr = nil;
847 RELEASE(fetRels); fetRels = nil;
848 RELEASE(updName); updName = nil;
850 self->flags.isPropertiesCacheValid = YES;
853 - (void)invalidatePropertiesCache {
854 if (flags.isPropertiesCacheValid) {
855 RELEASE(self->attributesUsedForInsert);
856 RELEASE(self->attributesUsedForFetch);
857 RELEASE(self->relationsUsedForFetch);
858 RELEASE(self->attributesNamesUsedForInsert);
860 self->attributesUsedForInsert = nil;
861 self->attributesUsedForFetch = nil;
862 self->relationsUsedForFetch = nil;
863 self->attributesNamesUsedForInsert = nil;
865 flags.isPropertiesCacheValid = NO;
871 - (NSString *)description {
872 return [NSString stringWithFormat:
873 @"<%@[0x%08X]: name=%@ className=%@ tableName=%@ "
875 NSStringFromClass([self class]), self,
876 [self name], [self className], [self externalName],
877 [self isReadOnly] ? "YES" : "NO"
881 @end /* EOEntity (EOEntityCreation) */
884 @implementation EOEntity(ValuesConversion)
886 - (NSDictionary *)convertValuesToModel:(NSDictionary *)aRow {
887 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
888 NSEnumerator *enumerator = [aRow keyEnumerator];
891 while ((key = [enumerator nextObject])) {
892 id old = [aRow objectForKey:key];
893 id new = [[self attributeNamed:key] convertValueToModel:old];
895 if (new) [dict setObject:new forKey:key];
898 return [dict count] ? dict : nil;
901 static int _compareByName(id obj1, id obj2, void * context) {
902 return [[(EOAttribute*)obj1 name] compare:[(EOAttribute*)obj2 name]];
905 @end /* EOAttribute (ValuesConversion) */
907 @implementation EOEntity(EOF2Additions)
909 - (BOOL)isAbstractEntity {
915 - (EOGlobalID *)globalIDForRow:(NSDictionary *)_row {
916 static Class EOKeyGlobalIDClass = Nil;
917 unsigned int keyCount = [self->primaryKeyAttributeNames count];
921 for (i = 0; i < keyCount; i++) {
924 attrName = [self->primaryKeyAttributeNames objectAtIndex:i];
925 values[i] = [_row objectForKey:attrName];
927 if (values[i] == nil)
930 if (EOKeyGlobalIDClass == Nil) EOKeyGlobalIDClass = [EOKeyGlobalID class];
932 return [EOKeyGlobalIDClass globalIDWithEntityName:self->name
938 - (BOOL)isPrimaryKeyValidInObject:(id)_object {
939 unsigned int keyCount = [self->primaryKeyAttributeNames count];
942 if (_object == nil) return NO;
944 for (i = 0; i < keyCount; i++) {
945 if ([_object valueForKey:[self->primaryKeyAttributeNames objectAtIndex:i]]
952 /* refs to other models */
954 - (NSArray *)externalModelsReferenced {
956 EORelationship *relship;
957 NSMutableArray *result;
960 thisModel = [self model];
963 e = [self->relationships objectEnumerator];
964 while ((relship = [e nextObject])) {
965 EOEntity *targetEntity;
968 targetEntity = [relship destinationEntity];
969 extModel = [targetEntity model];
971 if (extModel != thisModel) {
972 if (result == nil) result = [NSMutableArray array];
973 [result addObject:extModel];
976 return result ? result : [NSArray array];
981 - (EOFetchSpecification *)fetchSpecificationNamed:(NSString *)_name {
984 - (NSArray *)fetchSpecificationNames {
990 - (void)beautifyName {
991 [self setName:[[self name] _beautifyEntityName]];
994 @end /* EOEntity(EOF2Additions) */
996 @implementation EOEntity(PropertyListCoding)
998 static inline void _addToPropList(NSMutableDictionary *propertyList,
999 id _value, NSString *key) {
1000 if (_value) [propertyList setObject:_value forKey:key];
1003 - (void)encodeIntoPropertyList:(NSMutableDictionary *)_plist {
1006 _addToPropList(_plist, self->name, @"name");
1007 _addToPropList(_plist, self->className, @"className");
1008 _addToPropList(_plist, self->externalName, @"externalName");
1009 _addToPropList(_plist, self->externalQuery, @"externalQuery");
1010 _addToPropList(_plist, self->userDictionary, @"userDictionary");
1012 if ((count = [self->attributes count])) {
1015 attributesPList = [NSMutableArray array];
1016 for (i = 0; i < count; i++) {
1017 NSMutableDictionary *attributePList;
1019 attributePList = [[NSMutableDictionary alloc] init];
1020 [[self->attributes objectAtIndex:i]
1021 encodeIntoPropertyList:attributePList];
1022 [attributesPList addObject:attributePList];
1023 RELEASE(attributePList);
1026 _addToPropList(_plist, attributesPList, @"attributes");
1029 if ((count = [self->attributesUsedForLocking count])) {
1030 id attributesUsedForLockingPList;
1032 attributesUsedForLockingPList = [NSMutableArray array];
1033 for (i = 0; i < count; i++) {
1037 [(EOAttribute*)[self->attributesUsedForLocking objectAtIndex:i] name];
1038 [attributesUsedForLockingPList addObject:attributePList];
1040 _addToPropList(_plist, attributesUsedForLockingPList,
1041 @"attributesUsedForLocking");
1044 if ((count = [self->classProperties count])) {
1045 id classPropertiesPList = nil;
1047 classPropertiesPList = [NSMutableArray array];
1048 for (i = 0; i < count; i++) {
1049 id classPropertyPList;
1051 classPropertyPList =
1052 [(EOAttribute*)[self->classProperties objectAtIndex:i] name];
1053 [classPropertiesPList addObject:classPropertyPList];
1055 _addToPropList(_plist, classPropertiesPList, @"classProperties");
1058 if ((count = [self->primaryKeyAttributes count])) {
1059 id primaryKeyAttributesPList;
1061 primaryKeyAttributesPList = [NSMutableArray array];
1062 for (i = 0; i < count; i++) {
1065 [(EOAttribute*)[self->primaryKeyAttributes objectAtIndex:i] name];
1066 [primaryKeyAttributesPList addObject:attributePList];
1068 _addToPropList(_plist, primaryKeyAttributesPList, @"primaryKeyAttributes");
1071 if ((count = [self->relationships count])) {
1072 id relationshipsPList;
1074 relationshipsPList = [NSMutableArray array];
1075 for (i = 0; i < count; i++) {
1076 NSMutableDictionary *relationshipPList;
1078 relationshipPList = [NSMutableDictionary dictionary];
1080 [[self->relationships objectAtIndex:i]
1081 encodeIntoPropertyList:relationshipPList];
1082 [relationshipsPList addObject:relationshipPList];
1084 _addToPropList(_plist, relationshipsPList, @"relationships");
1088 @end /* EOEntity(PropertyListCoding) */
1090 @implementation NSString(EntityBeautify)
1092 - (NSString *)_beautifyEntityName {
1093 if ([self length] == 0)
1100 clen = [self cStringLength];
1102 s = objc_atomic_malloc(clen + 4);
1104 s = malloc(clen + 4);
1107 [self getCString:s maxLength:clen];
1109 for (cnt = cnt2 = 0; cnt < clen; cnt++, cnt2++) {
1110 if ((s[cnt] == '_') && (s[cnt + 1] != '\0')) {
1111 s[cnt2] = toupper(s[cnt + 1]);
1114 else if ((s[cnt] == '2') && (s[cnt + 1] != '\0')) {
1118 s[cnt2] = toupper(s[cnt]);
1121 s[cnt2] = tolower(s[cnt]);
1125 s[0] = toupper(s[0]);
1127 #if !LIB_FOUNDATION_LIBRARY
1131 os = [NSString stringWithCString:s];
1136 return [NSString stringWithCStringNoCopy:s freeWhenDone:YES];