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]]))
490 if([anAttribute isDerived])
496 - (void)setModel:(EOModel *)aModel {
497 self->model = aModel; /* non-retained */
503 return (self->model != nil) ? YES : NO;
506 - (void)setClassName:(NSString *)_name {
507 if(!_name) _name = @"EOGenericRecord";
508 ASSIGN(self->className, _name);
511 - (void)setReadOnly:(BOOL)flag
513 flags.isReadOnly = flag;
516 - (BOOL)referencesProperty:(id)property {
517 id propertyName = [(EOAttribute*)property name];
519 if([self->attributesByName objectForKey:propertyName]
520 || [self->relationshipsByName objectForKey:propertyName])
525 - (EOSQLQualifier*)qualifier {
526 if (self->qualifier == nil) {
527 self->qualifier = [[EOSQLQualifier allocWithZone:[self zone]]
529 qualifierFormat:nil];
531 return self->qualifier;
536 - (void)setExternalName:(NSString*)_name {
537 ASSIGN(externalName, _name);
539 - (NSString *)externalName {
540 return self->externalName;
543 - (void)setExternalQuery:(NSString*)query {
544 ASSIGN(externalQuery, query);
546 - (NSString *)externalQuery {
547 return self->externalQuery;
550 - (void)setUserDictionary:(NSDictionary*)dict {
551 ASSIGN(userDictionary, dict);
553 - (NSDictionary *)userDictionary {
554 return self->userDictionary;
561 return self->flags.isReadOnly;
563 - (NSString *)className {
564 return self->className;
566 - (NSArray *)attributesUsedForLocking {
567 return self->attributesUsedForLocking;
569 - (NSArray *)classPropertyNames {
570 return self->classPropertyNames;
572 - (NSArray *)classProperties {
573 return self->classProperties;
575 - (NSArray *)primaryKeyAttributes {
576 return self->primaryKeyAttributes;
578 - (NSArray *)primaryKeyAttributeNames {
579 return self->primaryKeyAttributeNames;
581 - (NSArray *)relationships {
582 return self->relationships;
587 - (NSArray *)attributes {
588 return self->attributes;
594 @implementation EOEntity (EOEntityCreation)
596 + (EOEntity *)entityFromPropertyList:(id)propertyList model:(EOModel *)_model {
599 NSEnumerator *enumerator;
601 id relationshipPList;
603 entity = AUTORELEASE([[EOEntity alloc] init]);
604 [entity setCreateMutableObjects:YES];
606 entity->name = RETAIN([propertyList objectForKey:@"name"]);
607 entity->className = RETAIN([propertyList objectForKey:@"className"]);
608 entity->externalName = RETAIN([propertyList objectForKey:@"externalName"]);
609 entity->externalQuery = RETAIN([propertyList objectForKey:@"externalQuery"]);
610 entity->userDictionary = RETAIN([propertyList objectForKey:@"userDictionary"]);
612 array = [propertyList objectForKey:@"attributes"];
613 enumerator = [array objectEnumerator];
615 while ((attributePList = [enumerator nextObject])) {
616 EOAttribute *attribute;
618 attribute = [EOAttribute attributeFromPropertyList:attributePList];
620 if (![entity addAttribute:attribute]) {
621 NSLog(@"duplicate name for attribute '%@' in entity '%@'",
622 [attribute name], [entity name]);
623 [_model errorInReading];
627 entity->attributesUsedForLocking
628 = RETAIN([propertyList objectForKey:@"attributesUsedForLocking"]);
629 entity->classPropertyNames
630 = RETAIN([propertyList objectForKey:@"classProperties"]);
632 if ((attributePList = [propertyList objectForKey:@"primaryKeyAttributes"])) {
633 entity->primaryKeyAttributeNames
634 = RETAIN([attributePList sortedArrayUsingSelector:@selector(compare:)]);
638 if ((attributePList = [propertyList objectForKey:@"primaryKeyAttribute"]))
639 entity->primaryKeyAttributeNames
640 = RETAIN([NSArray arrayWithObject:attributePList]);
642 array = [propertyList objectForKey:@"relationships"];
643 enumerator = [array objectEnumerator];
644 while((relationshipPList = [enumerator nextObject])) {
645 EORelationship *relationship
646 = [EORelationship relationshipFromPropertyList:relationshipPList
649 if(![entity addRelationship:relationship]) {
650 NSLog(@"duplicate name for relationship '%@' in entity '%@'",
651 [relationship name], [entity name]);
652 [_model errorInReading];
656 [entity setCreateMutableObjects:NO];
661 - (void)replaceStringsWithObjects {
662 NSEnumerator *enumerator = nil;
663 EOAttribute *attribute = nil;
664 NSString *attributeName = nil;
665 NSString *propertyName = nil;
666 NSMutableArray *array = nil;
669 enumerator = [self->primaryKeyAttributeNames objectEnumerator];
670 RELEASE(self->primaryKeyAttributes);
671 self->primaryKeyAttributes = AUTORELEASE([NSMutableArray new]);
673 while ((attributeName = [enumerator nextObject])) {
674 attribute = [self attributeNamed:attributeName];
676 if((attribute == nil) || ![self isValidPrimaryKeyAttribute:attribute]) {
677 NSLog(@"invalid attribute name specified as primary key attribute "
678 @"'%s' in entity '%s'",
679 [attributeName cString], [name cString]);
680 [self->model errorInReading];
683 [(NSMutableArray*)self->primaryKeyAttributes addObject:attribute];
685 self->primaryKeyAttributes = [self->primaryKeyAttributes copy];
687 enumerator = [self->classPropertyNames objectEnumerator];
688 RELEASE(self->classProperties);
689 self->classProperties = AUTORELEASE([NSMutableArray new]);
690 while((propertyName = [enumerator nextObject])) {
693 property = [self propertyNamed:propertyName];
694 if(!property || ![self isValidClassProperty:property]) {
695 NSLog(@"invalid property '%s' specified as class property in "
697 [propertyName cString], [name cString]);
698 [self->model errorInReading];
701 [(NSMutableArray*)self->classProperties addObject:property];
703 self->classProperties = [self->classProperties copy];
705 array = AUTORELEASE([NSMutableArray new]);
706 [array setArray:self->attributesUsedForLocking];
707 RELEASE(self->attributesUsedForLocking);
708 count = [array count];
709 for(i = 0; i < count; i++) {
710 attributeName = [array objectAtIndex:i];
711 attribute = [self attributeNamed:attributeName];
712 if(!attribute || ![self isValidAttributeUsedForLocking:attribute]) {
713 NSLog(@"invalid attribute specified as attribute used for "
714 @"locking '%@' in entity '%@'", attributeName, name);
715 [self->model errorInReading];
718 [array replaceObjectAtIndex:i withObject:attribute];
720 self->attributesUsedForLocking = [array copy];
727 propertyList = [NSMutableDictionary dictionary];
728 [self encodeIntoPropertyList:propertyList];
732 - (void)setCreateMutableObjects:(BOOL)flag {
733 if(self->flags.createsMutableObjects == flag)
736 self->flags.createsMutableObjects = flag;
738 if(self->flags.createsMutableObjects) {
739 self->attributes = [AUTORELEASE(self->attributes) mutableCopy];
740 self->relationships = [AUTORELEASE(self->relationships) mutableCopy];
743 self->attributes = [AUTORELEASE(self->attributes) copy];
744 self->relationships = [AUTORELEASE(self->relationships) copy];
748 - (BOOL)createsMutableObjects {
749 return self->flags.createsMutableObjects;
753 static inline void _printIds(NSArray *a, const char *pfx, const char *indent) {
755 if (pfx == NULL) pfx = "";
756 if (indent == NULL) indent = " ";
758 for (i = 0; i < [a count]; i++)
759 printf("%s0x%08X\n", indent, (unsigned)[a objectAtIndex:i]);
763 static inline BOOL _containsObject(NSArray *a, id obj) {
764 id (*objAtIdx)(NSArray*, SEL, int idx);
767 objAtIdx = (void *)[a methodForSelector:@selector(objectAtIndex:)];
768 for (i = [a count] - 1; i >= 0; i--) {
771 o = objAtIdx(a, @selector(objectAtIndex:), i);
772 if (o == obj) return YES;
777 - (void)validatePropertiesCache
779 NSMutableArray *updAttr = [NSMutableArray new];
780 NSMutableArray *updName = [NSMutableArray new];
781 NSMutableArray *fetAttr = [NSMutableArray new];
782 NSMutableArray *fetRels = [NSMutableArray new];
786 [self invalidatePropertiesCache];
789 NSAssert((updAttr != nil) && (updName != nil) &&
790 (fetAttr != nil) && (fetRels != nil),
791 @"allocation of array failed !");
793 NSAssert(self->primaryKeyAttributes, @"no pkey attributes are set !");
794 NSAssert(self->attributesUsedForLocking, @"no locking attrs are set !");
795 NSAssert(self->classProperties, @"no class properties are set !");
798 //_printIds(self->attributes, "attrs:\n", " ");
799 //_printIds(self->attributesUsedForLocking, "lock:\n", " ");
801 for (i = ([self->attributes count] - 1); i >= 0; i--) {
802 EOAttribute *attr = [self->attributes objectAtIndex:i];
805 pk = _containsObject(self->primaryKeyAttributes, attr);
806 lk = _containsObject(self->attributesUsedForLocking, attr);
807 cp = _containsObject(self->classProperties, attr);
808 sa = (![attr isDerived] && ![attr isFlattened]);
810 //NSLog(@"attribute %@ pk=%i lk=%i cp=%i sa=%i", [attr name], pk, lk, cp, sa);
812 if ((pk || lk || cp) && (!_containsObject(fetAttr, attr)))
813 [fetAttr addObject:attr];
815 if ((pk || lk || cp) && (sa) && (!_containsObject(updAttr, attr))) {
816 [updAttr addObject:attr];
817 [updName addObject:[attr name]];
821 for (i = [relationships count]-1; i >= 0; i--) {
822 id rel = [relationships objectAtIndex:i];
824 if (_containsObject(classProperties, rel))
825 [fetRels addObject:rel];
828 RELEASE(self->attributesUsedForInsert);
829 self->attributesUsedForInsert = [[NSArray alloc] initWithArray:updAttr];
830 RELEASE(self->relationsUsedForFetch);
831 self->relationsUsedForFetch = [[NSArray alloc] initWithArray:fetRels];
832 RELEASE(self->attributesUsedForFetch);
833 self->attributesUsedForFetch =
834 [[NSArray alloc] initWithArray:
835 [fetAttr sortedArrayUsingFunction:_compareByName context:nil]];
836 RELEASE(self->attributesNamesUsedForInsert);
837 attributesNamesUsedForInsert = [updName copy];
839 if ([self->attributesUsedForFetch count] == 0) {
840 NSLog(@"WARNING: entity %@ has no fetch attributes: "
843 [[(id)self->attributes mappedArrayUsingSelector:@selector(name)]
844 componentsJoinedByString:@","]);
847 RELEASE(updAttr); updAttr = nil;
848 RELEASE(fetAttr); fetAttr = nil;
849 RELEASE(fetRels); fetRels = nil;
850 RELEASE(updName); updName = nil;
852 self->flags.isPropertiesCacheValid = YES;
855 - (void)invalidatePropertiesCache {
856 if (flags.isPropertiesCacheValid) {
857 RELEASE(self->attributesUsedForInsert);
858 RELEASE(self->attributesUsedForFetch);
859 RELEASE(self->relationsUsedForFetch);
860 RELEASE(self->attributesNamesUsedForInsert);
862 self->attributesUsedForInsert = nil;
863 self->attributesUsedForFetch = nil;
864 self->relationsUsedForFetch = nil;
865 self->attributesNamesUsedForInsert = nil;
867 flags.isPropertiesCacheValid = NO;
873 - (NSString *)description {
874 return [NSString stringWithFormat:
875 @"<%@[0x%08X]: name=%@ className=%@ tableName=%@ "
877 NSStringFromClass([self class]), self,
878 [self name], [self className], [self externalName],
879 [self isReadOnly] ? "YES" : "NO"
883 @end /* EOEntity (EOEntityCreation) */
886 @implementation EOEntity(ValuesConversion)
888 - (NSDictionary *)convertValuesToModel:(NSDictionary *)aRow {
889 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
890 NSEnumerator *enumerator = [aRow keyEnumerator];
893 while ((key = [enumerator nextObject])) {
894 id old = [aRow objectForKey:key];
895 id new = [[self attributeNamed:key] convertValueToModel:old];
897 if (new) [dict setObject:new forKey:key];
900 return [dict count] ? dict : nil;
903 static int _compareByName(id obj1, id obj2, void * context) {
904 return [[(EOAttribute*)obj1 name] compare:[(EOAttribute*)obj2 name]];
907 @end /* EOAttribute (ValuesConversion) */
909 @implementation EOEntity(EOF2Additions)
911 - (BOOL)isAbstractEntity {
917 - (EOGlobalID *)globalIDForRow:(NSDictionary *)_row {
918 static Class EOKeyGlobalIDClass = Nil;
919 unsigned int keyCount = [self->primaryKeyAttributeNames count];
923 for (i = 0; i < keyCount; i++) {
926 attrName = [self->primaryKeyAttributeNames objectAtIndex:i];
927 values[i] = [_row objectForKey:attrName];
929 if (values[i] == nil)
932 if (EOKeyGlobalIDClass == Nil) EOKeyGlobalIDClass = [EOKeyGlobalID class];
934 return [EOKeyGlobalIDClass globalIDWithEntityName:self->name
940 - (BOOL)isPrimaryKeyValidInObject:(id)_object {
941 unsigned int keyCount = [self->primaryKeyAttributeNames count];
944 if (_object == nil) return NO;
946 for (i = 0; i < keyCount; i++) {
947 if ([_object valueForKey:[self->primaryKeyAttributeNames objectAtIndex:i]]
954 /* refs to other models */
956 - (NSArray *)externalModelsReferenced {
958 EORelationship *relship;
959 NSMutableArray *result;
962 thisModel = [self model];
965 e = [self->relationships objectEnumerator];
966 while ((relship = [e nextObject])) {
967 EOEntity *targetEntity;
970 targetEntity = [relship destinationEntity];
971 extModel = [targetEntity model];
973 if (extModel != thisModel) {
974 if (result == nil) result = [NSMutableArray array];
975 [result addObject:extModel];
978 return result ? result : [NSArray array];
983 - (EOFetchSpecification *)fetchSpecificationNamed:(NSString *)_name {
986 - (NSArray *)fetchSpecificationNames {
992 - (void)beautifyName {
993 [self setName:[[self name] _beautifyEntityName]];
996 @end /* EOEntity(EOF2Additions) */
998 @implementation EOEntity(PropertyListCoding)
1000 static inline void _addToPropList(NSMutableDictionary *propertyList,
1001 id _value, NSString *key) {
1002 if (_value) [propertyList setObject:_value forKey:key];
1005 - (void)encodeIntoPropertyList:(NSMutableDictionary *)_plist {
1008 _addToPropList(_plist, self->name, @"name");
1009 _addToPropList(_plist, self->className, @"className");
1010 _addToPropList(_plist, self->externalName, @"externalName");
1011 _addToPropList(_plist, self->externalQuery, @"externalQuery");
1012 _addToPropList(_plist, self->userDictionary, @"userDictionary");
1014 if ((count = [self->attributes count])) {
1017 attributesPList = [NSMutableArray array];
1018 for (i = 0; i < count; i++) {
1019 NSMutableDictionary *attributePList;
1021 attributePList = [[NSMutableDictionary alloc] init];
1022 [[self->attributes objectAtIndex:i]
1023 encodeIntoPropertyList:attributePList];
1024 [attributesPList addObject:attributePList];
1025 RELEASE(attributePList);
1028 _addToPropList(_plist, attributesPList, @"attributes");
1031 if ((count = [self->attributesUsedForLocking count])) {
1032 id attributesUsedForLockingPList;
1034 attributesUsedForLockingPList = [NSMutableArray array];
1035 for (i = 0; i < count; i++) {
1039 [(EOAttribute*)[self->attributesUsedForLocking objectAtIndex:i] name];
1040 [attributesUsedForLockingPList addObject:attributePList];
1042 _addToPropList(_plist, attributesUsedForLockingPList,
1043 @"attributesUsedForLocking");
1046 if ((count = [self->classProperties count])) {
1047 id classPropertiesPList = nil;
1049 classPropertiesPList = [NSMutableArray array];
1050 for (i = 0; i < count; i++) {
1051 id classPropertyPList;
1053 classPropertyPList =
1054 [(EOAttribute*)[self->classProperties objectAtIndex:i] name];
1055 [classPropertiesPList addObject:classPropertyPList];
1057 _addToPropList(_plist, classPropertiesPList, @"classProperties");
1060 if ((count = [self->primaryKeyAttributes count])) {
1061 id primaryKeyAttributesPList;
1063 primaryKeyAttributesPList = [NSMutableArray array];
1064 for (i = 0; i < count; i++) {
1067 [(EOAttribute*)[self->primaryKeyAttributes objectAtIndex:i] name];
1068 [primaryKeyAttributesPList addObject:attributePList];
1070 _addToPropList(_plist, primaryKeyAttributesPList, @"primaryKeyAttributes");
1073 if ((count = [self->relationships count])) {
1074 id relationshipsPList;
1076 relationshipsPList = [NSMutableArray array];
1077 for (i = 0; i < count; i++) {
1078 NSMutableDictionary *relationshipPList;
1080 relationshipPList = [NSMutableDictionary dictionary];
1082 [[self->relationships objectAtIndex:i]
1083 encodeIntoPropertyList:relationshipPList];
1084 [relationshipsPList addObject:relationshipPList];
1086 _addToPropList(_plist, relationshipsPList, @"relationships");
1090 @end /* EOEntity(PropertyListCoding) */
1092 @implementation NSString(EntityBeautify)
1094 - (NSString *)_beautifyEntityName {
1095 if ([self length] == 0)
1102 clen = [self cStringLength];
1104 s = objc_atomic_malloc(clen + 4);
1106 s = malloc(clen + 4);
1109 [self getCString:s maxLength:clen];
1111 for (cnt = cnt2 = 0; cnt < clen; cnt++, cnt2++) {
1112 if ((s[cnt] == '_') && (s[cnt + 1] != '\0')) {
1113 s[cnt2] = toupper(s[cnt + 1]);
1116 else if ((s[cnt] == '2') && (s[cnt + 1] != '\0')) {
1120 s[cnt2] = toupper(s[cnt]);
1123 s[cnt2] = tolower(s[cnt]);
1127 s[0] = toupper(s[0]);
1129 #if !LIB_FOUNDATION_LIBRARY
1133 os = [NSString stringWithCString:s];
1138 return [NSString stringWithCStringNoCopy:s freeWhenDone:YES];