Skip to content

Resource collections #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Classes/JSONAPIResourceCollection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// JSONAPIResourceCollection.h
// JSONAPI
//
// Created by Julian Krumow on 13.01.16.
// Copyright © 2016 Josh Holtz. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface JSONAPIResourceCollection : NSObject

@property (nonatomic) NSMutableArray *resources;
@property (nonatomic) NSString *selfLink;
@property (nonatomic) NSString *relatedLink;

- (instancetype)initWithArray:(NSArray *)array;

- (id)firstObject;
- (id)lastObject;

- (NSUInteger)count;
- (void)addObject:(id)object;

- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id __unsafe_unretained [])stackbuf
count:(NSUInteger)len;
@end
84 changes: 84 additions & 0 deletions Classes/JSONAPIResourceCollection.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// JSONAPIResourceCollection.m
// JSONAPI
//
// Created by Julian Krumow on 13.01.16.
// Copyright © 2016 Josh Holtz. All rights reserved.
//

#import "JSONAPIResourceCollection.h"

@interface JSONAPIResourceCollection ()

@end

@implementation JSONAPIResourceCollection

- (instancetype)initWithArray:(NSArray *)array
{
self = [super init];
if (self) {
_resources = [[NSMutableArray alloc] initWithArray:array];
}
return self;
}

- (instancetype)init
{
self = [super init];
if (self) {
_resources = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
JSONAPIResourceCollection *copy = [JSONAPIResourceCollection new];
copy.selfLink = self.selfLink.copy;
copy.relatedLink = self.relatedLink.copy;
copy.resources = self.resources.mutableCopy;
return copy;
}

- (id)firstObject
{
return self.resources.firstObject;
}
- (id)lastObject
{
return self.resources.lastObject;
}

- (NSUInteger)count
{
return self.resources.count;
}

- (void)addObject:(id)object
{
[self.resources addObject:object];
}

- (id)objectAtIndexedSubscript:(NSUInteger)idx
{
return self.resources[idx];
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
{
self.resources[idx] = obj;
}

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
[self.resources enumerateObjectsUsingBlock:block];
}

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id __unsafe_unretained [])stackbuf
count:(NSUInteger)len
{
return [self.resources countByEnumeratingWithState:state objects:stackbuf count:len];
}

@end
1 change: 0 additions & 1 deletion Classes/JSONAPIResourceDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
* This is required for any model resource.
*/
@property (strong) NSString *idProperty;

@property (strong) NSString *selfLinkProperty;

