<commit_before>//
//  RKManagedObjectRequestOperation.h
//  RestKit
//
//  Created by <NAME> on 8/9/12.
//  Copyright (c) 2012 RestKit. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

#ifdef _COREDATADEFINES_H
#import "RKObjectRequestOperation.h"
#import "RKManagedObjectCaching.h"

/**
 `RKManagedObjectRequestOperation` is a subclass of `RKObjectRequestOperation` that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation` in which the mapping targets `NSManagedObject` objects managed by Core Data.

 The `RKManagedObjectRequestOperation` class extends the basic behavior of an `RKObjectRequestOperation` to meet the constraints imposed by Core Data. In particular, managed object request operations observe the threading requirements by making use of `NSManagedObjectContext` concurrency types, leverage the support for parent/child contexts, and handle obtaining a permanent `NSManagedObjectID` for objects being mapped so that they are addressable across contexts. Object mapping is internally performed within a block provided to the target context via `performBlockAndWait:`, ensuring execution on the appropriate queue.

 Aside from providing the basic infrastructure for successful object mapping into Core Data, a number of additional Core Data specific features are provided by the `RKManagedObjectRequestOperation` class that warrant discussion in detail.

 ## Parent Context

 Every `RKManagedObjectRequestOperation` object must be assigned an `NSManagedObjectContext` in which to persist the results of the underlying object mapping operation. This context is used as the parent context for a new, private `NSManagedObjectContext` with a concurrency type of `NSPrivateQueueConcurrencyType` in which the object mapping is actually performed. The use of this parent context has a number of benefits:

 1. If the context that was assigned to the managed object request operation has a concurrency type of `NSMainQueueConcurrencyType`, then directly mapping into the context would block the execution of the main thread for the duration of the mapping process. The use of the private child context isolates the mapping process from the main thread.
 1. In the event of an error, the private context can be discarded, leaving the state of the parent context unchanged. On successful completion, the private context is saved and 'pushes' its changes up one level into the parent context.

 ## Permanent Managed Object IDs

 One of the confounding factors when working with asycnhronous processes interacting with Core Data is the addressability of managed objects that have not been saved to the persistent store across contexts. Unpersisted `NSManagedObject` instances have an `objectID` that is temporary and unsuitable for use in uniquely addressing a given object across two managed object contexts, even if they have common ancestry and share a persistent store coordinator. To mitigate this addressability issue without requiring objects to be saved to the persistent store, managed object request operations invoke `obtainPermanentIDsForObjects:` on the operation's target object (if any) and all managed objects that were inserted into the context during the mapping process. By the time the operation finishes, all managed objects in the mapping result can be referenced by `objectID` across contexts with no further action.

 ## Identification Attributes &amp; Managed Object Caching

 When object mapping managed objects it is necessary to differentiate between objects that already exist in the local store and those that are being created as part of the mapping process. This ensures that the local store does not become populated with duplicate records. To make this differentiation, RestKit requires that each `RKEntityMapping` be configured with one or more identification attributes. Each identification attribute must correspond to a static attribute assigned by the remote backend system. During mapping, these attributes are used to search the managed object context for an existing managed object. If one is found, the object is updated else a new object is created. Identification attributes are configured on the `[RKEntityMapping identificationAttributes]` property.

 Identification attributes are used in conjunction with the `RKManagedObjectCaching` protocol. Each managed object request operation is associated with an object conforming to the `RKManagedObjectCaching` protocol via the `managedObjectCache` proeprty. This cache is consulted during mapping to find existing objects and when establishing relationships between entities by one or more attributes. Please see the documentation accompanying `RKManagedObjectCaching` and `RKConnectionDescription` classes for more information.

 ## Deleting Managed Objects for `DELETE` requests

 `RKManagedObjectRequestOperation` adds special behavior to `DELETE` requests. Upon retrieving a successful (2xx status code) response for a `DELETE`, the operation will invoke `deleteObject:` with the operations `targetObject` on the managed object context. This will delete the target object from the local store in conjunction the successfully deleted remote representation.

 ## Fetch Request Blocks and Deleting Orphaned Objects

 A common problem when accessing remote resources representing collections of objects is the problem of deletion of remote objects. The `RKManagedObjectRequestOperation` class provides support for the cleanup of such orphaned objects. In order to utilize the functionality, the operation must be able to compare a set of reference objects to the retrieved payload in order to determine which objects exist in the local store, but are no longer being returned by the server. This reference set of objects is built by executing an `NSFetchRequest` that corresponds to the URL being loaded. Configuration of this fetch request is done via an `RKFetchRequestBlock` block object. This block takes a single `NSURL` argument and returns an `NSFetchRequest` objects. An array of these blocks can be provided to the managed object request operation and the array will be searched in reverse order until a non-nil value is returned by a block. Any block that cannot build a fetch request for the given URL is expected to return `nil` to indicate that it does not match the given URL. Processing of the URL is typically performed using an `RKPathMatcher` object against the value returned from the `relativePath` or `relativeString` methods of `NSURL`.

 To illustrate this concept, please consider the following real-world example which builds a fetch request for retrieving the Terminals that exist in an Airport:

    RKObjectManager *manager = [RKObjectManager managerWithBaseURL:@"http://restkit.org"];
    [manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
        RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"/airports/:airport_id/terminals.json"];

        NSDictionary *argsDict = nil;
        BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
        NSString *airportID;
        if (match) {
            airportID = [argsDict objectForKey:@"airport_id"];
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"];
            fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = %@", @([airportID integerValue])]; // NOTE: Coerced from string to number
            fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ];
            return fetchRequest;
        }

        return nil;
    }];

 The above example code defines an `RKFetchRequestBlock` block object that will match an `NSURL` with a relative path matching the pattern `@"/airports/:airport_id/terminals.json"`. If a match is found, the block extracts the `airport_id` key from the matched arguments, coerces its value into a number, and uses it to construct an `NSPredicate` for the primary key attribute of `GGAirport` entity. Take note that the value of the 'airport_id' was coerced from an `NSString` to an `NSNumber` -- failure to so would result in a predicate whose value is equal to `airportID == '1234'` vs. `airportID == 1234`, which will prevent fetch requests from evaluating correctly. Once coerced, the value is used to construct a `NSFetchRequest` object for the `GGTerminal` entity that will retrieve all the managed objects with an airport ID attribute whose value is equal to `airport_id` encoded within the URL's path.

 In more concrete terms, given the URL `http://restkit.org/airports/1234/terminals.json` the block would return an `NSFetchRequest` equal to:

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = 1234"];
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
<commit_msg>Fix typo in documentation for RKManagedObjectRequestOperation related to Fetch Request Blocks and Deleting Orphaned Objects<commit_after>//
//  RKManagedObjectRequestOperation.h
//  RestKit
//
//  Created by <NAME> on 8/9/12.
//  Copyright (c) 2012 RestKit. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

#ifdef _COREDATADEFINES_H
#import "RKObjectRequestOperation.h"
#import "RKManagedObjectCaching.h"

/**
 `RKManagedObjectRequestOperation` is a subclass of `RKObjectRequestOperation` that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation` in which the mapping targets `NSManagedObject` objects managed by Core Data.

 The `RKManagedObjectRequestOperation` class extends the basic behavior of an `RKObjectRequestOperation` to meet the constraints imposed by Core Data. In particular, managed object request operations observe the threading requirements by making use of `NSManagedObjectContext` concurrency types, leverage the support for parent/child contexts, and handle obtaining a permanent `NSManagedObjectID` for objects being mapped so that they are addressable across contexts. Object mapping is internally performed within a block provided to the target context via `performBlockAndWait:`, ensuring execution on the appropriate queue.

 Aside from providing the basic infrastructure for successful object mapping into Core Data, a number of additional Core Data specific features are provided by the `RKManagedObjectRequestOperation` class that warrant discussion in detail.

 ## Parent Context

 Every `RKManagedObjectRequestOperation` object must be assigned an `NSManagedObjectContext` in which to persist the results of the underlying object mapping operation. This context is used as the parent context for a new, private `NSManagedObjectContext` with a concurrency type of `NSPrivateQueueConcurrencyType` in which the object mapping is actually performed. The use of this parent context has a number of benefits:

 1. If the context that was assigned to the managed object request operation has a concurrency type of `NSMainQueueConcurrencyType`, then directly mapping into the context would block the execution of the main thread for the duration of the mapping process. The use of the private child context isolates the mapping process from the main thread.
 1. In the event of an error, the private context can be discarded, leaving the state of the parent context unchanged. On successful completion, the private context is saved and 'pushes' its changes up one level into the parent context.

 ## Permanent Managed Object IDs

 One of the confounding factors when working with asycnhronous processes interacting with Core Data is the addressability of managed objects that have not been saved to the persistent store across contexts. Unpersisted `NSManagedObject` instances have an `objectID` that is temporary and unsuitable for use in uniquely addressing a given object across two managed object contexts, even if they have common ancestry and share a persistent store coordinator. To mitigate this addressability issue without requiring objects to be saved to the persistent store, managed object request operations invoke `obtainPermanentIDsForObjects:` on the operation's target object (if any) and all managed objects that were inserted into the context during the mapping process. By the time the operation finishes, all managed objects in the mapping result can be referenced by `objectID` across contexts with no further action.

 ## Identification Attributes &amp; Managed Object Caching

 When object mapping managed objects it is necessary to differentiate between objects that already exist in the local store and those that are being created as part of the mapping process. This ensures that the local store does not become populated with duplicate records. To make this differentiation, RestKit requires that each `RKEntityMapping` be configured with one or more identification attributes. Each identification attribute must correspond to a static attribute assigned by the remote backend system. During mapping, these attributes are used to search the managed object context for an existing managed object. If one is found, the object is updated else a new object is created. Identification attributes are configured on the `[RKEntityMapping identificationAttributes]` property.

 Identification attributes are used in conjunction with the `RKManagedObjectCaching` protocol. Each managed object request operation is associated with an object conforming to the `RKManagedObjectCaching` protocol via the `managedObjectCache` proeprty. This cache is consulted during mapping to find existing objects and when establishing relationships between entities by one or more attributes. Please see the documentation accompanying `RKManagedObjectCaching` and `RKConnectionDescription` classes for more information.

 ## Deleting Managed Objects for `DELETE` requests

 `RKManagedObjectRequestOperation` adds special behavior to `DELETE` requests. Upon retrieving a successful (2xx status code) response for a `DELETE`, the operation will invoke `deleteObject:` with the operations `targetObject` on the managed object context. This will delete the target object from the local store in conjunction the successfully deleted remote representation.

 ## Fetch Request Blocks and Deleting Orphaned Objects

 A common problem when accessing remote resources representing collections of objects is the problem of deletion of remote objects. The `RKManagedObjectRequestOperation` class provides support for the cleanup of such orphaned objects. In order to utilize the functionality, the operation must be able to compare a set of reference objects to the retrieved payload in order to determine which objects exist in the local store, but are no longer being returned by the server. This reference set of objects is built by executing an `NSFetchRequest` that corresponds to the URL being loaded. Configuration of this fetch request is done via an `RKFetchRequestBlock` block object. This block takes a single `NSURL` argument and returns an `NSFetchRequest` object. An array of these blocks can be provided to the managed object request operation and the array will be searched in reverse order until a non-nil value is returned by a block. Any block that cannot build a fetch request for the given URL is expected to return `nil` to indicate that it does not match the given URL. Processing of the URL is typically performed using an `RKPathMatcher` object against the value returned from the `relativePath` or `relativeString` methods of `NSURL`.

 To illustrate this concept, please consider the following real-world example which builds a fetch request for retrieving the Terminals that exist in an Airport:

    RKObjectManager *manager = [RKObjectManager managerWithBaseURL:@"http://restkit.org"];
    [manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
        RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"/airports/:airport_id/terminals.json"];

        NSDictionary *argsDict = nil;
        BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
        NSString *airportID;
        if (match) {
            airportID = [argsDict objectForKey:@"airport_id"];
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"];
            fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = %@", @([airportID integerValue])]; // NOTE: Coerced from string to number
            fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ];
            return fetchRequest;
        }

        return nil;
    }];

 The above example code defines an `RKFetchRequestBlock` block object that will match an `NSURL` with a relative path matching the pattern `@"/airports/:airport_id/terminals.json"`. If a match is found, the block extracts the `airport_id` key from the matched arguments, coerces its value into a number, and uses it to construct an `NSPredicate` for the primary key attribute of `GGAirport` entity. Take note that the value of the 'airport_id' was coerced from an `NSString` to an `NSNumber` -- failure to so would result in a predicate whose value is equal to `airportID == '1234'` vs. `airportID == 1234`, which will prevent fetch requests from evaluating correctly. Once coerced, the value is used to construct a `NSFetchRequest` object for the `GGTerminal` entity that will retrieve all the managed objects with an airport ID attribute whose value is equal to `airport_id` encoded within the URL's path.

 In more concrete terms, given the URL `http://restkit.org/airports/1234/terminals.json` the block would return an `NSFetchRequest` equal to:

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = 1234"];
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];

{'fraction_non_alphanumeric': 0.04928880320950346, 'fraction_numerical': 0.0032303443963945188, 'mean_word_length': 4.988767550702028, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7650945', 'n_tokens_mistral': 4460, 'n_tokens_neox': 4188, 'n_words': 2454}