]> err.no Git - sope/blob - sope-gdl1/SQLite3/SQLiteChannel+Model.m
fixed for new -describeResults: API
[sope] / sope-gdl1 / SQLite3 / SQLiteChannel+Model.m
1 /* 
2    SQLiteChannel+Model.m
3
4    Copyright (C) 2003-2005 SKYRIX Software AG
5
6    Author: Helge Hess (helge.hess@skyrix.com)
7
8    This file is part of the SQLite Adaptor Library
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Library General Public License for more details.
19
20    You should have received a copy of the GNU Library General Public
21    License along with this library; see the file COPYING.LIB.
22    If not, write to the Free Software Foundation,
23    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26 #include "SQLiteChannel.h"
27 #include "NSString+SQLite.h"
28 #include "EOAttribute+SQLite.h"
29 #include "common.h"
30
31 @interface EORelationship(FixMe)
32 - (void)addJoin:(id)_join;
33 @end
34
35 @implementation SQLiteChannel(ModelFetching)
36
37 - (NSArray *)_attributesForTableName:(NSString *)_tableName {
38   NSMutableArray *attributes;
39   NSString       *sqlExpr;
40   NSArray        *resultDescription;
41   NSDictionary   *row;
42   
43   if ([_tableName length] == 0)
44     return nil;
45   
46   attributes = [self->_attributesForTableName objectForKey:_tableName];
47   if (attributes == nil) {
48 #if 1
49     // TODO: we would need to parse the SQL field of 'sqlite_master'?
50     NSLog(@"ERROR(%s): operation not supported on SQLite!",
51           __PRETTY_FUNCTION__);
52     return nil;
53 #else
54     sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
55 #endif
56   
57     if (![self evaluateExpression:sqlExpr]) {
58       fprintf(stderr,
59               "Couldn`t evaluate column-describe '%s' on table '%s'\n",
60               [sqlExpr cString], [_tableName cString]);
61       return nil;
62     }
63   
64     resultDescription = [self describeResults];
65     attributes = [NSMutableArray arrayWithCapacity:16];
66   
67     while ((row = [self fetchAttributes:resultDescription withZone:NULL])) {
68       EOAttribute *attribute;
69       NSString    *columnName   = nil;
70       NSString    *externalType = nil;
71       NSString    *attrName     = nil;
72
73       columnName   = [[row objectForKey:@"attname"] stringValue];
74       attrName     = [columnName _sqlite3ModelMakeInstanceVarName];
75       externalType = [[row objectForKey:@"typname"] stringValue];
76     
77       attribute = [[EOAttribute alloc] init];
78       [attribute setColumnName:columnName];
79       [attribute setName:attrName];
80       [attribute setExternalType:externalType];
81       [attribute loadValueClassForExternalSQLiteType:externalType];
82       [attributes addObject:attribute];
83       [attribute release];
84     }
85     [self->_attributesForTableName setObject:attributes forKey:_tableName];
86     //NSLog(@"got attrs: %@", attributes);
87   }
88   return attributes;
89 }
90
91 - (NSArray *)_primaryKeysNamesForTableName:(NSString *)_tableName {
92   //NSArray *pkNameForTableName = nil;
93
94   if ([_tableName length] == 0)
95     return nil;
96   
97   NSLog(@"ERROR(%s): operation not supported on SQLite!", __PRETTY_FUNCTION__);
98   return nil;
99 }
100
101 - (NSArray *)_foreignKeysForTableName:(NSString *)_tableName {
102   return nil;
103 }
104
105 - (EOModel *)describeModelWithTableNames:(NSArray *)_tableNames {
106   NSMutableArray *buildRelShips = [NSMutableArray arrayWithCapacity:64];
107   EOModel *model = AUTORELEASE([EOModel new]);
108   int cnt, tc = [_tableNames count];
109
110   for (cnt = 0; cnt < tc; cnt++) {
111     NSMutableDictionary *relNamesUsed         =
112       [NSMutableDictionary dictionaryWithCapacity:16];
113     NSMutableArray      *classProperties      =
114       [NSMutableArray arrayWithCapacity:16];
115     NSMutableArray      *primaryKeyAttributes =
116       [NSMutableArray arrayWithCapacity:2];
117     NSString *tableName  = [_tableNames objectAtIndex:cnt];
118     NSArray  *attributes = [self _attributesForTableName:tableName];
119     NSArray  *pkeys      = [self _primaryKeysNamesForTableName:tableName];
120     NSArray  *fkeys      = [self _foreignKeysForTableName:tableName];
121     EOEntity *entity     = [[EOEntity new] autorelease];
122     int      cnt2;
123     int      ac  = [attributes count];
124     int      fkc = [fkeys      count];
125
126     [entity setName:[tableName _sqlite3ModelMakeClassName]];
127     [entity setClassName:
128               [@"EO" stringByAppendingString:[tableName _sqlite3ModelMakeClassName]]];
129     [entity setExternalName:tableName];
130     [classProperties addObjectsFromArray:[entity classProperties]];
131     [primaryKeyAttributes addObjectsFromArray:[entity primaryKeyAttributes]];
132     [model addEntity:entity];
133
134     for (cnt2 = 0; cnt2 < ac; cnt2++) {
135       EOAttribute *attribute  = [attributes objectAtIndex:cnt2];
136       NSString    *columnName = [attribute columnName];
137
138       [entity addAttribute:attribute];
139       [classProperties addObject:attribute];
140
141       if ([pkeys containsObject:columnName])
142         [primaryKeyAttributes addObject:attribute];
143     }
144     [entity setClassProperties:classProperties];
145     [entity setPrimaryKeyAttributes:primaryKeyAttributes];
146     
147     for (cnt2 = 0; cnt2 < fkc; cnt2++) {
148       NSDictionary   *fkey             = [fkeys objectAtIndex:cnt2];
149       NSMutableArray *classProperties  =
150         AUTORELEASE([NSMutableArray new]);
151       NSString       *sa               = [fkey objectForKey:@"sourceAttr"];
152       NSString       *da               = [fkey objectForKey:@"targetAttr"];
153       NSString       *dt               = [fkey objectForKey:@"targetTable"];
154       EORelationship *rel              = 
155         [[[EORelationship alloc] init] autorelease];
156       EOJoin         *join             = 
157         [[[EOJoin alloc] init] autorelease];
158       NSString       *relName          = nil;
159
160       if ([pkeys containsObject:sa]) {
161         relName = [@"to" stringByAppendingString:
162                       [dt _sqlite3ModelMakeClassName]];
163       }
164       else {
165         relName = [@"to" stringByAppendingString:
166                     [[sa _sqlite3ModelMakeInstanceVarName]
167                          _sqlite3StringWithCapitalizedFirstChar]];
168         if ([relName hasSuffix:@"Id"]) {
169           int cLength = [relName cStringLength];
170
171           relName = [relName substringToIndex:cLength - 2];
172         }
173       }
174       if ([relNamesUsed objectForKey:relName]) {
175         int useCount = [[relNamesUsed objectForKey:relName] intValue];
176         
177         [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)] 
178                       forKey:relName];
179         relName = [NSString stringWithFormat:@"%s%d",
180                               [relName cString], useCount];
181       }
182       else
183         [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
184
185       [rel setName:relName];
186       //[rel setDestinationEntity:(EOEntity *)[dt _sqlite3ModelMakeClassName]];
187       [rel setToMany:NO];
188
189       // TODO: EOJoin is removed, fix this ...
190       [(id)join setSourceAttribute:
191              (EOAttribute *)[sa _sqlite3ModelMakeInstanceVarName]];
192       [(id)join setDestinationAttribute:
193              (EOAttribute *)[da _sqlite3ModelMakeInstanceVarName]];
194       [rel addJoin:join];
195       
196       [entity addRelationship:rel];
197       [classProperties addObjectsFromArray:[entity classProperties]];
198       [classProperties addObject:rel];
199       [entity setClassProperties:classProperties];
200       [buildRelShips addObject:rel];
201     }
202
203     [entity setAttributesUsedForLocking:[entity attributes]];
204   }
205
206   [buildRelShips makeObjectsPerformSelector:
207                    @selector(replaceStringsWithObjects)];
208   /*
209   // make reverse relations
210   {
211     int cnt, rc = [buildRelShips count];
212
213     for (cnt = 0; cnt < rc; cnt++) {
214       EORelationship *rel     = [buildRelShips objectAtIndex:cnt];
215       NSMutableArray *classProperties  = [NSMutableArray new];   
216       EORelationship *reverse = [rel reversedRelationShip];
217       EOEntity       *entity  = [rel destinationEntity];
218       NSArray        *pkeys   = [entity primaryKeyAttributes];
219       BOOL           isToMany = [reverse isToMany];
220       EOAttribute    *sa      = [[[reverse joins] lastObject] sourceAttribute];
221       NSString       *relName = nil;
222
223       if ([pkeys containsObject:sa]
224           || isToMany)
225         relName = [@"to" stringByAppendingString:
226                     [(EOEntity *)[reverse destinationEntity] name]];
227       else {
228         relName = [@"to" stringByAppendingString:
229                     [[[sa name] _sqlite3ModelMakeInstanceVarName]
230                           _sqlite3StringWithCapitalizedFirstChar]];
231         if ([relName hasSuffix:@"Id"]) {
232           int cLength = [relName cStringLength];
233
234           relName = [relName substringToIndex:cLength - 2];
235         }
236       }
237
238       if ([entity relationshipNamed:relName]) {
239         int cnt = 1;
240         NSString *numName;
241
242         numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
243         while ([entity relationshipNamed:numName]) {
244           cnt++;
245           numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
246         }
247
248         relName = numName;
249       }
250
251       [reverse setName:relName];
252
253       [entity addRelationship:reverse];
254       
255       [classProperties addObjectsFromArray:[entity classProperties]];
256       [classProperties addObject:reverse];
257       [entity setClassProperties:classProperties];
258     }
259   }
260   */
261   [model setAdaptorName:@"SQLite"];
262   [model setAdaptorClassName:@"SQLiteAdaptor"];
263   [model setConnectionDictionary:
264            [[adaptorContext adaptor] connectionDictionary]];
265   
266   return model;
267 }
268
269 - (NSArray *)describeTableNames {
270   NSMutableArray *tableNames        = nil;
271   NSArray        *resultDescription = nil;
272   NSString       *attributeName     = nil;
273   NSDictionary   *row               = nil;
274   NSString       *selectExpression  = nil;
275   
276   selectExpression = @"SELECT name FROM sqlite_master WHERE type='table'";
277   if (![self evaluateExpression:selectExpression]) {
278     fprintf(stderr, "Could not evaluate table-describe expression '%s'\n",
279             [selectExpression cString]);
280     return nil;
281   }
282   
283   resultDescription = [self describeResults];
284   attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
285   tableNames    = [NSMutableArray arrayWithCapacity:16];
286   
287   while ((row = [self fetchAttributes:resultDescription withZone:NULL])!=nil)
288     [tableNames addObject:[row objectForKey:attributeName]];
289   
290   return tableNames;
291 }
292
293 @end /* SQLiteChannel(ModelFetching) */
294
295 void __link_SQLiteChannelModel() {
296   // used to force linking of object file
297   __link_SQLiteChannelModel();
298 }