/**
Expand Down
1 change: 1 addition & 0 deletions Classes/JSONAPIResourceParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#import <Foundation/Foundation.h>

#import "JSONAPIResource.h"
#import "JSONAPIResourceCollection.h"

@class JSONAPI;

Expand Down
103 changes: 63 additions & 40 deletions Classes/JSONAPIResourceParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -97,44 +97,59 @@ + (NSDictionary*)dictionaryFor:(NSObject <JSONAPIResource>*)resource {
[dictionary setValue:ID forKey:@"id"];
}
}

NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];

// Loops through all keys to map to properties
NSDictionary *properties = [descriptor properties];
for (NSString *key in properties) {
JSONAPIPropertyDescriptor *property = [properties objectForKey:key];
id value = [resource valueForKey:key];
if (value) {
if ([value isKindOfClass:[NSArray class]]) {
NSArray *valueArray = value;
if (valueArray.count > 0) {
NSMutableArray *dictionaryArray = [[NSMutableArray alloc] initWithCapacity:valueArray.count];
if ([value isKindOfClass:[JSONAPIResourceCollection class]]) {
JSONAPIResourceCollection *collection = (JSONAPIResourceCollection *)value;

if (linkage == nil) {
linkage = [[NSMutableDictionary alloc] init];
}
NSMutableDictionary *collectionDictionary = [[NSMutableDictionary alloc] init];

if (collection.selfLink || collection.relatedLink) {
NSMutableDictionary *links = [[NSMutableDictionary alloc] init];
if (collection.selfLink) {
links[@"self"] = collection.selfLink.mutableCopy;
}
if (collection.relatedLink) {
links[@"related"] = collection.relatedLink.mutableCopy;
}
collectionDictionary[@"links"] = links;
}

[linkage setValue:collectionDictionary forKey:[property jsonName]];

if (collection.count > 0) {
NSMutableArray *dataArray = [[NSMutableArray alloc] initWithCapacity:collection.count];

if ([property resourceType] || [((NSArray *)value).firstObject conformsToProtocol:@protocol(JSONAPIResource)]) {
if (linkage == nil) {
linkage = [[NSMutableDictionary alloc] init];
}

for (id valueElement in valueArray) {
[dictionaryArray addObject:[self link:valueElement from:resource withKey:[property jsonName]]];
if ([property resourceType] || [collection.firstObject conformsToProtocol:@protocol(JSONAPIResource)]) {

for (id element in collection) {
[dataArray addObject:[self link:element from:resource withKey:[property jsonName]]];
}
collectionDictionary[@"data"] = dataArray;

NSDictionary *dataDictionary = @{@"data" : dictionaryArray};
[linkage setValue:dataDictionary forKey:[property jsonName]];
} else {
NSFormatter *format = [property formatter];

for (id valueElement in valueArray) {
for (id element in collection) {
if (format) {
[dictionaryArray addObject:[format stringForObjectValue:valueElement]];
[dataArray addObject:[format stringForObjectValue:element]];
} else {
[dictionaryArray addObject:valueElement];
[dataArray addObject:element];
}
}

[attributes setValue:dictionaryArray forKey:[property jsonName]];
[attributes setValue:dataArray forKey:[property jsonName]];
}
}
} else {
Expand Down Expand Up @@ -164,24 +179,24 @@ + (NSDictionary*)dictionaryFor:(NSObject <JSONAPIResource>*)resource {
if (linkage) {
[dictionary setValue:linkage forKey:@"relationships"];
}
// TODO: Need to also add in all other links
if (resource.selfLink) {
dictionary[@"links"] = @{ @"self": resource.selfLink };
}
// TODO: Need to also add in all other links
if (resource.selfLink) {
dictionary[@"links"] = @{ @"self": resource.selfLink };
}
return dictionary;
}

+ (void)set:(NSObject <JSONAPIResource> *)resource withDictionary:dictionary {
NSString *error;

JSONAPIResourceDescriptor *descriptor = [[resource class] descriptor];

NSDictionary *relationships = [dictionary objectForKey:@"relationships"];
NSDictionary *attributes = [dictionary objectForKey:@"attributes"];
NSDictionary *links = [dictionary objectForKey:@"links"];
id ID = [dictionary objectForKey:@"id"];
NSFormatter *format = [descriptor idFormatter];
if (format) {
Expand All @@ -197,7 +212,7 @@ + (void)set:(NSObject <JSONAPIResource> *)resource withDictionary:dictionary {
NSString *selfLink = links[@"self"];
[resource setValue:selfLink forKey:descriptor.selfLinkProperty];
}

// Loops through all keys to map to properties
NSDictionary *properties = [descriptor properties];
for (NSString *key in properties) {
Expand Down Expand Up @@ -260,12 +275,19 @@ + (void)set:(NSObject <JSONAPIResource> *)resource withDictionary:dictionary {
+ (id)jsonAPILink:(NSDictionary*)dictionary {
id linkage = dictionary[@"data"];
if ([linkage isKindOfClass:[NSArray class]]) {
NSMutableArray *linkArray = [[NSMutableArray alloc] initWithCapacity:[linkage count]];

JSONAPIResourceCollection *collection = [JSONAPIResourceCollection new];

if (dictionary[@"links"]) {
collection.selfLink = dictionary[@"links"][@"self"];
collection.relatedLink = dictionary[@"links"][@"related"];
}

for (NSDictionary *linkElement in linkage) {
[linkArray addObject:[JSONAPIResourceParser parseResource:linkElement]];
[collection addObject:[JSONAPIResourceParser parseResource:linkElement]];
}

return linkArray;
return collection;

} else {
return [JSONAPIResourceParser parseResource:linkage];
Expand All @@ -289,17 +311,18 @@ + (void)link:(NSObject <JSONAPIResource>*)resource withIncluded:(JSONAPI*)jsonAP
Class valueClass = nil;
if (propertyDescriptor.resourceType) {
valueClass = propertyDescriptor.resourceType;
} else if ([value conformsToProtocol:@protocol(JSONAPIResource)] || [value isKindOfClass:[NSArray class]]) {
} else if ([value conformsToProtocol:@protocol(JSONAPIResource)] || [value isKindOfClass:[JSONAPIResourceCollection class]]) {
valueClass = [value class];
}

// ordinary attribute
if (valueClass == nil) {
continue;
// has many
} else if ([value isKindOfClass:[NSArray class]]) {
NSMutableArray *matched = [value mutableCopy];
[value enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// has many
} else if ([value isKindOfClass:[JSONAPIResourceCollection class]]) {
JSONAPIResourceCollection *collection = (JSONAPIResourceCollection *)value;
JSONAPIResourceCollection *matched = [value mutableCopy];
[collection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj conformsToProtocol:@protocol(JSONAPIResource)]) {
NSObject <JSONAPIResource> *res = obj;
id includedValue = included[[[res.class descriptor] type]];
Expand All @@ -311,9 +334,9 @@ + (void)link:(NSObject <JSONAPIResource>*)resource withIncluded:(JSONAPI*)jsonAP
}
}
}];

[resource setValue:matched forKey:key];
// has one
// has one
} else if (value != nil) {
if ([value conformsToProtocol:@protocol(JSONAPIResource)]) {
id <JSONAPIResource> res = value;
Expand All @@ -340,7 +363,7 @@ + (NSArray*)relatedResourcesFor:(NSObject <JSONAPIResource>*)resource {
JSONAPIPropertyDescriptor *property = [properties objectForKey:key];
if (property.resourceType) {
id value = [resource valueForKey:key];
if ([value isKindOfClass:[NSArray class]]) {
if ([value isKindOfClass:[JSONAPIResourceCollection class]]) {
[related addObjectsFromArray:value];
} else {
[related addObject:value];
Expand Down Expand Up @@ -371,7 +394,7 @@ + (NSDictionary*)link:(NSObject <JSONAPIResource>*)resource from:(NSObject <JSON
@"type" : descriptor.type,
@"id" : resource.ID
};
if ([[owner valueForKey:key] isKindOfClass:[NSArray class]]) {
if ([[owner valueForKey:key] isKindOfClass:[JSONAPIResourceCollection class]]) {
reference = referenceObject.mutableCopy;
} else {
[reference setValue:referenceObject forKey:@"data"];
Expand Down
6 changes: 6 additions & 0 deletions Project/JSONAPI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
03FBD8DF1AB8DF8E00789DF3 /* JSONAPIErrorResource.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FBD8DE1AB8DF8E00789DF3 /* JSONAPIErrorResource.m */; };
03FBD8E21AB8E46E00789DF3 /* error_example.json in Resources */ = {isa = PBXBuildFile; fileRef = 03FBD8E11AB8E46E00789DF3 /* error_example.json */; };
03FBD8E31AB8E46E00789DF3 /* error_example.json in Resources */ = {isa = PBXBuildFile; fileRef = 03FBD8E11AB8E46E00789DF3 /* error_example.json */; };
3BFB45201C467967008F71D3 /* JSONAPIResourceCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFB451F1C467967008F71D3 /* JSONAPIResourceCollection.m */; };
680E14F51B08146E004FF8CD /* JSONAPIResourceParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 680E14F41B08146E004FF8CD /* JSONAPIResourceParser.m */; };
681B47761B08EA9800A99D76 /* JSONAPIResourceBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 681B47751B08EA9800A99D76 /* JSONAPIResourceBase.m */; };
685481EB1AE4161900D3A633 /* JSONAPIPropertyDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 685481EA1AE4161900D3A633 /* JSONAPIPropertyDescriptor.m */; };
Expand Down Expand Up @@ -107,6 +108,8 @@
03FBD8DD1AB8DF8E00789DF3 /* JSONAPIErrorResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAPIErrorResource.h; sourceTree = "<group>"; };
03FBD8DE1AB8DF8E00789DF3 /* JSONAPIErrorResource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONAPIErrorResource.m; sourceTree = "<group>"; };
03FBD8E11AB8E46E00789DF3 /* error_example.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = error_example.json; sourceTree = "<group>"; };
3BFB451E1C467967008F71D3 /* JSONAPIResourceCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAPIResourceCollection.h; sourceTree = "<group>"; };
3BFB451F1C467967008F71D3 /* JSONAPIResourceCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONAPIResourceCollection.m; sourceTree = "<group>"; };
680E14F31B08146E004FF8CD /* JSONAPIResourceParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAPIResourceParser.h; sourceTree = "<group>"; };
680E14F41B08146E004FF8CD /* JSONAPIResourceParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONAPIResourceParser.m; sourceTree = "<group>"; };
681B47741B08EA9800A99D76 /* JSONAPIResourceBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAPIResourceBase.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -276,6 +279,8 @@
680E14F41B08146E004FF8CD /* JSONAPIResourceParser.m */,
681B47741B08EA9800A99D76 /* JSONAPIResourceBase.h */,
681B47751B08EA9800A99D76 /* JSONAPIResourceBase.m */,
3BFB451E1C467967008F71D3 /* JSONAPIResourceCollection.h */,
3BFB451F1C467967008F71D3 /* JSONAPIResourceCollection.m */,
);
name = Classes;
path = ../Classes;
Expand Down Expand Up @@ -428,6 +433,7 @@
03866457186A94C200985CEC /* ArticleResource.m in Sources */,
03A055D11868E038004807F0 /* ViewController.m in Sources */,
03A055F71868E08A004807F0 /* JSONAPI.m in Sources */,
3BFB45201C467967008F71D3 /* JSONAPIResourceCollection.m in Sources */,
78A5C1D31C1E14D6008C8632 /* MediaResource.m in Sources */,
68A469941AE47E0000E7BBC8 /* NSDateFormatter+JSONAPIDateFormatter.m in Sources */,
685481EB1AE4161900D3A633 /* JSONAPIPropertyDescriptor.m in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion Project/JSONAPI/ArticleResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "JSONAPIResourceBase.h"
#import "JSONAPIResourceCollection.h"

@class PeopleResource;

Expand All @@ -15,7 +16,7 @@
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) PeopleResource *author;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSArray *comments;
@property (nonatomic, strong) JSONAPIResourceCollection *comments;

@property (nonatomic, strong) NSArray *versions;

Expand Down
3 changes: 2 additions & 1 deletion Project/JSONAPI/NewsFeedPostResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "JSONAPIResourceBase.h"
#import "JSONAPIResourceCollection.h"
#import "UserResource.h"
#import "SocialCommunityResource.h"
#import "MediaResource.h"
Expand All @@ -19,6 +20,6 @@
@property (nonatomic, strong) NSString *text;

@property (nonatomic, strong) id<JSONAPIResource> publisher;
@property (nonatomic, strong) NSArray *attachments;
@property (nonatomic, strong) JSONAPIResourceCollection *attachments;

@end
Loading