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 NSMutableArray *buildRelShips = [NSMutableArray arrayWithCapacity:64];
107 EOModel *model = AUTORELEASE([EOModel new]);
108 int cnt, tc = [_tableNames count];
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];
123 int ac = [attributes count];
124 int fkc = [fkeys count];
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];
134 for (cnt2 = 0; cnt2 < ac; cnt2++) {
135 EOAttribute *attribute = [attributes objectAtIndex:cnt2];
136 NSString *columnName = [attribute columnName];
138 [entity addAttribute:attribute];
139 [classProperties addObject:attribute];
141 if ([pkeys containsObject:columnName])
142 [primaryKeyAttributes addObject:attribute];
144 [entity setClassProperties:classProperties];
145 [entity setPrimaryKeyAttributes:primaryKeyAttributes];
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];
157 [[[EOJoin alloc] init] autorelease];
158 NSString *relName = nil;
160 if ([pkeys containsObject:sa]) {
161 relName = [@"to" stringByAppendingString:
162 [dt _sqlite3ModelMakeClassName]];
165 relName = [@"to" stringByAppendingString:
166 [[sa _sqlite3ModelMakeInstanceVarName]
167 _sqlite3StringWithCapitalizedFirstChar]];
168 if ([relName hasSuffix:@"Id"]) {
169 int cLength = [relName cStringLength];
171 relName = [relName substringToIndex:cLength - 2];
174 if ([relNamesUsed objectForKey:relName]) {
175 int useCount = [[relNamesUsed objectForKey:relName] intValue];
177 [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)]
179 relName = [NSString stringWithFormat:@"%s%d",
180 [relName cString], useCount];
183 [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
185 [rel setName:relName];
186 //[rel setDestinationEntity:(EOEntity *)[dt _sqlite3ModelMakeClassName]];
189 // TODO: EOJoin is removed, fix this ...
190 [(id)join setSourceAttribute:
191 (EOAttribute *)[sa _sqlite3ModelMakeInstanceVarName]];
192 [(id)join setDestinationAttribute:
193 (EOAttribute *)[da _sqlite3ModelMakeInstanceVarName]];
196 [entity addRelationship:rel];
197 [classProperties addObjectsFromArray:[entity classProperties]];
198 [classProperties addObject:rel];
199 [entity setClassProperties:classProperties];
200 [buildRelShips addObject:rel];
203 [entity setAttributesUsedForLocking:[entity attributes]];
206 [buildRelShips makeObjectsPerformSelector:
207 @selector(replaceStringsWithObjects)];
209 // make reverse relations
211 int cnt, rc = [buildRelShips count];
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;
223 if ([pkeys containsObject:sa]
225 relName = [@"to" stringByAppendingString:
226 [(EOEntity *)[reverse destinationEntity] name]];
228 relName = [@"to" stringByAppendingString:
229 [[[sa name] _sqlite3ModelMakeInstanceVarName]
230 _sqlite3StringWithCapitalizedFirstChar]];
231 if ([relName hasSuffix:@"Id"]) {
232 int cLength = [relName cStringLength];
234 relName = [relName substringToIndex:cLength - 2];
238 if ([entity relationshipNamed:relName]) {
242 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
243 while ([entity relationshipNamed:numName]) {
245 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
251 [reverse setName:relName];
253 [entity addRelationship:reverse];
255 [classProperties addObjectsFromArray:[entity classProperties]];
256 [classProperties addObject:reverse];
257 [entity setClassProperties:classProperties];
261 [model setAdaptorName:@"SQLite"];
262 [model setAdaptorClassName:@"SQLiteAdaptor"];
263 [model setConnectionDictionary:
264 [[adaptorContext adaptor] connectionDictionary]];
269 - (NSArray *)describeTableNames {
270 NSMutableArray *tableNames = nil;
271 NSArray *resultDescription = nil;
272 NSString *attributeName = nil;
273 NSDictionary *row = nil;
274 NSString *selectExpression = nil;
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]);
283 resultDescription = [self describeResults];
284 attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
285 tableNames = [NSMutableArray arrayWithCapacity:16];
287 while ((row = [self fetchAttributes:resultDescription withZone:NULL])!=nil)
288 [tableNames addObject:[row objectForKey:attributeName]];
293 @end /* SQLiteChannel(ModelFetching) */
295 void __link_SQLiteChannelModel() {
296 // used to force linking of object file
297 __link_SQLiteChannelModel();