Skip to content

Commit

Permalink
Merge pull request #388 from SyncDB/improve/rename-hyper-remotekey
Browse files Browse the repository at this point in the history
Rename hyper.remoteKey to sync.remoteKey
  • Loading branch information
3lvis authored Mar 21, 2017
2 parents 2dd3370 + 0fdfd20 commit 3155a98
Show file tree
Hide file tree
Showing 40 changed files with 295 additions and 63 deletions.
62 changes: 62 additions & 0 deletions Demo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ If you add the flag `hyper.isPrimaryKey` to the attribute `contractID` then:
- Local primary key will be: `contractID`
- Remote primary key will be: `contract_id`

If you want to use `id` for the remote primary key you also have to add the flag `hyper.remoteKey` and write `id` as the value.
If you want to use `id` for the remote primary key you also have to add the flag `sync.remoteKey` and write `id` as the value.

- Local primary key will be: `articleBody`
- Remote primary key will be: `id`
Expand All @@ -205,7 +205,7 @@ There are some exception to this rule:
* Reserved attributes should be prefixed with the `entityName` (`type` becomes `userType`, `description` becomes `userDescription` and so on). In the JSON they don't need to change, you can keep `type` and `description` for example. A full list of reserved attributes can be found [here](https://github.com/SyncDB/SyncPropertyMapper/blob/master/Sources/NSManagedObject-SyncPropertyMapper/NSManagedObject%2BSyncPropertyMapperHelpers.m#L282-L284)
* Attributes with acronyms will be normalized (`id`, `pdf`, `url`, `png`, `jpg`, `uri`, `json`, `xml`). For example `user_id` will be mapped to `userID` and so on. You can find the entire list of supported acronyms [here](https://github.com/SyncDB/SyncPropertyMapper/blob/master/Sources/NSString-SyncInflections/NSString%2BSyncInflections.m#L204-L206).

If you want to map your Core Data attribute with a JSON attribute that has different naming, you can do by adding `hyper.remoteKey` in the user info box with the value you want to map.
If you want to map your Core Data attribute with a JSON attribute that has different naming, you can do by adding `sync.remoteKey` in the user info box with the value you want to map.

![Custom remote key](https://raw.githubusercontent.com/SyncDB/Sync/master/Images/custom-remote-key-v2.png)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ static NSString * const SyncCustomLocalPrimaryKey = @"hyper.isPrimaryKey";
static NSString * const SyncCustomLocalPrimaryKeyValue = @"YES";
static NSString * const SyncCustomLocalPrimaryKeyAlternativeValue = @"true";

static NSString * const SyncCustomRemoteKey = @"hyper.remoteKey";
static NSString * const SyncCustomRemoteKey = @"sync.remoteKey";
static NSString * const SyncCompatibilityCustomRemoteKey = @"hyper.remoteKey";

@interface NSEntityDescription (SyncPrimaryKey)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "NSEntityDescription+SyncPrimaryKey.h"

#import "NSString+SyncInflections.h"
#import "NSPropertyDescription+Sync.h"

@implementation NSEntityDescription (SyncPrimaryKey)

Expand Down Expand Up @@ -35,7 +36,7 @@ - (nonnull NSString *)sync_localPrimaryKey {

- (nonnull NSString *)sync_remotePrimaryKey {
NSAttributeDescription *primaryKeyAttribute = [self sync_primaryKeyAttribute];
NSString *remoteKey = primaryKeyAttribute.userInfo[SyncCustomRemoteKey];
NSString *remoteKey = primaryKeyAttribute.customKey;

if (!remoteKey) {
if ([primaryKeyAttribute.name isEqualToString:SyncDefaultLocalPrimaryKey] || [primaryKeyAttribute.name isEqualToString:SyncDefaultLocalCompatiblePrimaryKey]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

static NSString * const SyncPropertyMapperDestroyKey = @"destroy";
static NSString * const SyncPropertyMapperCustomValueTransformerKey = @"hyper.valueTransformer";
static NSString * const SyncPropertyMapperCustomRemoteKey = @"hyper.remoteKey";
static NSString * const SyncPropertyMapperNonExportableKey = @"hyper.nonExportable";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import "NSString+SyncInflections.h"
#import "NSEntityDescription+SyncPrimaryKey.h"
#import "NSDate+SyncPropertyMapper.h"
#import "NSPropertyDescription+Sync.h"

@implementation NSManagedObject (SyncPropertyMapperHelpers)

Expand Down Expand Up @@ -43,8 +44,8 @@ - (NSAttributeDescription *)attributeDescriptionForRemoteKey:(NSString *)remoteK
if ([propertyDescription isKindOfClass:[NSAttributeDescription class]]) {
NSAttributeDescription *attributeDescription = (NSAttributeDescription *)propertyDescription;

NSDictionary *userInfo = [self.entity.propertiesByName[attributeDescription.name] userInfo];
NSString *customRemoteKey = userInfo[SyncPropertyMapperCustomRemoteKey];
NSString *customRemoteKey = [self.entity.propertiesByName[attributeDescription.name] customKey];

BOOL currentAttributeHasTheSameRemoteKey = (customRemoteKey.length > 0 && [customRemoteKey isEqualToString:remoteKey]);
if (currentAttributeHasTheSameRemoteKey) {
foundAttributeDescription = attributeDescription;
Expand Down Expand Up @@ -104,8 +105,7 @@ - (NSArray *)attributeDescriptionsForRemoteKeyPath:(NSString *)remoteKey {
if ([propertyDescription isKindOfClass:[NSAttributeDescription class]]) {
NSAttributeDescription *attributeDescription = (NSAttributeDescription *)propertyDescription;

NSDictionary *userInfo = [self.entity.propertiesByName[attributeDescription.name] userInfo];
NSString *customRemoteKeyPath = userInfo[SyncPropertyMapperCustomRemoteKey];
NSString *customRemoteKeyPath = self.entity.propertiesByName[attributeDescription.name].customKey;
NSString *customRootRemoteKey = [[customRemoteKeyPath componentsSeparatedByString:@"."] firstObject];
NSString *rootRemoteKey = [[remoteKey componentsSeparatedByString:@"."] firstObject];
BOOL currentAttributeHasTheSameRootRemoteKey = (customRootRemoteKey.length > 0 && [customRootRemoteKey isEqualToString:rootRemoteKey]);
Expand Down Expand Up @@ -135,11 +135,10 @@ - (NSString *)remoteKeyForAttributeDescription:(NSAttributeDescription *)attribu
- (NSString *)remoteKeyForAttributeDescription:(NSAttributeDescription *)attributeDescription
usingRelationshipType:(SyncPropertyMapperRelationshipType)relationshipType
inflectionType:(SyncPropertyMapperInflectionType)inflectionType {
NSDictionary *userInfo = attributeDescription.userInfo;
NSString *localKey = attributeDescription.name;
NSString *remoteKey;

NSString *customRemoteKey = userInfo[SyncPropertyMapperCustomRemoteKey];
NSString *customRemoteKey = attributeDescription.customKey;
if (customRemoteKey) {
remoteKey = customRemoteKey;
} else if ([localKey isEqualToString:SyncDefaultLocalPrimaryKey] || [localKey isEqualToString:SyncDefaultLocalCompatiblePrimaryKey]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import CoreData;

@interface NSPropertyDescription (Sync)

@property (nonatomic, nullable, readonly) NSString *customKey;

@end
16 changes: 16 additions & 0 deletions Source/NSPropertyDescription-Sync/NSPropertyDescription+Sync.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#import "NSPropertyDescription+Sync.h"

#import "NSEntityDescription+SyncPrimaryKey.h"

@implementation NSPropertyDescription (Sync)

- (NSString *)customKey {
NSString *keyName = self.userInfo[SyncCustomRemoteKey];
if (keyName == nil) {
keyName = self.userInfo[SyncCompatibilityCustomRemoteKey];
}

return keyName;
}

@end
1 change: 1 addition & 0 deletions Source/Sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ FOUNDATION_EXPORT const unsigned char SyncVersionString[];
#import "SyncPropertyMapper.h"
#import "NSEntityDescription+SyncPrimaryKey.h"
#import "NSManagedObject+SyncPropertyMapperHelpers.h"
#import "NSPropertyDescription+Sync.h"
14 changes: 14 additions & 0 deletions Source/Sync/NSEntityDescription+Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ extension NSEntityDescription {
return relationships
}

/// Finds the attributes for the current entity.
///
/// - Returns: An array of attributes for the current entity.
func sync_attributes() -> [NSAttributeDescription] {
var attributes = [NSAttributeDescription]()
for propertyDescription in properties {
if let attributeDescription = propertyDescription as? NSAttributeDescription {
attributes.append(attributeDescription)
}
}

return attributes
}

/**
Finds the parent for the current entity, if there are many parents nil will be returned.
- returns The parent relationship for the current entity
Expand Down
8 changes: 4 additions & 4 deletions Source/Sync/NSManagedObject+Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extension NSManagedObject {
for relationship in entity.sync_relationships() {
let suffix = relationship.isToMany ? "_ids" : "_id"
let constructedKeyName = relationship.name.hyp_snakeCase() + suffix
let keyName = relationship.userInfo?[SyncCustomRemoteKey] as? String ?? constructedKeyName
let keyName = relationship.customKey ?? constructedKeyName

if relationship.isToMany {
if let localPrimaryKey = dictionary[keyName], localPrimaryKey is Array < String> || localPrimaryKey is Array < Int> || localPrimaryKey is NSNull {
Expand Down Expand Up @@ -169,15 +169,15 @@ extension NSManagedObject {
*/
func sync_toManyRelationship(_ relationship: NSRelationshipDescription, dictionary: [String: Any], parent: NSManagedObject?, parentRelationship: NSRelationshipDescription?, context: NSManagedObjectContext, operations: Sync.OperationOptions, shouldContinueBlock: (() -> Bool)?, objectJSONBlock: ((_ objectJSON: [String: Any]) -> [String: Any])?) throws {
var children: [[String: Any]]?
let childrenIsNull = relationship.userInfo?[SyncCustomRemoteKey] is NSNull || dictionary[relationship.name.hyp_snakeCase()] is NSNull || dictionary[relationship.name] is NSNull
let childrenIsNull = (relationship.customKey as Any?) is NSNull || dictionary[relationship.name.hyp_snakeCase()] is NSNull || dictionary[relationship.name] is NSNull
if childrenIsNull {
children = [[String: Any]]()

if value(forKey: relationship.name) != nil {
setValue(nil, forKey: relationship.name)
}
} else {
if let customRelationshipName = relationship.userInfo?[SyncCustomRemoteKey] as? String {
if let customRelationshipName = relationship.customKey {
if customRelationshipName.contains(".") {
if let deepMapingRootKey = customRelationshipName.components(separatedBy: ".").first {
if let rootObject = dictionary[deepMapingRootKey] as? [String: Any] {
Expand Down Expand Up @@ -352,7 +352,7 @@ extension NSManagedObject {
func sync_toOneRelationship(_ relationship: NSRelationshipDescription, dictionary: [String: Any], context: NSManagedObjectContext, operations: Sync.OperationOptions, shouldContinueBlock: (() -> Bool)?, objectJSONBlock: ((_ objectJSON: [String: Any]) -> [String: Any])?) {
var filteredObjectDictionary: [String: Any]?

if let customRelationshipName = relationship.userInfo?[SyncCustomRemoteKey] as? String {
if let customRelationshipName = relationship.customKey {
filteredObjectDictionary = dictionary[customRelationshipName] as? [String: Any]
} else if let result = dictionary[relationship.name.hyp_snakeCase()] as? [String: Any] {
filteredObjectDictionary = result
Expand Down
2 changes: 1 addition & 1 deletion Source/Sync/Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public protocol SyncDelegate: class {
}

if remotePrimaryKey.isEmpty {
fatalError("Remote primary key not found for entity: \(entityName), we were looking for id, if your remote ID has a different name consider using hyper.remoteKey to map to the right value")
fatalError("Remote primary key not found for entity: \(entityName), we were looking for id, if your remote ID has a different name consider using sync.remoteKey to map to the right value")
}

let dataFilterOperations = DataFilter.Operation(rawValue: operations.rawValue)
Expand Down
10 changes: 8 additions & 2 deletions Tests/NSEntityDescription-SyncPrimaryKey/PrimaryKeyTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ - (void)testPrimaryKeyAttribute {
XCTAssertEqualObjects(attribute.name, @"alternativeID");
}

- (void)testLocalKey {
- (void)testLocalPrimaryKey {
NSEntityDescription *entity = [self entityForName:@"User"];
XCTAssertEqualObjects([entity sync_localPrimaryKey], @"remoteID");

Expand All @@ -74,9 +74,12 @@ - (void)testLocalKey {

entity = [self entityForName:@"AlternativeID"];
XCTAssertEqualObjects([entity sync_localPrimaryKey], @"alternativeID");

entity = [self entityForName:@"Compatibility"];
XCTAssertEqualObjects([entity sync_localPrimaryKey], @"id");
}

- (void)testRemoteKey {
- (void)testRemotePrimaryKey {
NSEntityDescription *entity = [self entityForName:@"User"];
XCTAssertEqualObjects([entity sync_remotePrimaryKey], @"id");

Expand All @@ -94,6 +97,9 @@ - (void)testRemoteKey {

entity = [self entityForName:@"AlternativeID"];
XCTAssertEqualObjects([entity sync_remotePrimaryKey], @"alternative_id");

entity = [self entityForName:@"Compatibility"];
XCTAssertEqualObjects([entity sync_remotePrimaryKey], @"greeting");
}

@end
18 changes: 13 additions & 5 deletions ...escription-SyncPrimaryKey/SyncPrimaryKey.xcdatamodeld/SyncPrimaryKey.xcdatamodel/contents
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10174" systemVersion="15E65" minimumToolsVersion="Automatic">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11759" systemVersion="16D32" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="AlternativeID" syncable="YES">
<attribute name="alternativeID" optional="YES" attributeType="String" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="true"/>
</userInfo>
</attribute>
</entity>
<entity name="Compatibility" syncable="YES">
<attribute name="id" optional="YES" attributeType="String" syncable="YES">
<userInfo>
<entry key="hyper.remoteKey" value="greeting"/>
</userInfo>
</attribute>
</entity>
<entity name="NoID" syncable="YES">
<attribute name="attribute" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<entity name="Note" syncable="YES">
<attribute name="attribute" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="uniqueID" optional="YES" attributeType="Integer 16" defaultValueString="0" syncable="YES">
<attribute name="uniqueID" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
</userInfo>
Expand All @@ -27,20 +34,21 @@
<attribute name="randomId" optional="YES" attributeType="String" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
</entity>
<entity name="User" representedClassName="" syncable="YES">
<attribute name="attribute" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="remoteID" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="remoteID" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="AlternativeID" positionX="-27" positionY="18" width="128" height="60"/>
<element name="NoID" positionX="-27" positionY="18" width="128" height="60"/>
<element name="Note" positionX="-20" positionY="18" width="128" height="75"/>
<element name="SimpleID" positionX="-27" positionY="18" width="128" height="75"/>
<element name="Tag" positionX="160" positionY="0" width="128" height="75"/>
<element name="User" positionX="-207" positionY="-15" width="128" height="73"/>
<element name="AlternativeID" positionX="-27" positionY="18" width="128" height="60"/>
<element name="Compatibility" positionX="-27" positionY="18" width="128" height="60"/>
</elements>
</model>
14 changes: 14 additions & 0 deletions Tests/Sync/JSONs/388.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"id": 0,
"name": "Note 0"
},
{
"id": 1,
"name": "Note 1"
},
{
"id": 2,
"name": "Note 2"
}
]
7 changes: 7 additions & 0 deletions Tests/Sync/JSONs/hyper_remote_key.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"id": 1,
"custom_old": "old",
"custom_current": "current"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<relationship name="awesomeComments" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="AwesomeComment" inverseName="awesomeStory" inverseEntity="AwesomeComment" syncable="YES"/>
<relationship name="awesomeSummarize" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AwesomeSummarize" inverseName="awesomeStory" inverseEntity="AwesomeSummarize" syncable="YES">
<userInfo>
<entry key="hyper.remoteKey" value="summarize_text"/>
<entry key="sync.remoteKey" value="summarize_text"/>
</userInfo>
</relationship>
</entity>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<attribute name="noteID" attributeType="Integer 32" defaultValueString="0" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="true"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<relationship name="tags" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Tag" inverseName="notes" inverseEntity="Tag" syncable="YES"/>
Expand All @@ -15,7 +15,7 @@
<attribute name="tagID" optional="YES" attributeType="String" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="true"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<relationship name="notes" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Note" inverseName="tags" inverseEntity="Note" syncable="YES"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<attribute name="noteID" attributeType="Integer 32" defaultValueString="0" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="User" inverseName="notes" inverseEntity="User" syncable="YES"/>
Expand All @@ -15,7 +15,7 @@
<attribute name="userID" attributeType="Integer 32" defaultValueString="0" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<relationship name="notes" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Note" inverseName="user" inverseEntity="Note" syncable="YES"/>
Expand Down
4 changes: 2 additions & 2 deletions Tests/Sync/Models/157.xcdatamodeld/157.xcdatamodel/contents
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<attribute name="cityID" attributeType="Integer 16" defaultValueString="0" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
Expand All @@ -14,7 +14,7 @@
<attribute name="locationID" attributeType="Integer 16" defaultValueString="0" syncable="YES">
<userInfo>
<entry key="hyper.isPrimaryKey" value="YES"/>
<entry key="hyper.remoteKey" value="id"/>
<entry key="sync.remoteKey" value="id"/>
</userInfo>
</attribute>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
Expand Down
Loading

0 comments on commit 3155a98

Please sign in to comment.