Search code examples
iosobjective-csqlitecore-datansfetchrequest

Performing basic calculations on Core Data attributes / columns


I am using Core Data based time series (entity/table) which consists of the following attributes / columns:

dateTime mc nd re

Based on the formula result = (mc + nd) / re I would like to calculate the result for each row and return the results (dateTime + value) in an array.

I tried the following code to perform the calculations on the database level but do get wrong results in my result array (multiple dateTime values per row, wrong calculation results). However, the NSExpressionDescription returns the correct formula when NSLogging it.

Do you have any idea on what might be wrong with my code?

NSString *divisorKeyPath = @"revenue"
NSExpression *marketCapExpression = [NSExpression expressionForKeyPath:@"mc"];
NSExpression *netDebtExpression   = [NSExpression expressionForKeyPath:@"nd"];
NSExpression *divisorExpression   = [NSExpression expressionForKeyPath:
    divisorKeyPath];
NSExpression *evExpression        = [NSExpression expressionForFunction:
    @"add:to:"  
    arguments:@[marketCapExpression,netDebtExpression]];
NSExpression *divisionExpression  = [NSExpression expressionForFunction:
    @"divide:by:"
    arguments:@[evExpression, divisorExpression]];
NSString *divisionExpressionName = @"division";
NSExpressionDescription *divisionDescription  = [[NSExpressionDescription alloc] init];
divisionDescription.name                      = divisionExpressionName;
divisionDescription.expression                = divisionExpression;
divisionDescription.expressionResultType      = NSDoubleAttributeType;

NSFetchRequest *divisionRequest = [NSFetchRequest fetchRequestWithEntityName:
   NSStringFromClass([SharePrice class])];
divisionRequest.propertiesToFetch = @[@"dateTime",divisionDescription];
divisionRequest.resultType = NSDictionaryResultType;
NSSortDescriptor *sortDescriptor = [NSSortDescriptor 
   sortDescriptorWithKey:@"dateTime" ascending:YES];
divisionRequest.sortDescriptors = @[sortDescriptor];

NSError *error;
NSArray *divisionResults = [self.managedDocument.managedObjectContext
   executeFetchRequest:divisionRequest error:&error];
NSLog(@"results: %@",divisionResults);

Solution

  • This seems to be a bug in Core Data. If you set the launch argument "-com.apple.CoreData.SQLDebug 3" then you can see that the expression description is translated to the SQLite query

    SELECT t0.ZDATETIME,  t0.ZMARKETCAP +  t0.ZNETDEBT /  t0.ZREVENUE FROM ZENTITY t0 ORDER BY t0.ZDATETIME
    

    and not

    SELECT t0.ZDATETIME,  (t0.ZMARKETCAP +  t0.ZNETDEBT) /  t0.ZREVENUE FROM ZENTITY t0 ORDER BY t0.ZDATETIME
    

    as it should be.

    The divisionExpression itself is correct. If you apply it to a single sharePrice object of your entity, using

    NSNumber *x = [expression expressionValueWithObject:sharePrice context: nil];
    

    it returns the expected result.