CoreData: API proposal - AGEntityMapper

Background

Mapping JSON representations to a "rich" domain model in ObjC is a bit cumbersome. Similar is true when mapping a JSON data/response to a NSMangedObject (and vise versa). There is a base framework for "remote persistence", via the CoreData API, by leveraging a custom NSIncrementalStore -> AFIncrementalStore.

For that,... a similar two-way-mapping is required, as described here.

AeroGear and CoreData

Our CoreData offerings are leveraging the AFIncrementalStore, therefore (as with other frameworks/libraries) we need a mapping as well. We need to know the name of the entity and we need a NSDictionary that covers the actual JSON/property mapping. It could be done with the vanialla ObjC classes:

// some mappers:
NSDictionary *task_mapper =
  [NSDictionary dictionaryWithObjectsAndKeys:@"description",@"desc",@"id",@"myId", nil];
NSDictionary *project_mapper =
  [NSDictionary dictionaryWithObjectsAndKeys:@"id",@"myId", nil];

// create a schema out of the mappers:
NSDictionary *schema =
  [NSDictionary dictionaryWithObjectsAndKeys:task_mapper, @"Task", project_mapper, @"Project", nil];

// pass the schema to the AGCoreDataHelper class, when doing the init...

Proposal for a custom API

I'd like to introduce a new wrapper type, called AGEntityMapper:

@interface AGEnityMapper : NSObject

@property NSString *name;
@property NSDictionary *mapper;

-(id) initWithName:(NSString *) name mapper:(NSDictionary *) mapper;
@end

This AGEntityMapper would be applied onto the AGCoreDataConfig:

@protocol AGCoreDataConfig <NSObject>

@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSURL *baseURL;

-(void)applyEntityMappers:(AGEnityMapper *)firstObject, ... NS_REQUIRES_NIL_TERMINATION;

@end

The actual code, would look like this:

EnityMapper *taskMapper =
  [[EnityMapper alloc] initWithName:@"Task"
       // mapping the properties on the "entity" (NSManagedObject)
       // to the external representation (e.g. JSON)
                             mapper:@{ @"desc": @"description", @"myId": @"id"}];

EnityMapper *projectMapper =
  [[EnityMapper alloc] initWithName:@"Project"
       // mapping the properties on the "entity" (NSManagedObject)
       // to the external representation (e.g. JSON)
                             mapper:@{ @"myId": @"id"}];

AGCoreDataHelper *helper = [[AGCoreDataHelper alloc] initWithConfig:^(id<AGCoreDataConfig> config) {

  [config setBaseURL:[NSURL URLWithString:@"http://server.com"]];

  [config applyEntityMappers:
    taskMapper,
    projectMapper,
    nil // terminate the varargs.
  ];
}];

--
Matthias Wessendorf

blog: http://matthiaswessendorf.wordpress.com/
sessions: http://www.slideshare.net/mwessendorf
twitter: http://twitter.com/mwessendorf