Annotation of Examples/EnterpriseObjects/FlatFileDataSource/TableDataSource.m, revision 1.1

1.1     ! root        1: /* TableDataSource.m
        !             2:  *
        !             3:  *  This data source reads a flat file table (such as Product.table or Item.table) 
        !             4:  *  and generates EOGeneric records that can be passed to an EOController.
        !             5:  *
        !             6:  * You may freely copy, distribute, and reuse the code in this example.
        !             7:  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
        !             8:  * fitness for any particular use.
        !             9:  *
        !            10:  *
        !            11:  *
        !            12:  */
        !            13: 
        !            14: #import <appkit/appkit.h>
        !            15: #import <eoaccess/eoaccess.h>
        !            16: #import "TableDataSource.h"
        !            17: #import "TableDataSourcePrivate.h"
        !            18: #import "DetailTableDataSource.h"
        !            19: #include <sys/file.h> 
        !            20: 
        !            21: 
        !            22: #define @QUALIFIER_ALL @"*"
        !            23: #define @QPROPERTY @"PROPERTY"
        !            24: #define @QVALUE @"VALUE"
        !            25: 
        !            26: @implementation TableDataSource
        !            27: 
        !            28: // init a new TableDataSource with an array of EOGeneric records and the path to
        !            29: // the table file (the flat file database!). The entity name will be found from a
        !            30: // record in the array.
        !            31: // Use this initialization method when you have existing records (possibly from
        !            32: // a real database) and you want to save them to a file
        !            33: - initWithEOGenericRecords:(NSArray *)records tablePath:(NSString *)tablePath {
        !            34:        NSString *tableFile;
        !            35:        NSMutableArray *dictArray = [NSMutableArray array];
        !            36:        NSDictionary *dict;
        !            37:        int i;
        !            38: 
        !            39:        // We need at least a record to get the entity
        !            40:        if (![records count]) {
        !            41:                NSLog(@"<initWithEOGenericRecords:tablePath:> No records");
        !            42:                return nil;
        !            43:        }
        !            44:        entity = [[records objectAtIndex:0] entity];
        !            45:        tableFile=[NSString stringWithFormat:@"%@/%@.table", tablePath, [entity name]];
        !            46:        for (i=0; i<[records count]; i++) {
        !            47:                dict = [[records objectAtIndex:i] valuesForKeys:[entity classPropertyNames]];
        !            48:                [dictArray addObject:dict];
        !            49:        }
        !            50:        
        !            51:        // Save the records to a file as a property-list string
        !            52:        if (![[[dictArray description] dataUsingEncoding:NSASCIIStringEncoding] 
        !            53:                        writeToFile:tableFile atomically:NO]) {
        !            54:                NSLog(@"<initWithEOGenericRecords:tablePath:> DataSource %@ failed to save", [entity name]);
        !            55:                return nil;
        !            56:        }
        !            57:        // Call the designated initialization method
        !            58:        else return [self initWithEntity:entity tablePath:tablePath];
        !            59:        
        !            60: }
        !            61: 
        !            62: // The designated initialization method for TableDataSource
        !            63: // Pick an entity in the model, then initialize the source from a flat file that
        !            64: // contains a string representation of an array of dictionaries.
        !            65: // Note that unlike the EODatabaseSataSource, this dataSource has a "state".
        !            66: // It cashes the eos (dictionaries) that it read from the file and also maintains 
        !            67: // a few hash tables to speed up fetch operations...
        !            68: // Although the state of the TableDataSource is an array of dictionaries (I call it
        !            69: // the snapshot) the TabledataSource will copy these dictionaries into an array of 
        !            70: // EOGeneric records before handing them to a controller...
        !            71: - initWithEntity:(EOEntity *)anEntity tablePath:(NSString *)tablePath {
        !            72:        NSString *primaryKey;
        !            73:        NSArray *relations;
        !            74:        NSMutableArray *qualifiers = [NSMutableArray array];
        !            75: 
        !            76:        [super init];
        !            77:        entity = [anEntity retain];
        !            78:        primaryKey = [(EOAttribute *)[[entity primaryKeyAttributes] objectAtIndex:0] name];
        !            79:        relations = [entity relationships];
        !            80:        detailSources = [[NSMutableArray array] retain]; 
        !            81:        return [self initWithTable:tablePath primaryKey:primaryKey qualifierKeys:qualifiers];
        !            82: }
        !            83: 
        !            84: // The new NSObject world, I guess
        !            85: - (void)dealloc {
        !            86:        [table autorelease];
        !            87:        [eos autorelease];
        !            88:        [lookupTables autorelease];
        !            89:        [qualifier autorelease];
        !            90:        [uniqueKey autorelease];
        !            91:        [detailSources autorelease];
        !            92:        [entity autorelease];
        !            93:        [orderByKey autorelease];
        !            94:        [super dealloc];
        !            95: }
        !            96: 
        !            97: // The path to persistent storage, here to the "table" file... 
        !            98: - (NSString *)tablePath {
        !            99:        return table;
        !           100: }
        !           101: 
        !           102: // The other one...
        !           103: - setTablePath:(NSString *)aPath {
        !           104:        [table autorelease];
        !           105:        table = [aPath retain];
        !           106:        return self;
        !           107: }
        !           108: 
        !           109: // The supported entity, we got it from the EOmodel at initialization time
        !           110: - (EOEntity *)entity {
        !           111:        return entity;
        !           112: }
        !           113: 
        !           114: // A custom way (meaning different from the EOF way) to qualify the source for a given property name and value
        !           115: // The equivalent SQL is: WHERE( key = value)
        !           116: - qualifyForProperty:(NSString *)key andValue:value {
        !           117:        NSMutableDictionary *qual = [NSMutableDictionary dictionary];
        !           118:        
        !           119:        if (![[self keys] containsObject:key]) {
        !           120:                NSLog(@"%@ is not a valid property of entity %@", key, [entity name]);
        !           121:                qual=nil;
        !           122:        }
        !           123:        else {
        !           124:                [qual setObject:key forKey:@QPROPERTY];
        !           125:                [qual setObject:value forKey:@QVALUE];
        !           126:        }
        !           127:        return [self setQualifier:qual];
        !           128: }
        !           129: 
        !           130: // Qualify for all records
        !           131: - setEntityQualifier {
        !           132:        NSMutableDictionary *qual =[NSMutableDictionary dictionary];
        !           133:        [qual setObject:uniqueKey forKey:@QPROPERTY];
        !           134:        [qual setObject:@QUALIFIER_ALL forKey:@QVALUE];
        !           135:        return [self setQualifier:qual];
        !           136: }
        !           137: 
        !           138: // Set the qualifier before the fetch
        !           139: - setQualifier:(NSMutableDictionary *)newQualifier {
        !           140:        [qualifier autorelease];
        !           141:        if (newQualifier)  qualifier  = [newQualifier retain];
        !           142:        else qualifier=nil;
        !           143:        //NSLog(@"New qualifier %@", [(NSMutableDictionary *)qualifier description]);
        !           144:        return self;
        !           145: }
        !           146: 
        !           147: - setEmptySetQualifier {
        !           148:        [qualifier autorelease];
        !           149:        qualifier=nil;
        !           150:        return self;
        !           151: }
        !           152: 
        !           153: - (BOOL)orderBy:(NSString *)key {
        !           154:        if (![[self keys] containsObject:key]) return NO;
        !           155:        else {
        !           156:                [orderByKey autorelease];
        !           157:                orderByKey = [key retain];
        !           158:                [eos sortUsingFunction:eoSort context:orderByKey];
        !           159:                return YES;
        !           160:        }
        !           161: }
        !           162: 
        !           163: - setOrderDescendantSources:(BOOL)aFlag {
        !           164:        orderDescendantSources=aFlag;
        !           165:        return self;
        !           166: }
        !           167: 
        !           168: // *************************************  DATASOURCE PROTOCOL ****************/
        !           169: // The class property names (keys for the dictionary or EOGenericRecord)
        !           170: - (NSArray *)keys {
        !           171:        NSArray *attrs = [entity attributes];
        !           172:        NSMutableArray *keys = [NSMutableArray array];
        !           173:        int i;
        !           174: 
        !           175:        for (i=0; i<[attrs count]; i++) {
        !           176:                EOAttribute *at = [attrs objectAtIndex:i];
        !           177:                [keys addObject:[at name]];
        !           178:        }
        !           179:        return keys;
        !           180: }
        !           181: 
        !           182: - createObject{
        !           183:        NSNumber *newId=[self findNextPrimaryKey];
        !           184:        NSMutableDictionary *newObject=[[NSMutableDictionary alloc] init];
        !           185:        
        !           186:        if (!newId) return nil;
        !           187:        else {
        !           188:                NSArray *allKeys = [self keys];
        !           189:                NSArray *relations = [entity relationships];
        !           190:                int i, count;
        !           191: 
        !           192:                for (i=0, count=[allKeys count]; i<count; i++) {
        !           193:                        id key = [allKeys objectAtIndex:i];
        !           194:                        [newObject setObject:@"" forKey:key];
        !           195:                }
        !           196:                for (i=0, count=[relations count]; i<count; i++) {
        !           197:                        EORelationship *rel = [relations objectAtIndex:i];
        !           198:                        if ([rel isToMany]) [newObject setObject:[newId description] forKey:[rel name]];
        !           199:                }
        !           200:                [newObject setObject:[newId description] forKey:uniqueKey];
        !           201:                return newObject;
        !           202:        }
        !           203: }
        !           204: 
        !           205: - (BOOL)insertObject:object {
        !           206:        NSNumber *objectId=[object objectForKey:uniqueKey];
        !           207:        NSArray *allKeys;
        !           208:        int i;
        !           209:        NSMutableDictionary *newObject;
        !           210: 
        !           211:        if (![self isValidNewPrimaryKey:objectId]) {
        !           212:                NSLog(@"DataSource cannot insert; primary key is invalid: %@", [(NSString *)objectId description]);
        !           213:                return NO;
        !           214:        }
        !           215: 
        !           216:        newObject=[NSMutableDictionary dictionary];
        !           217:        allKeys = [self keys];
        !           218:        for (i=0; i<[allKeys count]; i++) {
        !           219:                id key = [allKeys objectAtIndex:i];
        !           220:                id value = [object objectForKey:key];
        !           221:                if ([value isEqual:[EONull null]]) value=@"";
        !           222:                [newObject setObject:value forKey:key];
        !           223:        }
        !           224:        
        !           225:        [eos addObject:newObject];
        !           226:        if (orderByKey) [eos sortUsingFunction:eoSort context:orderByKey];
        !           227:        [self modifyLookupTables];
        !           228:        return YES;
        !           229: }
        !           230: 
        !           231: - (BOOL)deleteAllObjects {
        !           232:        int i;
        !           233:        for (i=[eos count]-1; i>=0; i--) {
        !           234:                [eos removeObject:[eos objectAtIndex:i]];
        !           235:        }
        !           236:        [self modifyLookupTables];
        !           237:        return YES;
        !           238: }
        !           239: 
        !           240: - (BOOL)deleteObject:object {
        !           241:        id primaryKeyValue = [object objectForKey:uniqueKey];
        !           242:        NSMutableArray *deletes=[[lookupTables objectForKey:uniqueKey] objectForKey:primaryKeyValue];
        !           243:        int i;
        !           244: 
        !           245:        if ( !deletes || ![deletes count]) return NO;
        !           246:        for (i=0; i<[deletes count]; i++) {
        !           247:                [eos removeObject:[deletes objectAtIndex:i]];
        !           248:        }
        !           249:        [self modifyLookupTables];
        !           250:        return YES;
        !           251: }
        !           252: 
        !           253: - (BOOL)updateObject:object {
        !           254:        id primaryKeyValue = [object objectForKey:uniqueKey];
        !           255:        NSMutableArray *update=[[lookupTables objectForKey:uniqueKey] objectForKey:primaryKeyValue];
        !           256:        NSArray *allKeys;
        !           257:        NSMutableDictionary *eo;
        !           258:        int i;
        !           259:        NSString *key;
        !           260:        id value;
        !           261: 
        !           262:        if (!update || [update count]!=1) return NO;
        !           263:        allKeys = [self keys];
        !           264:        eo = [update objectAtIndex:0];
        !           265:        for (i=0; i<[allKeys count]; i++) {
        !           266:                key = [allKeys objectAtIndex:i];
        !           267:                value = [object objectForKey:key];
        !           268:                if (!value || [value isEqual:[EONull null]] ) value=@"";
        !           269:                [eo setObject:value forKey:key];
        !           270:        }
        !           271:        if (orderByKey) [eos sortUsingFunction:eoSort context:orderByKey];
        !           272:        [self modifyLookupTables];
        !           273:        return YES;
        !           274: }
        !           275: 
        !           276: - (NSArray *)fetchObjects {
        !           277:        NSArray *records;
        !           278:        NSString *qualifierPropertyKey = [qualifier objectForKey:@QPROPERTY];
        !           279:        NSString *qualifierPropertyValue = [qualifier objectForKey:@QVALUE];
        !           280: 
        !           281:        if (qualifierPropertyKey && qualifierPropertyValue) {
        !           282: 
        !           283:                if ( [qualifierPropertyValue isEqual:@QUALIFIER_ALL] ) {
        !           284:                        records =[self eosArrayToGenericRecordsArray:eos];
        !           285:                }
        !           286:                else {
        !           287:                        NSMutableDictionary *hash = [lookupTables objectForKey:qualifierPropertyKey];
        !           288:                        if (!hash) {
        !           289:                                NSLog(@"No lookup table for qualifier key %@", qualifierPropertyKey);
        !           290:                                records =nil;
        !           291:                        }
        !           292:                        else {
        !           293:                                NSArray *qualifiedEos=[hash objectForKey:qualifierPropertyValue];
        !           294:                                if (!qualifiedEos || ![qualifiedEos count]) {
        !           295:                                        //NSLog(@"No qualified eos where %@=%@", qualifierPropertyKey, [(NSString *)qualifierPropertyValue description]);
        !           296:                                        records =nil;
        !           297:                                }
        !           298:                                records =[self eosArrayToGenericRecordsArray:qualifiedEos];
        !           299:                        }
        !           300: 
        !           301:                }
        !           302:        }
        !           303:        else {
        !           304:                //NSLog(@"nil or uncomplete qualifier %@", [(NSMutableDictionary *)qualifier description]);
        !           305:                records = [NSArray array]; 
        !           306:        }
        !           307:        //NSLog(@"TABLE %@ - FETCHED OBJECTS: %d", [entity name], [records count]);
        !           308:        return records;
        !           309: }
        !           310: 
        !           311: // This is where we save the eos to persistent storage (COMMIT in SQL)
        !           312: - (BOOL)saveObjects{
        !           313:        NSString *tableFile=[NSString stringWithFormat:@"%@/%@.table", table, [entity name]];
        !           314:        if (![[[eos description] dataUsingEncoding:NSASCIIStringEncoding] 
        !           315:                        writeToFile:tableFile atomically:NO]) {
        !           316:                NSString *emess;
        !           317:  
        !           318:                if ( (!access([tableFile cString], F_OK)) && (access([tableFile cString], W_OK)) ) {
        !           319:                        int ans;
        !           320:                        emess = [NSString stringWithFormat:@"\'%@\' data source cannot save changes. You do not have write permission on \'%@\'. Do you want to overwrite?", [entity name], tableFile];
        !           321:                        ans=NXRunAlertPanel("ERROR", [emess cString], "Overwrite", "Cancel", NULL);
        !           322:                        if (ans==NX_ALERTDEFAULT) return [self forceSaveObjects];
        !           323:                        else return NO;
        !           324:                }
        !           325:                else return NO;
        !           326:        }
        !           327:        else return YES;
        !           328: }
        !           329: 
        !           330: - (BOOL)canDelete {
        !           331:        return YES;
        !           332: }
        !           333: 
        !           334: // Not implemented yet...
        !           335: // Coerce a value to the appropriate type.
        !           336: // This method should convert to either an NSNumber, NSString, NSData,
        !           337: // a custom type, or nil.  The value return by this method may be safely
        !           338: // passed to an EO via takeValuesFromDictionary:.  This method is used
        !           339: // by controllers to coerce values supplied from associations before
        !           340: // those values are passed on to the EOs.
        !           341: - coerceValue: value forKey: (NSString *)key {
        !           342:        // sorry, another day , maybe...
        !           343:        return value;
        !           344: }
        !           345: 
        !           346: // ******************************  MASTER DATASOURCE PROTOCOL ****************/
        !           347: // What we are doing here is closer to a master-peer than a master-detail setup.
        !           348: // We are creating the detail dataSource and handing it to the association. 
        !           349: // This new detail dataSource will be attached to the detail controller automatically
        !           350: // From there, the detail controller and its DetailTableDataSource will be on their own
        !           351: // Also notice than in an EOF master-detail setup, a master eo (meaning an eo 
        !           352: // produced by the master source) "carries" its detail eos. In other word if one 
        !           353: // writes [masterEo objectForKey:masterDetailRelationshipKey], the master eo will 
        !           354: // return an array full of detail eos (assuming that the master detail relationship
        !           355: // was set as a class property name in EOModeler). Although it could, the TableDataSource 
        !           356: // does not support that feature...
        !           357: - (id <EOQualifiableDataSources>)dataSourceQualifiedByKey:(NSString *)key {
        !           358:        EORelationship *rel = [entity relationshipNamed:key];
        !           359:        EOEntity *detailEntity=[rel destinationEntity];
        !           360:        DetailTableDataSource *detailSource;
        !           361: 
        !           362:        if (!rel) return nil;
        !           363:        if (!detailEntity) return nil;
        !           364:        detailSource = [[(DetailTableDataSource *)[DetailTableDataSource alloc] initWithMasterDataSource:self entity:detailEntity] autorelease];        
        !           365:        if (orderByKey && orderDescendantSources) [detailSource orderBy:orderByKey];
        !           366: 
        !           367:        // We cash it (I had some grandiose plane, unused today!!)
        !           368:        [detailSources addObject:detailSource];
        !           369:        return detailSource;
        !           370: }
        !           371: 
        !           372: // ***************************************************************************/
        !           373: 
        !           374: // a convenience method to fetch all the objects in the entity
        !           375: - (NSArray *)fetchAllObjects {
        !           376:        NSMutableDictionary *qual =[NSMutableDictionary dictionary];
        !           377:        [qual setObject:uniqueKey forKey:@QPROPERTY];
        !           378:        [qual setObject:@QUALIFIER_ALL forKey:@QVALUE];
        !           379:        [self setQualifier:qual];
        !           380:        return [self fetchObjects];
        !           381: }
        !           382: 
        !           383: // a convenience fetch method
        !           384: - objectForPrimaryKey:value {
        !           385:        id hash = [lookupTables objectForKey:uniqueKey];
        !           386:        NSArray *objects = [hash objectForKey:value];
        !           387:        id object;
        !           388:        EOGenericRecord *record;
        !           389:        NSMutableDictionary *primaryKeyDictionary;
        !           390:        NSString *key;
        !           391:        id copy;
        !           392:        int count, j;
        !           393:        NSArray *allKeys = [self keys];
        !           394: 
        !           395:        if ([objects count]!=1) return nil;
        !           396:        object = [objects objectAtIndex:0];
        !           397:        primaryKeyDictionary=[NSMutableDictionary dictionary];
        !           398:        [primaryKeyDictionary setObject:value forKey:uniqueKey];
        !           399:        record = [[EOGenericRecord alloc] initWithPrimaryKey:primaryKeyDictionary               
        !           400:                                                                                entity:entity];
        !           401:        for (j=0, count=[allKeys count]; j<count; j++) {
        !           402:                key = [allKeys objectAtIndex:j];
        !           403:                copy = [[object objectForKey:key] copy];
        !           404:                [record setObject:[copy autorelease] forKey:key];
        !           405:        }
        !           406:        return [record autorelease];
        !           407: }
        !           408: 
        !           409: - addLookupTableForKey:(NSString *)key {
        !           410:        NSMutableDictionary *hash;
        !           411: 
        !           412:        hash = [self createLookupTableForQualifierKey:key];
        !           413:        [lookupTables setObject:hash forKey:key];
        !           414:        return self;
        !           415: }
        !           416: 
        !           417: 
        !           418: 
        !           419: @end
        !           420: 
        !           421: // *************************************  Private Category ****************/
        !           422: @implementation TableDataSource (Private)
        !           423: 
        !           424: // This initialization method is called by initWithEntity:tablePath:
        !           425: // It sets the key for the primary key  and creates a key->array of objects hash
        !           426: // tables for each element of the qualifiers array.
        !           427: - initWithTable:(NSString *)tablePath primaryKey:(NSString *)primaryKey qualifierKeys:(NSArray *)qualifiers {
        !           428: 
        !           429:        // Create snapshot from table (eos)
        !           430:        table = [tablePath retain];
        !           431:        if (![self createSnapshot]) return nil;
        !           432: 
        !           433:        // Create a dictionary of hash tables for query (key is like @"ID", value is a lookup table)
        !           434:        uniqueKey = [primaryKey retain];
        !           435:        if ( !([self createLookupTables:qualifiers]) ) return nil;
        !           436: 
        !           437:        // set qualifier to select everything 
        !           438:        // To be clean, we should have a qualifier Class, oh well...it is a rush job
        !           439:        // after all
        !           440:        orderByKey=nil;
        !           441:        orderDescendantSources = NO;
        !           442:        qualifier = [[NSMutableDictionary alloc] init];
        !           443:        [qualifier setObject:uniqueKey forKey:@QPROPERTY];
        !           444:        [qualifier setObject:@QUALIFIER_ALL forKey:@QVALUE];
        !           445: 
        !           446:        return self;
        !           447: }
        !           448: 
        !           449: // The flat file is read here and the objects that have been retrieved are cashed
        !           450: // in an instance variable (of class NSMutableArray) called eos
        !           451: - createSnapshot {
        !           452:        NSString *tableFile=[NSString stringWithFormat:@"%@/%@", table, [entity externalName]];
        !           453:        NSString *tableString;
        !           454:        NSArray  *nonMutableEos;
        !           455: 
        !           456:        // read the table file that should be in a property list format 
        !           457:        // Isn't foundation great or what?!!!
        !           458:        if ( !(tableString=[[NSString alloc] initWithContentsOfFile:tableFile]) ||
        !           459:                 !(nonMutableEos = [tableString propertyList]) ) {
        !           460:                        NSLog(@"<createSnapshot> Cannot init from table %@", tableFile);
        !           461:                        return nil;
        !           462:        }
        !           463:        // Make deep mutable copy
        !           464:        else {
        !           465:                NSEnumerator *eoEnumerator = [nonMutableEos objectEnumerator];
        !           466:                NSDictionary *nonMutableEo;
        !           467: 
        !           468:                eos = [[NSMutableArray alloc] init];
        !           469:                while ( nonMutableEo = [eoEnumerator nextObject] ) {
        !           470:                        [eos addObject: [[nonMutableEo mutableCopy] autorelease]];
        !           471:                }
        !           472:        }
        !           473:        return self;
        !           474: }
        !           475: 
        !           476: // Create the lookup tables (to speed up fetch operations)
        !           477: // The qualifiers array contains the property names that we should hash on
        !           478: // a lookup table is in the form key = "a property key" --> value = an array of 
        !           479: // dictionaries...
        !           480: - createLookupTables:(NSArray *)qualifiers {
        !           481:        int i, count;
        !           482:        NSMutableDictionary *hash;
        !           483:        NSString *qualifierKey;
        !           484: 
        !           485:        lookupTables = [[NSMutableDictionary alloc] init];
        !           486:        hash = [self createLookupTableForQualifierKey:uniqueKey];
        !           487:        [lookupTables setObject:hash forKey:uniqueKey];
        !           488: 
        !           489:        for (i=0, count=[qualifiers count]; i<count; i++) {
        !           490:        
        !           491:                qualifierKey = [qualifiers objectAtIndex:i];
        !           492:                if ( ![lookupTables objectForKey:qualifierKey] ) {
        !           493:                        //NSLog(@"Creating lookup table for qualifierKey %@", qualifierKey);
        !           494:                        if ( !(hash = [self createLookupTableForQualifierKey:qualifierKey]) ) return nil;
        !           495:                        [lookupTables setObject:hash forKey:qualifierKey];
        !           496:                }
        !           497:        }
        !           498:        return self;
        !           499: }
        !           500: 
        !           501: // Create a lookup table for a given property name (the key)
        !           502: - createLookupTableForQualifierKey:(NSString *)key {
        !           503: 
        !           504:        NSMutableDictionary *hash;
        !           505:        int i, count;
        !           506:        NSDictionary *eo;
        !           507:        NSMutableArray *values;
        !           508:        id value;
        !           509:        
        !           510:        hash=[NSMutableDictionary dictionary];
        !           511: 
        !           512:        for (i=0, count=[eos count]; i<count; i++) {
        !           513: 
        !           514:                eo = [eos objectAtIndex:i];
        !           515: 
        !           516:                // get the property value for the qualifier key
        !           517:                if ( !(value = [eo objectForKey:key]) ) {
        !           518:                        NSLog(@"<createLookupTableForQualifierKey:> eos dictionary does not respond to qualifier key %@", key);
        !           519:                        return nil;
        !           520:                }
        !           521:        
        !           522:                // It is the first time that we encounter an eo such that propertyValue(key) = value
        !           523:                if ( !(values = [hash objectForKey:value]) ) {
        !           524:                        values = [NSMutableArray array];
        !           525:                        [values addObject:eo];
        !           526:                        [hash setObject:values forKey:[(NSObject *)value description]];
        !           527:                }
        !           528:                // We have already found an eo such that propertyValue(key) = value
        !           529:                else {
        !           530:                        [values addObject:eo];
        !           531:                }
        !           532:        }
        !           533:        //NSLog(@"HASH FOR KEY %@\n%@", key, [(NSDictionary *)hash description]);
        !           534:        return hash;
        !           535: }
        !           536: 
        !           537: // After insert, delete or update opeations, the lookup tables must be refreshed
        !           538: - modifyLookupTables {
        !           539:        NSArray *allKeys=[lookupTables allKeys];
        !           540:        int i, count;
        !           541:        NSString *key;
        !           542:        NSMutableDictionary *hash;
        !           543: 
        !           544:        for (i=0, count=[allKeys count]; i<count; i++) {
        !           545:                key = [allKeys objectAtIndex:i];
        !           546:                [lookupTables removeObjectForKey:key];
        !           547:                hash = [self createLookupTableForQualifierKey:key];
        !           548:                [lookupTables setObject:hash forKey:key];
        !           549:        }
        !           550:        return self;
        !           551: }
        !           552: 
        !           553: // a method to transform an array of eos (state of the TableDataSource) into
        !           554: // an array of EOGeneric records that we can hand to the outside worls...
        !           555: - (NSMutableArray *)eosArrayToGenericRecordsArray:(NSArray *)eoArray {
        !           556:        NSMutableArray *records = [NSMutableArray  array];
        !           557:        int i, eoCount;
        !           558: 
        !           559:        for (i=0, eoCount=[eoArray count]; i<eoCount; i++) {
        !           560:                NSMutableDictionary *eo;
        !           561:                NSMutableDictionary *primaryKey=[NSMutableDictionary dictionary];
        !           562:                EOGenericRecord *record;
        !           563:                NSArray *allKeys;
        !           564:                NSArray *relations;
        !           565:                int j, count;
        !           566: 
        !           567:                eo = [eoArray objectAtIndex:i];
        !           568:                allKeys = [self keys];
        !           569:                [primaryKey setObject:[eo objectForKey:uniqueKey] forKey:uniqueKey];
        !           570:                record = [[[EOGenericRecord alloc] initWithPrimaryKey:primaryKey entity:entity] autorelease];
        !           571:                for (j=0, count=[allKeys count]; j<count; j++) {
        !           572:                        NSString *key = [allKeys objectAtIndex:j];
        !           573:                        id copy;
        !           574: 
        !           575:                        copy = [[eo objectForKey:key] copy];
        !           576:                        [record setObject:[copy autorelease] forKey:key];
        !           577:                }
        !           578:                relations = [entity relationships];
        !           579: 
        !           580:                // We support master-details but not flattened attribute for now!!!
        !           581:                for (j=0, count=[relations count]; j<count; j++) {
        !           582:                        EORelationship *rel = [relations objectAtIndex:j];
        !           583:                        id copy;
        !           584:        
        !           585:                        if ([rel isToMany]) {
        !           586:                                copy = [[eo objectForKey:uniqueKey] copy];
        !           587:                                [record setObject:[copy autorelease] forKey:[rel name]];
        !           588:                        }
        !           589: 
        !           590:                }
        !           591:                [records addObject:record];
        !           592:        }
        !           593:        return records;
        !           594: }
        !           595: 
        !           596: // Unlike the EODatabaseDataSource, when a TableDataSource creates a new object
        !           597: // It sets the primary key value for the created object. 
        !           598: // This method computes the next available primary key (the next in the sequence)
        !           599: - (NSNumber *)findNextPrimaryKey {
        !           600:        int i, max=-1;
        !           601: 
        !           602:        for (i=0; i<[eos count]; i++) {
        !           603:                id eo;
        !           604:                int current;
        !           605: 
        !           606:                eo = [eos objectAtIndex:i];
        !           607:                current = [[eo objectForKey:uniqueKey] intValue];
        !           608:                if (current  > max) max=current;
        !           609:        }
        !           610:        return [NSNumber numberWithInt:max+1];
        !           611: }
        !           612: 
        !           613: // make sure the the primary key of a new object handed for insertion has a valid primary key
        !           614: // (in this case, valid means not used by a record stored in the table)
        !           615: - (BOOL)isValidNewPrimaryKey:(NSNumber *)number {
        !           616:        int i;
        !           617: 
        !           618:        for (i=0; i<[eos count]; i++) {
        !           619:                id eo;
        !           620: 
        !           621:                eo = [eos objectAtIndex:i];
        !           622:                if ([number isEqual:[eo objectForKey:uniqueKey]]) return NO;
        !           623:        }
        !           624:        return YES;
        !           625: }
        !           626: 
        !           627: - (BOOL)forceSaveObjects {
        !           628:        NSString *tableFile=[NSString stringWithFormat:@"%@/%@.table", table, [entity name]];
        !           629:        NSString *emess=@"Cannot overwrite; changes will not be saved...";
        !           630:        NSString *cmd;
        !           631: 
        !           632:        cmd = [NSString stringWithFormat:@"mv %@ %@.otto", tableFile, tableFile];
        !           633:        if (system([cmd cString])) {
        !           634:                NXRunAlertPanel("ERROR", [emess cString], "OK", NULL, NULL);
        !           635:                return NO;
        !           636:        }
        !           637:        cmd = [NSString stringWithFormat:@"cp %@.otto %@; ", tableFile, tableFile];
        !           638:        if (system([cmd cString])) {
        !           639:                NXRunAlertPanel("ERROR", [emess cString], "OK", NULL, NULL);
        !           640:                return NO;
        !           641:        }
        !           642:        cmd = [NSString stringWithFormat:@"rm -f %@.otto; chmod u+w %@", tableFile, tableFile];
        !           643:        system([cmd cString]);
        !           644: 
        !           645:        if (![[[eos description] dataUsingEncoding:NSASCIIStringEncoding] 
        !           646:                        writeToFile:tableFile atomically:NO]) return NO;
        !           647:        else return YES;
        !           648:        
        !           649: }
        !           650: 
        !           651: int eoSort(id eo1, id eo2, void *context) {
        !           652:        NSString *key=(NSString *)context;
        !           653:        NSString *val1, *val2;
        !           654: 
        !           655:        if (!key) return NSOrderedSame;
        !           656:        val1 = [eo1 objectForKey:key];
        !           657:        val2 = [eo2 objectForKey:key];
        !           658:        if (!val1 || !val2) return NSOrderedSame;
        !           659:        else return [val1 compare:val2];
        !           660: }
        !           661: 
        !           662: 
        !           663: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.