4 Copyright (C) 2003-2005 SKYRIX Software AG
6 Author: Helge Hess (helge.hess@skyrix.com)
8 This file is part of the SQLite Adaptor Library
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.
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.
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.
26 #include "SQLiteChannel.h"
27 #include "NSString+SQLite.h"
28 #include "EOAttribute+SQLite.h"
31 @interface EORelationship(FixMe)
32 - (void)addJoin:(id)_join;
35 @implementation SQLiteChannel(ModelFetching)
37 - (NSArray *)_attributesForTableName:(NSString *)_tableName {
38 NSMutableArray *attributes;
40 NSArray *resultDescription;
43 if ([_tableName length] == 0)
46 attributes = [self->_attributesForTableName objectForKey:_tableName];
47 if (attributes == nil) {
49 // TODO: we would need to parse the SQL field of 'sqlite_master'?
50 NSLog(@"ERROR(%s): operation not supported on SQLite!",
54 sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
57 if (![self evaluateExpression:sqlExpr]) {
59 "Couldn`t evaluate column-describe '%s' on table '%s'\n",
60 [sqlExpr cString], [_tableName cString]);
64 resultDescription = [self describeResults];
65 attributes = [NSMutableArray arrayWithCapacity:16];
67 while ((row = [self fetchAttributes:resultDescription withZone:NULL])) {
68 EOAttribute *attribute;
69 NSString *columnName = nil;
70 NSString *externalType = nil;
71 NSString *attrName = nil;
73 columnName = [[row objectForKey:@"attname"] stringValue];
74 attrName = [columnName _sqlite3ModelMakeInstanceVarName];
75 externalType = [[row objectForKey:@"typname"] stringValue];
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];
85 [self->_attributesForTableName setObject:attributes forKey:_tableName];
86 //NSLog(@"got attrs: %@", attributes);
91 - (NSArray *)_primaryKeysNamesForTableName:(NSString *)_tableName {
92 //NSArray *pkNameForTableName = nil;
94 if ([_tableName length] == 0)
97 NSLog(@"ERROR(%s): operation not supported on SQLite!", __PRETTY_FUNCTION__);
101 - (NSArray *)_foreignKeysForTableName:(NSString *)_tableName {
105 - (EOModel *)describeModelWithTableNames:(NSArray *)_tableNames {
106 // TODO: is this correct for SQLite?!
107 NSMutableArray *buildRelShips;
111 buildRelShips = [NSMutableArray arrayWithCapacity:64];
112 model = [[[EOModel alloc] init] autorelease];
114 for (cnt = 0, tc = [_tableNames count]; cnt < tc; cnt++) {
115 NSMutableDictionary *relNamesUsed;
116 NSMutableArray *classProperties, *primaryKeyAttributes;
118 NSArray *attributes, *pkeys, *fkeys;
122 relNamesUsed = [NSMutableDictionary dictionaryWithCapacity:16];
123 classProperties = [NSMutableArray arrayWithCapacity:16];
124 primaryKeyAttributes = [NSMutableArray arrayWithCapacity:2];
125 tableName = [_tableNames objectAtIndex:cnt];
126 attributes = [self _attributesForTableName:tableName];
127 pkeys = [self _primaryKeysNamesForTableName:tableName];
128 fkeys = [self _foreignKeysForTableName:tableName];
129 entity = [[[EOEntity alloc] init] autorelease];
130 ac = [attributes count];
133 [entity setName:[tableName _sqlite3ModelMakeClassName]];
134 [entity setClassName:
135 [@"EO" stringByAppendingString:
136 [tableName _sqlite3ModelMakeClassName]]];
137 [entity setExternalName:tableName];
138 [classProperties addObjectsFromArray:[entity classProperties]];
139 [primaryKeyAttributes addObjectsFromArray:[entity primaryKeyAttributes]];
140 [model addEntity:entity];
142 for (cnt2 = 0; cnt2 < ac; cnt2++) {
143 EOAttribute *attribute = [attributes objectAtIndex:cnt2];
144 NSString *columnName = [attribute columnName];
146 [entity addAttribute:attribute];
147 [classProperties addObject:attribute];
149 if ([pkeys containsObject:columnName])
150 [primaryKeyAttributes addObject:attribute];
152 [entity setClassProperties:classProperties];
153 [entity setPrimaryKeyAttributes:primaryKeyAttributes];
155 for (cnt2 = 0; cnt2 < fkc; cnt2++) {
157 NSMutableArray *classProperties;
158 NSString *sa, *da, *dt;
160 EOJoin *join; // TODO: fix me, EOJoin is deprecated
163 fkey = [fkeys objectAtIndex:cnt2];
164 classProperties = [NSMutableArray arrayWithCapacity:8];
165 sa = [fkey objectForKey:@"sourceAttr"];
166 da = [fkey objectForKey:@"targetAttr"];
167 dt = [fkey objectForKey:@"targetTable"];
168 rel = [[[EORelationship alloc] init] autorelease];
171 join = [[[NSClassFromString(@"EOJoin") alloc] init] autorelease];
173 if ([pkeys containsObject:sa]) {
174 relName = [@"to" stringByAppendingString:
175 [dt _sqlite3ModelMakeClassName]];
178 relName = [@"to" stringByAppendingString:
179 [[sa _sqlite3ModelMakeInstanceVarName]
180 _sqlite3StringWithCapitalizedFirstChar]];
181 if ([relName hasSuffix:@"Id"]) {
182 int cLength = [relName cStringLength];
184 relName = [relName substringToIndex:cLength - 2];
187 if ([relNamesUsed objectForKey:relName]) {
188 int useCount = [[relNamesUsed objectForKey:relName] intValue];
190 [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)]
192 relName = [NSString stringWithFormat:@"%s%d",
193 [relName cString], useCount];
196 [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
198 [rel setName:relName];
199 //[rel setDestinationEntity:(EOEntity *)[dt _sqlite3ModelMakeClassName]];
202 // TODO: EOJoin is removed, fix this ...
203 [(id)join setSourceAttribute:
204 (EOAttribute *)[sa _sqlite3ModelMakeInstanceVarName]];
205 [(id)join setDestinationAttribute:
206 (EOAttribute *)[da _sqlite3ModelMakeInstanceVarName]];
209 [entity addRelationship:rel];
210 [classProperties addObjectsFromArray:[entity classProperties]];
211 [classProperties addObject:rel];
212 [entity setClassProperties:classProperties];
213 [buildRelShips addObject:rel];
216 [entity setAttributesUsedForLocking:[entity attributes]];
219 [buildRelShips makeObjectsPerformSelector:
220 @selector(replaceStringsWithObjects)];
222 // make reverse relations
224 int cnt, rc = [buildRelShips count];
226 for (cnt = 0; cnt < rc; cnt++) {
227 EORelationship *rel = [buildRelShips objectAtIndex:cnt];
228 NSMutableArray *classProperties = [NSMutableArray new];
229 EORelationship *reverse = [rel reversedRelationShip];
230 EOEntity *entity = [rel destinationEntity];
231 NSArray *pkeys = [entity primaryKeyAttributes];
232 BOOL isToMany = [reverse isToMany];
233 EOAttribute *sa = [[[reverse joins] lastObject] sourceAttribute];
234 NSString *relName = nil;
236 if ([pkeys containsObject:sa]
238 relName = [@"to" stringByAppendingString:
239 [(EOEntity *)[reverse destinationEntity] name]];
241 relName = [@"to" stringByAppendingString:
242 [[[sa name] _sqlite3ModelMakeInstanceVarName]
243 _sqlite3StringWithCapitalizedFirstChar]];
244 if ([relName hasSuffix:@"Id"]) {
245 int cLength = [relName cStringLength];
247 relName = [relName substringToIndex:cLength - 2];
251 if ([entity relationshipNamed:relName]) {
255 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
256 while ([entity relationshipNamed:numName]) {
258 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
264 [reverse setName:relName];
266 [entity addRelationship:reverse];
268 [classProperties addObjectsFromArray:[entity classProperties]];
269 [classProperties addObject:reverse];
270 [entity setClassProperties:classProperties];
274 [model setAdaptorName:@"SQLite"];
275 [model setAdaptorClassName:@"SQLiteAdaptor"];
276 [model setConnectionDictionary:
277 [[adaptorContext adaptor] connectionDictionary]];
282 - (NSArray *)describeTableNames {
283 NSMutableArray *tableNames = nil;
284 NSArray *resultDescription = nil;
285 NSString *attributeName = nil;
286 NSDictionary *row = nil;
287 NSString *selectExpression = nil;
289 selectExpression = @"SELECT name FROM sqlite_master WHERE type='table'";
290 if (![self evaluateExpression:selectExpression]) {
291 fprintf(stderr, "Could not evaluate table-describe expression '%s'\n",
292 [selectExpression cString]);
296 resultDescription = [self describeResults];
297 attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
298 tableNames = [NSMutableArray arrayWithCapacity:16];
300 while ((row = [self fetchAttributes:resultDescription withZone:NULL])!=nil)
301 [tableNames addObject:[row objectForKey:attributeName]];
306 @end /* SQLiteChannel(ModelFetching) */
308 void __link_SQLiteChannelModel() {
309 // used to force linking of object file
310 __link_SQLiteChannelModel();