Annotation of Examples/EnterpriseObjects/FlatFileDataSource/TableDataSource.m, revision 1.1.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.