4 Copyright (C) 1996 Free Software Foundation, Inc.
6 Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
9 This file is part of the GNUstep Database Library.
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Library General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Library General Public License for more details.
21 You should have received a copy of the GNU Library General Public
22 License along with this library; see the file COPYING.LIB.
23 If not, write to the Free Software Foundation,
24 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #import "EOAttribute.h"
31 #import "EORelationship.h"
32 #import "EOExpressionArray.h"
33 #import "EOCustomValues.h"
34 #import <EOControl/EONull.h>
35 #import "EOFExceptions.h"
37 @interface NSString(BeautifyAttributeName)
39 - (NSString *)_beautifyAttributeName;
43 @implementation EOAttribute
45 static NSString *defaultCalendarFormat = @"%b %d %Y %H:%M";
46 static EONull *null = nil;
50 null = [[EONull null] retain];
53 - (id)initWithName:(NSString*)_name {
54 if ((self = [super init])) {
55 ASSIGN(self->name,_name);
61 return [self initWithName:nil];
66 [self->calendarFormat release];
67 [self->clientTimeZone release];
68 [self->serverTimeZone release];
69 [self->columnName release];
70 [self->externalType release];
71 [self->valueClassName release];
72 [self->valueType release];
73 [self->userDictionary release];
74 self->entity = nil; /* non-retained */
78 // These methods should be here to let the library work with NeXT foundation
82 - (id)copyWithZone:(NSZone *)_zone {
86 // Is equal only if same name; used to make aliasing ordering stable
88 return [self->name hash];
91 - (BOOL)setName:(NSString*)_name {
92 if([name isEqual:_name])
95 if([entity attributeNamed:_name])
102 + (BOOL)isValidName:(NSString*)_name {
103 return [EOEntity isValidName:_name];
106 - (BOOL)referencesProperty:(id)property { // TODO: still used?
110 - (NSString *)expressionValueForContext:(id<EOExpressionContext>)context {
112 ? [context expressionValueForAttribute:self]
116 - (void)setEntity:(EOEntity*)_entity {
117 self->entity = _entity; /* non-retained */
119 - (EOEntity *)entity {
122 - (void)resetEntity {
126 return (self->entity != nil) ? YES : NO;
129 - (void)setCalendarFormat:(NSString*)format {
130 ASSIGN(self->calendarFormat, format);
132 - (NSString *)calendarFormat {
133 return self->calendarFormat;
136 - (void)setClientTimeZone:(NSTimeZone*)tz {
137 ASSIGN(self->clientTimeZone, tz);
139 - (NSTimeZone *)clientTimeZone {
140 return self->clientTimeZone;
143 - (void)setServerTimeZone:(NSTimeZone*)tz {
144 ASSIGN(self->serverTimeZone, tz);
146 - (NSTimeZone *)serverTimeZone {
147 return self->serverTimeZone;
150 - (void)setColumnName:(NSString *)_name {
151 ASSIGNCOPY(self->columnName, _name);
153 - (NSString *)columnName {
154 return self->columnName;
157 - (void)setExternalType:(NSString *)type {
158 ASSIGNCOPY(self->externalType, type);
160 - (NSString *)externalType {
161 return self->externalType;
164 - (void)setValueClassName:(NSString *)_name {
165 ASSIGNCOPY(self->valueClassName, _name);
167 - (NSString *)valueClassName {
168 return self->valueClassName;
171 - (void)setValueType:(NSString *)type {
172 ASSIGN(self->valueType, type);
174 - (NSString *)valueType {
175 return self->valueType;
178 - (void)setUserDictionary:(NSDictionary *)dict {
179 ASSIGN(self->userDictionary, dict);
181 - (NSDictionary *)userDictionary {
182 return self->userDictionary;
185 + (NSString *)defaultCalendarFormat {
186 return defaultCalendarFormat;
194 - (NSString *)description {
195 return [[self propertyList] description];
198 /* EOAttributePrivate */
200 + (EOAttribute*)attributeFromPropertyList:(id)propertyList {
201 NSDictionary *plist = propertyList;
202 EOAttribute *attribute = nil;
203 NSString *timeZoneName;
206 attribute = [[[EOAttribute alloc] init] autorelease];
208 [attribute setName:[plist objectForKey:@"name"]];
209 [attribute setCalendarFormat:[plist objectForKey:@"calendarFormat"]];
211 timeZoneName = [plist objectForKey:@"clientTimeZone"];
213 [attribute setClientTimeZone:[NSTimeZone timeZoneWithName:timeZoneName]];
215 timeZoneName = [plist objectForKey:@"serverTimeZone"];
217 [attribute setServerTimeZone:[NSTimeZone timeZoneWithName:timeZoneName]];
219 [attribute setColumnName: [plist objectForKey:@"columnName"]];
220 [attribute setExternalType: [plist objectForKey:@"externalType"]];
221 [attribute setValueClassName:[plist objectForKey:@"valueClassName"]];
222 [attribute setValueType: [plist objectForKey:@"valueType"]];
223 [attribute setUserDictionary:[plist objectForKey:@"userDictionary"]];
225 if ((tmp = [plist objectForKey:@"allowsNull"]))
226 [attribute setAllowsNull:[tmp isEqual:@"Y"]];
228 [attribute setAllowsNull:YES];
230 [attribute setWidth:[[plist objectForKey:@"width"] unsignedIntValue]];
234 /* WARNING: You should call this method from entity after the relationships
235 were constructed and after the `attributes' array contains the real
237 - (void)replaceStringsWithObjects {
241 NSMutableDictionary *propertyList;
243 propertyList = [NSMutableDictionary dictionaryWithCapacity:16];
244 [self encodeIntoPropertyList:propertyList];
248 - (int)compareByName:(EOAttribute *)_other {
249 return [[(EOAttribute *)self name] compare:[_other name]];
252 /* ValuesConversion */
254 - (id)convertValue:(id)aValue toClass:(Class)aClass forType:(NSString*)_type {
258 if (aValue == [EONull null])
261 // Check if we need conversion; we use is kind of because
262 // a string is not a NSString but some concrete class, so is NSData,
263 // NSNumber and may be other classes
264 if ([aValue isKindOfClass:aClass])
267 // We have to convert the aValue
269 // Try EOCustomValues
270 if ([aValue respondsToSelector:@selector(stringForType:)]) {
271 // Special case if aClass is NSNumber
272 if (aClass == [NSNumber class]) {
274 numberWithString:[aValue stringForType:_type]
278 // Even more Special case if aClass is NSCalendar date
279 if (aClass == [NSCalendarDate class]) {
282 format = [self calendarFormat];
284 format = [EOAttribute defaultCalendarFormat];
285 date = [NSCalendarDate
286 dateWithString:[aValue stringForType:_type]
287 calendarFormat:format];
288 [date setCalendarFormat:format];
292 // See if we can alloc a new aValue and initilize it
293 if ([aClass instancesRespondToSelector:
294 @selector(initWithString:type:)]) {
295 return AUTORELEASE([[aClass alloc]
296 initWithString:[aValue stringForType:_type]
301 // Try EODatabaseCustomValues
302 if ([aValue respondsToSelector:@selector(dataForType:)]) {
303 // See if we can alloc a new aValue and initilize it
304 if ([aClass instancesRespondToSelector:
305 @selector(initWithData:type:)]) {
306 return AUTORELEASE([[aClass alloc]
307 initWithData:[aValue dataForType:_type]
312 // Could not convert if got here
316 - (id)convertValueToModel:(id)aValue {
320 // Check value class from attribute
321 aValueClassName = [self valueClassName];
322 aValueClass = NSClassFromString(aValueClassName);
323 if (aValueClass == Nil)
326 return [self convertValue:aValue
327 toClass:aValueClass forType:[self valueType]];
330 @end /* EOAttribute */
332 @implementation NSString(EOAttributeTypeCheck)
334 - (BOOL)isNameOfARelationshipPath {
336 char buf[[self cStringLength] + 1];
340 [self getCString:buf];
342 if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#')
346 if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#' && *s != '$'
356 @end /* NSString(EOAttributeTypeCheck) */
358 @implementation EOAttribute(PropertyListCoding)
360 static inline void _addToPropList(NSMutableDictionary *propertyList,
361 id _value, NSString *key) {
362 if (_value != nil) [propertyList setObject:_value forKey:key];
365 - (void)encodeIntoPropertyList:(NSMutableDictionary *)_plist {
366 _addToPropList(_plist, self->name, @"name");
367 _addToPropList(_plist, self->calendarFormat, @"calendarFormat");
368 _addToPropList(_plist, self->columnName, @"columnName");
369 _addToPropList(_plist, self->externalType, @"externalType");
370 _addToPropList(_plist, self->valueClassName, @"valueClassName");
371 _addToPropList(_plist, self->valueType, @"valueType");
372 _addToPropList(_plist, self->userDictionary, @"userDictionary");
374 if (self->clientTimeZone) {
375 #if !LIB_FOUNDATION_LIBRARY
376 [_plist setObject:[self->clientTimeZone name]
377 forKey:@"clientTimeZone"];
379 [_plist setObject:[self->clientTimeZone timeZoneName]
380 forKey:@"clientTimeZone"];
383 if (self->serverTimeZone) {
384 #if !LIB_FOUNDATION_LIBRARY
385 [_plist setObject:[self->serverTimeZone name]
386 forKey:@"serverTimeZone"];
388 [_plist setObject:[self->serverTimeZone timeZoneName]
389 forKey:@"serverTimeZone"];
393 if (self->width != 0) {
394 [_plist setObject:[NSNumber numberWithUnsignedInt:self->width]
397 if (self->flags.allowsNull) {
398 [_plist setObject:[NSString stringWithCString:"Y"]
399 forKey:@"allowsNull"];
403 @end /* EOAttribute(PropertyListCoding) */
405 @implementation EOAttribute(EOF2Additions)
407 - (void)beautifyName {
408 [self setName:[[self name] _beautifyAttributeName]];
413 - (void)setAllowsNull:(BOOL)_flag {
414 self->flags.allowsNull = _flag ? 1 : 0;
417 return self->flags.allowsNull ? YES : NO;
420 - (void)setWidth:(unsigned)_width {
421 self->width = _width;
427 - (NSException *)validateValue:(id *)_value {
428 if (_value == NULL) return nil;
430 /* check NULL constraint */
431 if (!self->flags.allowsNull) {
432 if ((*_value == nil) || (*_value == null)) {
436 ui = [NSDictionary dictionaryWithObjectsAndKeys:
437 *_value ? *_value : null, @"value",
441 e = [NSException exceptionWithName:@"EOValidationException"
442 reason:@"violated not-null constraint"
448 /* check width constraint */
450 if (self->width != 0) {
451 static Class NSDataClass = Nil;
452 static Class NSStringClass = Nil;
454 if (NSDataClass == nil) NSDataClass = [NSData class];
455 if (NSStringClass == nil) NSStringClass = [NSString class];
457 if ([(NSObject *)[*_value class] isKindOfClass:NSDataClass]) {
460 len = [*_value length];
461 if (len > self->width) {
465 ui = [NSDictionary dictionaryWithObjectsAndKeys:
466 [NSNumber numberWithUnsignedInt:self->width],
468 [NSNumber numberWithUnsignedInt:len], @"width",
469 *_value ? *_value : null, @"value",
473 e = [NSException exceptionWithName:@"EOValidationException"
474 reason:@"data value exceeds allowed attribute width"
479 else if ([(NSObject *)[*_value class] isKindOfClass:NSStringClass]) {
482 len = [*_value cStringLength];
483 if (len > self->width) {
487 ui = [NSDictionary dictionaryWithObjectsAndKeys:
488 [NSNumber numberWithUnsignedInt:self->width],
490 [NSNumber numberWithUnsignedInt:len], @"width",
491 *_value ? *_value : null, @"value",
495 e = [NSException exceptionWithName:@"EOValidationException"
496 reason:@"string value exceeds allowed attribute width"
506 @end /* EOAttribute(EOF2Additions) */
508 @implementation NSString(BeautifyAttributeName)
510 - (NSString *)_beautifyAttributeName {
516 if ([self length] == 0)
519 clen = [self cStringLength];
521 s = objc_atomic_malloc(clen + 4);
523 s = malloc(clen + 4);
526 [self getCString:s maxLength:clen];
528 for (cnt = cnt2 = 0; cnt < clen; cnt++, cnt2++) {
529 if ((s[cnt] == '_') && (s[cnt + 1] != '\0')) {
530 s[cnt2] = toupper(s[cnt + 1]);
533 else if ((s[cnt] == '2') && (s[cnt + 1] != '\0')) {
537 s[cnt2] = toupper(s[cnt]);
540 s[cnt2] = tolower(s[cnt]);
544 #if !LIB_FOUNDATION_LIBRARY
548 os = [NSString stringWithCString:s];
553 return [NSString stringWithCStringNoCopy:s freeWhenDone:YES];
557 @end /* NSString(BeautifyAttributeName) */