]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOAttribute.m
added missing inline pathes
[sope] / sope-gdl1 / GDLAccess / EOAttribute.m
1 /* 
2    EOAttributeOrdering.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
7    Date: 1996
8
9    This file is part of the GNUstep Database Library.
10
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.
15
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.
20
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.
25 */
26
27 #import "common.h"
28 #import "EOAttribute.h"
29 #import "EOModel.h"
30 #import "EOEntity.h"
31 #import "EORelationship.h"
32 #import "EOExpressionArray.h"
33 #import "EOCustomValues.h"
34 #import <EOControl/EONull.h>
35 #import "EOFExceptions.h"
36
37 @interface NSString(BeautifyAttributeName)
38
39 - (NSString *)_beautifyAttributeName;
40
41 @end
42
43 @implementation EOAttribute
44
45 static NSString *defaultCalendarFormat = @"%b %d %Y %H:%M";
46 static EONull   *null = nil;
47
48 + (void)initialize {
49   if (null == nil)
50     null = [[EONull null] retain];
51 }
52
53 - (id)initWithName:(NSString*)_name {
54   if ((self = [super init])) {
55     ASSIGN(self->name,_name);
56     self->entity = nil;
57   }
58   return self;
59 }
60 - (id)init {
61   return [self initWithName:nil];
62 }
63
64 - (void)dealloc {
65   [self->name           release];
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 */
75   [super dealloc];
76 }
77
78 // These methods should be here to let the library work with NeXT foundation
79 - (id)copy {
80   return [self retain];
81 }
82 - (id)copyWithZone:(NSZone *)_zone {
83   return [self retain];
84 }
85
86 // Is equal only if same name; used to make aliasing ordering stable
87 - (unsigned)hash {
88   return [self->name hash];
89 }
90
91 - (BOOL)setName:(NSString*)_name {
92   if([name isEqual:_name])
93     return YES;
94
95   if([entity attributeNamed:_name])
96     return NO;
97
98   ASSIGN(name, _name);
99   return YES;
100 }
101
102 + (BOOL)isValidName:(NSString*)_name {
103   return [EOEntity isValidName:_name];
104 }
105
106 - (BOOL)referencesProperty:(id)property { // TODO: still used?
107   return NO;
108 }
109
110 - (NSString *)expressionValueForContext:(id<EOExpressionContext>)context {
111   return (context)
112     ? [context expressionValueForAttribute:self]
113     : columnName;
114 }
115
116 - (void)setEntity:(EOEntity*)_entity {
117   self->entity = _entity; /* non-retained */
118 }
119 - (EOEntity *)entity {
120   return self->entity;
121 }
122 - (void)resetEntity {
123   self->entity = nil;
124 }
125 - (BOOL)hasEntity {
126   return (self->entity != nil) ? YES : NO;
127 }
128
129 - (void)setCalendarFormat:(NSString*)format {
130   ASSIGN(self->calendarFormat, format);
131 }
132 - (NSString *)calendarFormat {
133   return self->calendarFormat;
134 }
135
136 - (void)setClientTimeZone:(NSTimeZone*)tz {
137   ASSIGN(self->clientTimeZone, tz);
138 }
139 - (NSTimeZone *)clientTimeZone {
140   return self->clientTimeZone;
141 }
142
143 - (void)setServerTimeZone:(NSTimeZone*)tz {
144   ASSIGN(self->serverTimeZone, tz);
145 }
146 - (NSTimeZone *)serverTimeZone {
147   return self->serverTimeZone;
148 }
149
150 - (void)setColumnName:(NSString *)_name {
151   ASSIGNCOPY(self->columnName, _name);
152 }
153 - (NSString *)columnName {
154   return self->columnName;
155 }
156
157 - (void)setExternalType:(NSString *)type {
158   ASSIGNCOPY(self->externalType, type);
159 }
160 - (NSString *)externalType {
161   return self->externalType;
162 }
163
164 - (void)setValueClassName:(NSString *)_name {
165   ASSIGNCOPY(self->valueClassName, _name);
166 }
167 - (NSString *)valueClassName {
168   return self->valueClassName;
169 }
170
171 - (void)setValueType:(NSString *)type {
172   ASSIGN(self->valueType, type);
173 }
174 - (NSString *)valueType {
175   return self->valueType;
176 }
177
178 - (void)setUserDictionary:(NSDictionary *)dict {
179   ASSIGN(self->userDictionary, dict);
180 }
181 - (NSDictionary *)userDictionary {
182   return self->userDictionary;
183 }
184
185 + (NSString *)defaultCalendarFormat {
186   return defaultCalendarFormat;
187 }
188 - (NSString *)name {
189   return self->name;
190 }
191
192 /* description */
193
194 - (NSString *)description {
195   return [[self propertyList] description];
196 }
197
198 /* EOAttributePrivate */
199
200 + (EOAttribute*)attributeFromPropertyList:(id)propertyList {
201   NSDictionary *plist = propertyList;
202   EOAttribute *attribute = nil;
203   NSString    *timeZoneName;
204   id          tmp;
205   
206   attribute = [[[EOAttribute alloc] init] autorelease];
207   
208   [attribute setName:[plist objectForKey:@"name"]];
209   [attribute setCalendarFormat:[plist objectForKey:@"calendarFormat"]];
210
211   timeZoneName = [plist objectForKey:@"clientTimeZone"];
212   if (timeZoneName)
213     [attribute setClientTimeZone:[NSTimeZone timeZoneWithName:timeZoneName]];
214
215   timeZoneName = [plist objectForKey:@"serverTimeZone"];
216   if (timeZoneName)
217     [attribute setServerTimeZone:[NSTimeZone timeZoneWithName:timeZoneName]];
218   
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"]];
224   
225   if ((tmp = [plist objectForKey:@"allowsNull"]))
226     [attribute setAllowsNull:[tmp isEqual:@"Y"]];
227   else
228     [attribute setAllowsNull:YES];
229   
230   [attribute setWidth:[[plist objectForKey:@"width"] unsignedIntValue]];
231   return attribute;
232 }
233
234 /* WARNING: You should call this method from entity after the relationships
235    were constructed and after the `attributes' array contains the real
236    attributes. */
237 - (void)replaceStringsWithObjects {
238 }
239
240 - (id)propertyList {
241   NSMutableDictionary *propertyList;
242
243   propertyList = [NSMutableDictionary dictionaryWithCapacity:16];
244   [self encodeIntoPropertyList:propertyList];
245   return propertyList;
246 }
247
248 - (int)compareByName:(EOAttribute *)_other {
249   return [[(EOAttribute *)self name] compare:[_other name]];
250 }
251
252 /* ValuesConversion */
253
254 - (id)convertValue:(id)aValue toClass:(Class)aClass forType:(NSString*)_type {
255   // Check nil/EONull
256   if (aValue == nil)
257     return nil;
258   if (aValue == [EONull null])
259     return aValue;
260     
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])
265     return aValue;
266     
267     // We have to convert the aValue
268     
269     // Try EOCustomValues
270   if ([aValue respondsToSelector:@selector(stringForType:)]) {
271     // Special case if aClass is NSNumber
272     if (aClass == [NSNumber class]) {
273       return [NSNumber
274                       numberWithString:[aValue stringForType:_type]
275                       type:_type];
276     }
277         
278     // Even more Special case if aClass is NSCalendar date
279     if (aClass == [NSCalendarDate class]) {
280       id format, date;
281             
282       format = [self calendarFormat];
283       if (format == nil)
284         format = [EOAttribute defaultCalendarFormat];
285       date = [NSCalendarDate 
286                              dateWithString:[aValue stringForType:_type]
287                              calendarFormat:format];
288       [date setCalendarFormat:format];
289       return date;
290     }
291         
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]
297                                   type:_type]);
298     }
299   }
300     
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]
308                                   type:_type]);
309     }
310   }
311     
312   // Could not convert if got here
313   return nil;
314 }
315
316 - (id)convertValueToModel:(id)aValue {
317   id aValueClassName;
318   Class aValueClass;
319     
320   // Check value class from attribute
321   aValueClassName = [self valueClassName];
322   aValueClass     = NSClassFromString(aValueClassName);
323   if (aValueClass == Nil)
324     return aValue;
325     
326   return [self convertValue:aValue 
327                toClass:aValueClass forType:[self valueType]];
328 }
329
330 @end /* EOAttribute */
331
332 @implementation NSString(EOAttributeTypeCheck)
333
334 - (BOOL)isNameOfARelationshipPath {
335   BOOL result = NO;
336   char buf[[self cStringLength] + 1];
337   const char *s;
338   
339   s = buf;
340   [self getCString:buf];
341   
342   if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#')
343     return NO;
344
345   for(++s; *s; s++) {
346     if(!isalnum((int)*s) && *s != '@' && *s != '_' && *s != '#' && *s != '$'
347        && *s != '.')
348       return NO;
349     if(*s == '.')
350       result = YES;
351   }
352
353   return result;
354 }
355
356 @end /* NSString(EOAttributeTypeCheck) */
357
358 @implementation EOAttribute(PropertyListCoding)
359
360 static inline void _addToPropList(NSMutableDictionary *propertyList,
361                                   id _value, NSString *key) {
362   if (_value != nil) [propertyList setObject:_value forKey:key];
363 }
364
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");
373   
374   if (self->clientTimeZone) {
375 #if !LIB_FOUNDATION_LIBRARY
376     [_plist setObject:[self->clientTimeZone name]
377             forKey:@"clientTimeZone"];
378 #else
379     [_plist setObject:[self->clientTimeZone timeZoneName]
380             forKey:@"clientTimeZone"];
381 #endif
382   }
383   if (self->serverTimeZone) {
384 #if !LIB_FOUNDATION_LIBRARY
385     [_plist setObject:[self->serverTimeZone name]
386             forKey:@"serverTimeZone"];
387 #else
388     [_plist setObject:[self->serverTimeZone timeZoneName]
389             forKey:@"serverTimeZone"];
390 #endif
391   }
392
393   if (self->width != 0) {
394     [_plist setObject:[NSNumber numberWithUnsignedInt:self->width]
395             forKey:@"width"];
396   }
397   if (self->flags.allowsNull) {
398     [_plist setObject:[NSString stringWithCString:"Y"]
399             forKey:@"allowsNull"];
400   }
401 }
402
403 @end /* EOAttribute(PropertyListCoding) */
404
405 @implementation EOAttribute(EOF2Additions)
406
407 - (void)beautifyName {
408   [self setName:[[self name] _beautifyAttributeName]];
409 }
410
411 /* constraints */
412
413 - (void)setAllowsNull:(BOOL)_flag {
414   self->flags.allowsNull = _flag ? 1 : 0;
415 }
416 - (BOOL)allowsNull {
417   return self->flags.allowsNull ? YES : NO;
418 }
419
420 - (void)setWidth:(unsigned)_width {
421   self->width = _width;
422 }
423 - (unsigned)width {
424   return self->width;
425 }
426
427 - (NSException *)validateValue:(id *)_value {
428   if (_value == NULL) return nil;
429   
430   /* check NULL constraint */
431   if (!self->flags.allowsNull) {
432     if ((*_value == nil) || (*_value == null)) {
433       NSException *e;
434       NSDictionary *ui;
435       
436       ui = [NSDictionary dictionaryWithObjectsAndKeys:
437                            *_value ? *_value : null, @"value",
438                            self,                     @"attribute",
439                            nil];
440       
441       e = [NSException exceptionWithName:@"EOValidationException"
442                        reason:@"violated not-null constraint"
443                        userInfo:ui];
444       return e;
445     }
446   }
447   
448   /* check width constraint */
449   
450   if (self->width != 0) {
451     static Class NSDataClass   = Nil;
452     static Class NSStringClass = Nil;
453
454     if (NSDataClass   == nil) NSDataClass   = [NSData   class];
455     if (NSStringClass == nil) NSStringClass = [NSString class];
456     
457     if ([(NSObject *)[*_value class] isKindOfClass:NSDataClass]) {
458       unsigned len;
459       
460       len = [*_value length];
461       if (len > self->width) {
462         NSException *e;
463         NSDictionary *ui;
464         
465         ui = [NSDictionary dictionaryWithObjectsAndKeys:
466                              [NSNumber numberWithUnsignedInt:self->width],
467                              @"maxWidth",
468                              [NSNumber numberWithUnsignedInt:len], @"width",
469                              *_value ? *_value : null,             @"value",
470                              self,                                 @"attribute",
471                              nil];
472         
473         e = [NSException exceptionWithName:@"EOValidationException"
474                          reason:@"data value exceeds allowed attribute width"
475                          userInfo:ui];
476         return e;
477       }
478     }
479     else if ([(NSObject *)[*_value class] isKindOfClass:NSStringClass]) {
480       unsigned len;
481       
482       len = [*_value cStringLength];
483       if (len > self->width) {
484         NSException *e;
485         NSDictionary *ui;
486         
487         ui = [NSDictionary dictionaryWithObjectsAndKeys:
488                              [NSNumber numberWithUnsignedInt:self->width],
489                              @"maxWidth",
490                              [NSNumber numberWithUnsignedInt:len], @"width",
491                              *_value ? *_value : null,             @"value",
492                              self,                                 @"attribute",
493                              nil];
494         
495         e = [NSException exceptionWithName:@"EOValidationException"
496                          reason:@"string value exceeds allowed attribute width"
497                          userInfo:ui];
498         return e;
499       }
500     }
501   }
502   
503   return nil;
504 }
505
506 @end /* EOAttribute(EOF2Additions) */
507
508 @implementation NSString(BeautifyAttributeName)
509
510 - (NSString *)_beautifyAttributeName {
511   // DML Unicode
512   unsigned clen = 0;
513   char     *s   = NULL;
514   unsigned cnt, cnt2;
515
516   if ([self length] == 0)
517     return @"";
518
519   clen = [self cStringLength];
520 #if GNU_RUNTIME
521   s = objc_atomic_malloc(clen + 4);
522 #else
523   s = malloc(clen + 4);
524 #endif
525
526   [self getCString:s maxLength:clen];
527     
528   for (cnt = cnt2 = 0; cnt < clen; cnt++, cnt2++) {
529       if ((s[cnt] == '_') && (s[cnt + 1] != '\0')) {
530         s[cnt2] = toupper(s[cnt + 1]);
531         cnt++;
532       }
533       else if ((s[cnt] == '2') && (s[cnt + 1] != '\0')) {
534         s[cnt2] = s[cnt];
535         cnt++;
536         cnt2++;
537         s[cnt2] = toupper(s[cnt]);
538       }
539       else
540         s[cnt2] = tolower(s[cnt]);
541   }
542   s[cnt2] = '\0';
543
544 #if !LIB_FOUNDATION_LIBRARY
545   {
546       NSString *os;
547
548       os = [NSString stringWithCString:s];
549       free(s);
550       return os;
551   }
552 #else
553   return [NSString stringWithCStringNoCopy:s freeWhenDone:YES];
554 #endif
555 }
556
557 @end /* NSString(BeautifyAttributeName) */