Skip to content

Commit

Permalink
Move primary keys mapping from Store and Cache to Deserializer
Browse files Browse the repository at this point in the history
  • Loading branch information
Dima Zen committed Apr 22, 2017
1 parent 3c9cd6f commit 3ebddb9
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 64 deletions.
8 changes: 3 additions & 5 deletions FastEasyMapping/Source/Cache/FEMObjectCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ typedef _Nonnull id<NSFastEnumeration> (^FEMObjectCacheSource)(FEMMapping *mappi

- (instancetype)initWithSource:(FEMObjectCacheSource)source NS_DESIGNATED_INITIALIZER;

- (nullable id)existingObjectForRepresentation:(id)representation mapping:(FEMMapping *)mapping;
- (nullable id)existingObjectForPrimaryKey:(id)primaryKey mapping:(FEMMapping *)mapping;

- (void)addExistingObject:(id)object mapping:(FEMMapping *)mapping;
- (NSDictionary *)existingObjectsForMapping:(FEMMapping *)mapping;
- (nullable id)objectForKey:(id)key mapping:(FEMMapping *)mapping;
- (void)setObject:(id)object forKey:(id)key mapping:(FEMMapping *)mapping;
- (NSDictionary *)objectsForMapping:(FEMMapping *)mapping;

@end

Expand Down
23 changes: 5 additions & 18 deletions FastEasyMapping/Source/Cache/FEMObjectCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,20 @@ - (NSMutableDictionary *)cachedObjectsForMapping:(FEMMapping *)mapping {
return entityObjectsMap;
}

- (id)existingObjectForRepresentation:(id)representation mapping:(FEMMapping *)mapping {
- (id)objectForKey:(id)key mapping:(FEMMapping *)mapping {
NSDictionary *entityObjectsMap = [self cachedObjectsForMapping:mapping];

id primaryKeyValue = FEMRepresentationValueForAttribute(representation, mapping.primaryKeyAttribute);
if (primaryKeyValue == nil || primaryKeyValue == NSNull.null) return nil;

return entityObjectsMap[primaryKeyValue];
}

- (id)existingObjectForPrimaryKey:(id)primaryKey mapping:(FEMMapping *)mapping {
NSDictionary *entityObjectsMap = [self cachedObjectsForMapping:mapping];

return entityObjectsMap[primaryKey];
return entityObjectsMap[key];
}

- (void)addExistingObject:(id)object mapping:(FEMMapping *)mapping {
- (void)setObject:(id)object forKey:(id)key mapping:(FEMMapping *)mapping {
NSParameterAssert(mapping.primaryKey);
NSParameterAssert(object);

id primaryKeyValue = [object valueForKey:mapping.primaryKey];
NSAssert(primaryKeyValue, @"No value for key (%@) on object (%@) found", mapping.primaryKey, object);

NSMutableDictionary *entityObjectsMap = [self cachedObjectsForMapping:mapping];
entityObjectsMap[primaryKeyValue] = object;
entityObjectsMap[key] = object;
}

- (NSDictionary *)existingObjectsForMapping:(FEMMapping *)mapping {
- (NSDictionary *)objectsForMapping:(FEMMapping *)mapping {
return [[self cachedObjectsForMapping:mapping] copy];
}

Expand Down
29 changes: 19 additions & 10 deletions FastEasyMapping/Source/Deserializer/FEMDeserializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,22 @@ - (void)applyRelationshipsToObject:(id)object representation:(NSDictionary *)rep
}
}

- (id)_objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocate {
id object = [self.store registeredObjectForRepresentation:representation mapping:mapping];
- (id)_objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocateIfNeeded {
id object = nil;
id primaryKey = nil;

FEMAttribute *primaryKeyAttribute = mapping.primaryKeyAttribute;
if (primaryKeyAttribute) {
primaryKey = FEMRepresentationValueForAttribute(representation, primaryKeyAttribute);
if (primaryKey != nil && primaryKey != [NSNull null]) {
object = [self.store objectForPrimaryKey:primaryKey mapping:mapping];
}
}

BOOL newObject = NO;
if (!object && allocate) {
BOOL allocated = NO;
if (!object && allocateIfNeeded) {
object = [self.store newObjectForMapping:mapping];
newObject = YES;
allocated = YES;
}

if (!object) {
Expand All @@ -127,10 +136,10 @@ - (id)_objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMappi
[self.delegate deserializer:self willMapObjectFromRepresentation:representation mapping:mapping];
}

[self applyAttributesToObject:object representation:representation mapping:mapping allocated:newObject];
[self applyAttributesToObject:object representation:representation mapping:mapping allocated:allocated];

if (newObject && [self.store canRegisterObject:object forMapping:mapping]) {
[self.store registerObject:object forMapping:mapping];
if (allocated) {
[self.store addObject:object forPrimaryKey:primaryKey mapping:mapping];
}

[self applyRelationshipsToObject:object representation:representation mapping:mapping];
Expand All @@ -142,15 +151,15 @@ - (id)_objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMappi
return object;
}

- (NSArray *)_collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocate {
- (NSArray *)_collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocateIfNeeded {
if (_delegateFlags.willMapCollection) {
[self.delegate deserializer:self willMapCollectionFromRepresentation:representation mapping:mapping];
}

NSMutableArray *output = [[NSMutableArray alloc] initWithCapacity:representation.count];
for (id objectRepresentation in representation) {
@autoreleasepool {
id object = [self _objectFromRepresentation:objectRepresentation mapping:mapping allocateIfNeeded:allocate];
id object = [self _objectFromRepresentation:objectRepresentation mapping:mapping allocateIfNeeded:allocateIfNeeded];
[output addObject:object];
}
}
Expand Down
16 changes: 9 additions & 7 deletions FastEasyMapping/Source/Store/FEMManagedObjectStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#import "FEMManagedObjectMapping.h"
#import "FEMObjectCache.h"
#import "FEMRepresentationUtility.h"

__attribute__((always_inline)) void validateMapping(FEMMapping *mapping) {
NSCAssert(mapping.entityName != nil, @"Entity name can't be nil. Please, use -[FEMMapping initWithEntityName:]");
Expand Down Expand Up @@ -55,22 +56,23 @@ - (id)newObjectForMapping:(FEMMapping *)mapping {
return [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.context];
}

- (id)registeredObjectForRepresentation:(id)representation mapping:(FEMMapping *)mapping {
- (id)objectForPrimaryKey:(id)primaryKey mapping:(FEMMapping *)mapping {
validateMapping(mapping);

return [_cache existingObjectForRepresentation:representation mapping:mapping];
return [_cache objectForKey:primaryKey mapping:mapping];
}

- (void)registerObject:(id)object forMapping:(FEMMapping *)mapping {
- (void)addObject:(id)object forPrimaryKey:(nullable id)primaryKey mapping:(FEMMapping *)mapping {
validateMapping(mapping);

[_cache addExistingObject:object mapping:mapping];
if (primaryKey != nil) {
[_cache setObject:object forKey:primaryKey mapping:mapping];
}
}

- (NSDictionary *)registeredObjectsForMapping:(FEMMapping *)mapping {
- (NSDictionary *)objectsForMapping:(FEMMapping *)mapping {
validateMapping(mapping);

return [_cache existingObjectsForMapping:mapping];
return [_cache objectsForMapping:mapping];
}

- (BOOL)canRegisterObject:(id)object forMapping:(FEMMapping *)mapping {
Expand Down
8 changes: 4 additions & 4 deletions FastEasyMapping/Source/Store/FEMObjectStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
@param object Fully deserialized the Object with fulfilled attributes and relationships.
@param mapping Mapping that is describing the `object`. You may want to ask for the `mapping.primaryKey` in order to get primary key value from `object`.
*/
- (void)registerObject:(id)object forMapping:(FEMMapping *)mapping;
- (void)addObject:(id)object forPrimaryKey:(nullable id)primaryKey mapping:(FEMMapping *)mapping;

/**
@brief Evaluates whether object can be registered in the internal cache or not.
Expand All @@ -100,7 +100,7 @@ NS_ASSUME_NONNULL_BEGIN
@return Dictionary where key is a Primary Key and value is Object.
*/
- (NSDictionary *)registeredObjectsForMapping:(FEMMapping *)mapping;
- (NSDictionary *)objectsForMapping:(FEMMapping *)mapping;

/**
@brief Returns regitered Object for the given JSON representation of the Object.
Expand All @@ -109,12 +109,12 @@ NS_ASSUME_NONNULL_BEGIN
for the given JSON. FEMObjectStore may want to perform a lookup in the internal cache for existing object by extracting
primary key from the JSON.
@param representation JSON representing the Object
@param primaryKey JSON representing the Object
@param mapping Mapping for which registered object requested.
@return Registered Object or nil.
*/
- (nullable id)registeredObjectForRepresentation:(id)representation mapping:(FEMMapping *)mapping;
- (nullable id)objectForPrimaryKey:(id)primaryKey mapping:(FEMMapping *)mapping;

@end

Expand Down
6 changes: 3 additions & 3 deletions FastEasyMapping/Source/Store/FEMObjectStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ - (FEMRelationshipAssignmentContext *)newAssignmentContext {
return context;
}

- (void)registerObject:(id)object forMapping:(FEMMapping *)mapping {
- (void)addObject:(id)object forPrimaryKey:(nullable id)primaryKey mapping:(FEMMapping *)mapping {
// no-op
}

- (BOOL)canRegisterObject:(id)object forMapping:(FEMMapping *)mapping {
return mapping.primaryKeyAttribute != nil;
}

- (NSDictionary *)registeredObjectsForMapping:(FEMMapping *)mapping {
- (NSDictionary *)objectsForMapping:(FEMMapping *)mapping {
return @{};
}

- (id)registeredObjectForRepresentation:(id)representation mapping:(FEMMapping *)mapping {
- (id)objectForPrimaryKey:(id)primaryKey mapping:(FEMMapping *)mapping {
return nil;
}

Expand Down
27 changes: 10 additions & 17 deletions FastEasyMappingTests/Specs/FEMCacheSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
});

describe(@"object retrieval", ^{
__block id primaryKey = @1;
__block NSDictionary *representation = nil;
__block FEMMapping *mapping = nil;
__block FEMObjectCache *cache = nil;
Expand All @@ -55,25 +56,17 @@

it(@"should return nil for missing object", ^{
[[@([Car MR_countOfEntitiesWithContext:context]) should] beZero];
[[[cache existingObjectForRepresentation:representation mapping:mapping] should] beNil];

id missingRepresentation = @{
@"id": @1,
@"model": @"i30",
@"year": @"2013"
};

[[[cache existingObjectForRepresentation:missingRepresentation mapping:mapping] should] beNil];
[[[cache objectForKey:primaryKey mapping:mapping] should] beNil];
});

it(@"should add objects", ^{
[[@([Car MR_countOfEntitiesWithContext:context]) should] beZero];
[[[cache existingObjectForRepresentation:representation mapping:mapping] should] beNil];
[[[cache objectForKey:primaryKey mapping:mapping] should] beNil];

Car *car = [FEMDeserializer objectFromRepresentation:representation mapping:mapping context:context];

[cache addExistingObject:car mapping:mapping];
[[[cache existingObjectForRepresentation:representation mapping:mapping] should] equal:car];
[cache setObject:car forKey:primaryKey mapping:mapping];
[[[cache objectForKey:primaryKey mapping:mapping] should] equal:car];
});

it(@"should return registered object", ^{
Expand All @@ -84,7 +77,7 @@
[[@(car.objectID.isTemporaryID) should] beTrue];
[[[context objectRegisteredForID:car.objectID] should] equal:car];

[[[cache existingObjectForRepresentation:representation mapping:mapping] should] equal:car];
[[[cache objectForKey:primaryKey mapping:mapping] should] equal:car];
});

it(@"should return saved object", ^{
Expand All @@ -101,7 +94,7 @@
[[[context objectRegisteredForID:car.objectID] should] beNil];

car = [Car MR_findFirstInContext:context];
[[[cache existingObjectForRepresentation:representation mapping:mapping] should] equal:car];
[[[cache objectForKey:primaryKey mapping:mapping] should] equal:car];
});
});

Expand Down Expand Up @@ -129,14 +122,14 @@

it(@"should return nil for missing nested object", ^{
[FEMDeserializer objectFromRepresentation:representation mapping:mapping context:context];
id missingObjectRepresentation = @{@"id": @2};
id missingKey = @2;

[[[cache existingObjectForRepresentation:missingObjectRepresentation mapping:carMapping] should] beNil];
[[[cache objectForKey:missingKey mapping:carMapping] should] beNil];
});

it(@"should return existing nested object", ^{
Person *person = [FEMDeserializer objectFromRepresentation:representation mapping:mapping context:context];
[[[cache existingObjectForRepresentation:representation[@"car"] mapping:carMapping] should] equal:person.car];
[[[cache objectForKey:[person.car valueForKey:carMapping.primaryKey] mapping:carMapping] should] equal:person.car];
});
});

Expand Down

0 comments on commit 3ebddb9

Please sign in to comment.