Repository: realm/realm-swift
File: Realm/RLMQueryUtil.mm (Objective-C++)

Code before:
    NSArray *arr = [columnName componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"."]];
    NSString *firstColumnName = [arr objectAtIndex:0];
    NSString *secondColumnName;

    BOOL isLinkQuery = NO;
    NSUInteger firstIndex, secondIndex = 0;
    RLMPropertyType secondType = RLMPropertyTypeAny;

    firstIndex = RLMValidatedColumnIndex(desc, firstColumnName);
    RLMProperty *firstProp = desc[firstColumnName];

    // FIXME: when core support multiple levels of link queries, change == to >=
    //        and loop through the elements of arr to build up link query
    if ([arr count] == 2) {
        isLinkQuery = YES;
        if (firstProp.type != RLMPropertyTypeObject && firstProp.type != RLMPropertyTypeArray) {
            throw RLMPredicateException(@"Invalid value", [NSString stringWithFormat:@"column name '%@' is not a link", firstColumnName]);
        }
        secondColumnName = [arr objectAtIndex:1];
        RLMProperty *secondProp = schema[firstProp.objectClassName][secondColumnName];
        secondType = secondProp.type;
        secondIndex = RLMValidatedColumnIndex(schema[firstProp.objectClassName], secondColumnName);
    }
    else if ([arr count] > 2) {
        @throw RLMPredicateException(@"Invalid predicate",
                                     [NSString stringWithFormat:@"Too many levels of relationships: %lu > 2", (unsigned long)[arr count]]);
    }

    BOOL betweenOperation = (operatorType == NSBetweenPredicateOperatorType);
    if (!isLinkQuery) {
        validate_value_for_query(value, firstProp, betweenOperation);
    }
    
    if (betweenOperation) {
        add_between_constraint_to_query(query, firstProp.type, firstIndex, value);
        return;
    }
    
    // finally cast to native types and add query clause
    RLMPropertyType type;
    if (isLinkQuery) {
        type = secondType;
    }
    else {
        type = firstProp.type;
    }
    switch (type) {
        case type_Bool:
            if (isLinkQuery) {
                add_bool_constraint_to_link_query(query, operatorType, firstIndex, secondIndex, bool([(NSNumber *)value boolValue]));
            }

Review comment (suggestion):
Please throw an Objective C exception (`@throw`) and not a C++ exception (`throw`).


Code after:
}
 
void update_link_query_with_value_expression(RLMSchema *schema,
                                             RLMObjectSchema *desc,
                                             tightdb::Query &query,
                                             NSArray *paths,
                                             id value,
                                             NSComparisonPredicate *pred)
{
    if (pred.predicateOperatorType == NSBetweenPredicateOperatorType) {
        @throw RLMPredicateException(@"Invalid predicate", @"BETWEEN operator not supported for KeyPath queries.");
    }

    // FIXME: when core support multiple levels of link queries, change == to >=
    //        and loop through the elements of arr to build up link query
    if (paths.count != 2) {
        @throw RLMPredicateException(@"Invalid predicate", @"Only KeyPaths one level deep are currently supported");
    }
    
    // get the first index and property
    NSUInteger idx1 = RLMValidatedColumnIndex(desc, paths[0]);
    RLMProperty *firstProp = desc[paths[0]];

    // make sure we have a valid property type
    if (firstProp.type != RLMPropertyTypeObject && firstProp.type != RLMPropertyTypeArray) {
        throw RLMPredicateException(@"Invalid value", [NSString stringWithFormat:@"column name '%@' is not a link", paths[0]]);
    }

    // get the next level index and property
    NSUInteger idx2 = RLMValidatedColumnIndex(schema[firstProp.objectClassName], paths[1]);
    RLMProperty *secondProp = schema[firstProp.objectClassName][paths[1]];

    // validate value
    if (!RLMIsObjectValidForProperty(value, secondProp)) {
        @throw RLMPredicateException(@"Invalid value",
                                     [NSString stringWithFormat:@"object for property '%@' must be of type '%@'",
                                      secondProp.name, RLMTypeToString(secondProp.type)]);
    }

    // finally cast to native types and add query clause
    RLMPropertyType type = secondProp.type;
    NSPredicateOperatorType opType = pred.predicateOperatorType;
    switch (type) {
        case type_Bool:
            add_bool_constraint_to_link_query(query, opType, idx1, idx2, bool([(NSNumber *)value boolValue]));
            break;
        case type_DateTime:
            add_datetime_constraint_to_link_query(query, opType, idx1, idx2, double([(NSDate *)value timeIntervalSince1970]));
            break;
        case type_Double:
            add_numeric_constraint_to_link_query(query, type, opType, idx1, idx2, Double([(NSNumber *)value doubleValue]));