From cd6e6daf3153d788162f6ebf09f95bb7136354ec Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sun, 14 Oct 2018 18:10:07 -0700 Subject: [PATCH] Continue work on Feedbin sync data types. --- .../Account/Account.xcodeproj/project.pbxproj | 32 ++++---- Frameworks/Account/Feedbin/Feedbin.swift | 46 ------------ .../Feedbin/FeedbinAccountDelegate.swift | 43 ----------- .../Account/Feedbin/FeedbinArticle.swift | 22 +++--- .../Feedbin/FeedbinArticleIDArray.swift | 22 ++++++ ...inSubscription.swift => FeedbinFeed.swift} | 28 +++---- .../FeedbinGetSubscriptionsDelegate.swift | 42 ----------- .../Account/Feedbin/FeedbinSavedSearch.swift | 57 ++++++++++++++ .../Account/Feedbin/FeedbinTagging.swift | 75 +++++++++++++++++++ 9 files changed, 197 insertions(+), 170 deletions(-) delete mode 100644 Frameworks/Account/Feedbin/Feedbin.swift delete mode 100644 Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift create mode 100644 Frameworks/Account/Feedbin/FeedbinArticleIDArray.swift rename Frameworks/Account/Feedbin/{FeedbinSubscription.swift => FeedbinFeed.swift} (80%) delete mode 100644 Frameworks/Account/Feedbin/FeedbinGetSubscriptionsDelegate.swift create mode 100644 Frameworks/Account/Feedbin/FeedbinSavedSearch.swift create mode 100644 Frameworks/Account/Feedbin/FeedbinTagging.swift diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index 148193ee3..3d8c4e600 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -13,10 +13,7 @@ 841974251F6DDCE4006346C4 /* AccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974241F6DDCE4006346C4 /* AccountDelegate.swift */; }; 841D4D702106B40400DD04E6 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D6F2106B40400DD04E6 /* ArticlesDatabase.framework */; }; 841D4D722106B40A00DD04E6 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D712106B40A00DD04E6 /* Articles.framework */; }; - 84245C7F1FDDD2580074AFBB /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C7E1FDDD2580074AFBB /* FeedbinAccountDelegate.swift */; }; - 84245C811FDDD42A0074AFBB /* Feedbin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C801FDDD42A0074AFBB /* Feedbin.swift */; }; - 84245C831FDDD8160074AFBB /* FeedbinGetSubscriptionsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C821FDDD8160074AFBB /* FeedbinGetSubscriptionsDelegate.swift */; }; - 84245C851FDDD8CB0074AFBB /* FeedbinSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */; }; + 84245C851FDDD8CB0074AFBB /* FeedbinFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */; }; 844B297D2106C7EC004020B3 /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B297C2106C7EC004020B3 /* Feed.swift */; }; 844B297F210CE37E004020B3 /* UnreadCountProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B297E210CE37E004020B3 /* UnreadCountProvider.swift */; }; 844B2981210CE3BF004020B3 /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844B2980210CE3BF004020B3 /* RSWeb.framework */; }; @@ -31,6 +28,9 @@ 84C3654A1F899F3B001EC85C /* CombinedRefreshProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C365491F899F3B001EC85C /* CombinedRefreshProgress.swift */; }; 84C8B3F41F89DE430053CCA6 /* DataExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C8B3F31F89DE430053CCA6 /* DataExtensions.swift */; }; 84CAD7161FDF2E22000F0755 /* FeedbinArticle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CAD7151FDF2E22000F0755 /* FeedbinArticle.swift */; }; + 84D096212174169100D77525 /* FeedbinArticleIDArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D096202174169100D77525 /* FeedbinArticleIDArray.swift */; }; + 84D09623217418DC00D77525 /* FeedbinTagging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D09622217418DC00D77525 /* FeedbinTagging.swift */; }; + 84D0962521741B8500D77525 /* FeedbinSavedSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D0962421741B8500D77525 /* FeedbinSavedSearch.swift */; }; 84EAC4822148CC6300F154AB /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAC4812148CC6300F154AB /* RSDatabase.framework */; }; 84F73CF1202788D90000BCEF /* ArticleFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F73CF0202788D80000BCEF /* ArticleFetcher.swift */; }; /* End PBXBuildFile section */ @@ -90,10 +90,7 @@ 8419742D1F6DDE96006346C4 /* LocalAccountRefresher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAccountRefresher.swift; sourceTree = ""; }; 841D4D6F2106B40400DD04E6 /* ArticlesDatabase.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ArticlesDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 841D4D712106B40A00DD04E6 /* Articles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Articles.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 84245C7E1FDDD2580074AFBB /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = ""; }; - 84245C801FDDD42A0074AFBB /* Feedbin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feedbin.swift; sourceTree = ""; }; - 84245C821FDDD8160074AFBB /* FeedbinGetSubscriptionsDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinGetSubscriptionsDelegate.swift; sourceTree = ""; }; - 84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinSubscription.swift; sourceTree = ""; }; + 84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinFeed.swift; sourceTree = ""; }; 844B297C2106C7EC004020B3 /* Feed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = ""; }; 844B297E210CE37E004020B3 /* UnreadCountProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnreadCountProvider.swift; sourceTree = ""; }; 844B2980210CE3BF004020B3 /* RSWeb.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSWeb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -108,6 +105,9 @@ 84C365491F899F3B001EC85C /* CombinedRefreshProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombinedRefreshProgress.swift; sourceTree = ""; }; 84C8B3F31F89DE430053CCA6 /* DataExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtensions.swift; sourceTree = ""; }; 84CAD7151FDF2E22000F0755 /* FeedbinArticle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinArticle.swift; sourceTree = ""; }; + 84D096202174169100D77525 /* FeedbinArticleIDArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinArticleIDArray.swift; sourceTree = ""; }; + 84D09622217418DC00D77525 /* FeedbinTagging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinTagging.swift; sourceTree = ""; }; + 84D0962421741B8500D77525 /* FeedbinSavedSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinSavedSearch.swift; sourceTree = ""; }; 84EAC4812148CC6300F154AB /* RSDatabase.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84F73CF0202788D80000BCEF /* ArticleFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleFetcher.swift; sourceTree = ""; }; D511EEB5202422BB00712EC3 /* Account_project_debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Account_project_debug.xcconfig; sourceTree = ""; }; @@ -173,11 +173,11 @@ 84245C7D1FDDD2580074AFBB /* Feedbin */ = { isa = PBXGroup; children = ( - 84245C7E1FDDD2580074AFBB /* FeedbinAccountDelegate.swift */, - 84245C801FDDD42A0074AFBB /* Feedbin.swift */, - 84245C821FDDD8160074AFBB /* FeedbinGetSubscriptionsDelegate.swift */, - 84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */, + 84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */, 84CAD7151FDF2E22000F0755 /* FeedbinArticle.swift */, + 84D096202174169100D77525 /* FeedbinArticleIDArray.swift */, + 84D09622217418DC00D77525 /* FeedbinTagging.swift */, + 84D0962421741B8500D77525 /* FeedbinSavedSearch.swift */, ); path = Feedbin; sourceTree = ""; @@ -411,21 +411,21 @@ 84C8B3F41F89DE430053CCA6 /* DataExtensions.swift in Sources */, 84C3654A1F899F3B001EC85C /* CombinedRefreshProgress.swift in Sources */, 8469F81C1F6DD15E0084783E /* Account.swift in Sources */, + 84D096212174169100D77525 /* FeedbinArticleIDArray.swift in Sources */, 846E77451F6EF9B900A165E2 /* Container.swift in Sources */, 84F73CF1202788D90000BCEF /* ArticleFetcher.swift in Sources */, - 84245C7F1FDDD2580074AFBB /* FeedbinAccountDelegate.swift in Sources */, 841974251F6DDCE4006346C4 /* AccountDelegate.swift in Sources */, 846E77541F6F00E300A165E2 /* AccountManager.swift in Sources */, 844B297D2106C7EC004020B3 /* Feed.swift in Sources */, 84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */, 846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */, - 84245C811FDDD42A0074AFBB /* Feedbin.swift in Sources */, + 84D09623217418DC00D77525 /* FeedbinTagging.swift in Sources */, 84CAD7161FDF2E22000F0755 /* FeedbinArticle.swift in Sources */, + 84D0962521741B8500D77525 /* FeedbinSavedSearch.swift in Sources */, 841974011F6DD1EC006346C4 /* Folder.swift in Sources */, 846E774F1F6EF9C000A165E2 /* LocalAccountDelegate.swift in Sources */, 844B297F210CE37E004020B3 /* UnreadCountProvider.swift in Sources */, - 84245C851FDDD8CB0074AFBB /* FeedbinSubscription.swift in Sources */, - 84245C831FDDD8160074AFBB /* FeedbinGetSubscriptionsDelegate.swift in Sources */, + 84245C851FDDD8CB0074AFBB /* FeedbinFeed.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Frameworks/Account/Feedbin/Feedbin.swift b/Frameworks/Account/Feedbin/Feedbin.swift deleted file mode 100644 index ebdca306f..000000000 --- a/Frameworks/Account/Feedbin/Feedbin.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// Feedbin.swift -// Account -// -// Created by Brent Simmons on 12/10/17. -// Copyright © 2017 Ranchero Software, LLC. All rights reserved. -// - -import Foundation -import RSWeb - -final class Feedbin: WebServiceProvider { - - let account: Account - - struct MethodName { - static let getSubscriptions = "getSubscriptions" - } - - init(account: Account) { - - self.account = account - } - - // MARK: - Feedbin API - - func getSubscriptions() { - - let delegate = FeedbinGetSubscriptionsDelegate(provider: self) - callAPI(MethodName.getSubscriptions, delegate) - } -} - -private extension Feedbin { - - func callAPI(_ methodName: String, _ delegate: APICallDelegate) { - - let call = APICall(provider: self, methodName: methodName, delegate: delegate) - run(call) - } - - func run(_ apiCall: APICall) { - - // TODO: add to url session - } -} diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift deleted file mode 100644 index 1fea57d98..000000000 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// FeedbinAccountDelegate.swift -// Account -// -// Created by Brent Simmons on 12/10/17. -// Copyright © 2017 Ranchero Software, LLC. All rights reserved. -// - -import Foundation -import RSWeb - -final class FeedbinAccountDelegate: AccountDelegate { - - let supportsSubFolders = false - - var refreshProgress: DownloadProgress { - return DownloadProgress(numberOfTasks: 0) // TODO - } - - func refreshAll(for: Account) { - - // TODO - } - - // MARK: Disk - - func accountDidInitialize(_ account: Account) { - - // TODO: add username to account name - account.nameForDisplay = NSLocalizedString("Feedbin", comment: "Feedbin Account Name") - } - - func update(account: Account, withUserInfo: NSDictionary?) { - - } - - func userInfo(for: Account) -> NSDictionary? { - - // TODO: save username - return nil - } -} - diff --git a/Frameworks/Account/Feedbin/FeedbinArticle.swift b/Frameworks/Account/Feedbin/FeedbinArticle.swift index 0305b59f1..0a997fc65 100644 --- a/Frameworks/Account/Feedbin/FeedbinArticle.swift +++ b/Frameworks/Account/Feedbin/FeedbinArticle.swift @@ -12,6 +12,8 @@ import RSCore struct FeedbinArticle { + // https://github.com/feedbin/feedbin-api/blob/master/content/entries.md + // // "id": 2077, // "feed_id": 135, // "title": "Objective-C Runtime Releases", @@ -22,6 +24,16 @@ struct FeedbinArticle { // "published": "2013-02-03T01:00:19.000000Z", // "created_at": "2013-02-04T01:00:19.127893Z" + let syncID: String + let feedID: String + let title: String? + let url: String? + let authorName: String? + let contentHTML: String? + let summary: String? + let datePublished: Date? + let dateArrived: Date? + struct Key { static let syncID = "id" static let feedID = "feed_id" @@ -34,16 +46,6 @@ struct FeedbinArticle { static let dateArrived = "created_at" } - let syncID: String - let feedID: String - let title: String? - let url: String? - let authorName: String? - let contentHTML: String? - let summary: String? - let datePublished: Date? - let dateArrived: Date? - init?(jsonDictionary: JSONDictionary) { guard let syncIDInt = jsonDictionary[Key.syncID] as? Int else { diff --git a/Frameworks/Account/Feedbin/FeedbinArticleIDArray.swift b/Frameworks/Account/Feedbin/FeedbinArticleIDArray.swift new file mode 100644 index 000000000..91627a881 --- /dev/null +++ b/Frameworks/Account/Feedbin/FeedbinArticleIDArray.swift @@ -0,0 +1,22 @@ +// +// FeedbinArticleIDArray.swift +// Account +// +// Created by Brent Simmons on 10/14/18. +// Copyright © 2018 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +struct FeedbinArticleIDArray { + + // https://github.com/feedbin/feedbin-api/blob/master/content/unread-entries.md + // + // [4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097] + + let articleIDs: [Int] + + init(jsonArray: [Any]) { + self.articleIDs = jsonArray.compactMap { $0 as? Int } + } +} diff --git a/Frameworks/Account/Feedbin/FeedbinSubscription.swift b/Frameworks/Account/Feedbin/FeedbinFeed.swift similarity index 80% rename from Frameworks/Account/Feedbin/FeedbinSubscription.swift rename to Frameworks/Account/Feedbin/FeedbinFeed.swift index 0c76374b0..56ca33b54 100644 --- a/Frameworks/Account/Feedbin/FeedbinSubscription.swift +++ b/Frameworks/Account/Feedbin/FeedbinFeed.swift @@ -1,5 +1,5 @@ // -// FeedbinSubscription.swift +// FeedbinFeed.swift // Account // // Created by Brent Simmons on 12/10/17. @@ -10,7 +10,16 @@ import Foundation import RSCore import RSParser -struct FeedbinSubscription { +struct FeedbinFeed { + + // https://github.com/feedbin/feedbin-api/blob/master/content/feeds.md + // + // "id": 525, + // "created_at": "2013-03-12T11:30:25.209432Z", + // "feed_id": 47, + // "title": "Daring Fireball", + // "feed_url": "http://daringfireball.net/index.xml", + // "site_url": "http://daringfireball.net/" let subscriptionID: String let feedID: String @@ -19,13 +28,6 @@ struct FeedbinSubscription { let url: String let homePageURL: String? - // "id": 525, - // "created_at": "2013-03-12T11:30:25.209432Z", - // "feed_id": 47, - // "title": "Daring Fireball", - // "feed_url": "http://daringfireball.net/index.xml", - // "site_url": "http://daringfireball.net/" - struct Key { static let subscriptionID = "id" static let feedID = "feed_id" @@ -47,8 +49,8 @@ struct FeedbinSubscription { return nil } - self.subscriptionID = "\(subscriptionIDInt)" - self.feedID = "\(feedIDInt)" + self.subscriptionID = String(subscriptionIDInt) + self.feedID = String(feedIDInt) self.url = url if let creationDateString = dictionary[Key.creationDate] as? String { @@ -62,9 +64,9 @@ struct FeedbinSubscription { self.homePageURL = dictionary[Key.homePageURL] as? String } - static func subscriptions(with array: JSONArray) -> [FeedbinSubscription]? { + static func feeds(with array: JSONArray) -> [FeedbinFeed]? { - let subs = array.compactMap { FeedbinSubscription(dictionary: $0) } + let subs = array.compactMap { FeedbinFeed(dictionary: $0) } return subs.isEmpty ? nil : subs } } diff --git a/Frameworks/Account/Feedbin/FeedbinGetSubscriptionsDelegate.swift b/Frameworks/Account/Feedbin/FeedbinGetSubscriptionsDelegate.swift deleted file mode 100644 index 7acb7ee00..000000000 --- a/Frameworks/Account/Feedbin/FeedbinGetSubscriptionsDelegate.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// FeedbinGetSubscriptionsDelegate.swift -// Account -// -// Created by Brent Simmons on 12/10/17. -// Copyright © 2017 Ranchero Software, LLC. All rights reserved. -// - -import Foundation -import RSWeb -import RSParser - -struct FeedbinGetSubscriptionsDelegate: APICallDelegate { - - let provider: Feedbin - - func apiCallURLRequest(_ call: APICall) -> URLRequest? { - - return nil // TODO - } - - func apiCall(_ call: APICall, parseReturnedObjectWith result: HTTPResult) -> Any? { - - guard let data = result.data, let jsonArray = JSONUtilities.array(with: data) else { - return nil - } - - return FeedbinSubscription.subscriptions(with: jsonArray) - } - - func apiCall(_ call: APICall, handleErrorWith: HTTPResult, returnedObject: Any?) { - - // TODO - } - - func apiCall(_ call: APICall, performActionWith: HTTPResult, returnedObject: Any?) { - - // TODO - } - - -} diff --git a/Frameworks/Account/Feedbin/FeedbinSavedSearch.swift b/Frameworks/Account/Feedbin/FeedbinSavedSearch.swift new file mode 100644 index 000000000..460c6703c --- /dev/null +++ b/Frameworks/Account/Feedbin/FeedbinSavedSearch.swift @@ -0,0 +1,57 @@ +// +// FeedbinSavedSearch.swift +// Account +// +// Created by Brent Simmons on 10/14/18. +// Copyright © 2018 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +struct FeedbinSavedSearch: Hashable { + + // https://github.com/feedbin/feedbin-api/blob/master/content/saved-searches.md + // + // [ + // { + // "id": 1, + // "name": "JavaScript", + // "query": "javascript is:unread" + // } + // ] + + let uniqueID: Int + let name: String + let query: String + + private struct Key { + static let uniqueID = "id" + static let name = "name" + static let query = "query" + } + + init?(jsonDictionary: [String: Any]) { + guard let uniqueID = jsonDictionary[Key.uniqueID] as? Int else { + return nil + } + guard let name = jsonDictionary[Key.name] as? String else { + return nil + } + guard let query = jsonDictionary[Key.query] as? String else { + return nil + } + self.uniqueID = uniqueID + self.name = name + self.query = query + } + + static func savedSearches(with jsonArray: [Any]) -> Set { + let searches = jsonArray.compactMap { (oneSearch) -> FeedbinSavedSearch? in + if let oneSearch = oneSearch as? [String: Any] { + return FeedbinSavedSearch(jsonDictionary: oneSearch) + } + return nil + } + return Set(searches) + } +} diff --git a/Frameworks/Account/Feedbin/FeedbinTagging.swift b/Frameworks/Account/Feedbin/FeedbinTagging.swift new file mode 100644 index 000000000..3de1d0dc7 --- /dev/null +++ b/Frameworks/Account/Feedbin/FeedbinTagging.swift @@ -0,0 +1,75 @@ +// +// FeedbinTagging.swift +// Account +// +// Created by Brent Simmons on 10/14/18. +// Copyright © 2018 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +struct FeedbinTagging: Hashable { + + // https://github.com/feedbin/feedbin-api/blob/master/content/taggings.md + // + // [ + // { + // "id": 4, + // "feed_id": 1, + // "name": "Tech" + // }, + // { + // "id": 5, + // "feed_id": 2, + // "name": "News" + // } + // ] + + let taggingID: Int + let feedID: Int + let name: String + + private struct Key { + static let taggingID = "id" + static let feedID = "feed_id" + static let name = "name" + } + + init?(jsonDictionary: [String: Any]) { + guard let taggingID = jsonDictionary[Key.taggingID] as? Int else { + return nil + } + guard let feedID = jsonDictionary[Key.feedID] as? Int else { + return nil + } + guard let name = jsonDictionary[Key.name] as? String else { + return nil + } + self.taggingID = taggingID + self.feedID = feedID + self.name = name + } + + // MARK: - Hashable + + public func hash(into hasher: inout Hasher) { + hasher.combine(taggingID) + } + + // MARK: - Equatable + + public static func ==(lhs: FeedbinTagging, rhs: FeedbinTagging) -> Bool { + return lhs.taggingID == rhs.taggingID && lhs.feedID == rhs.feedID && lhs.name == rhs.name + } + + static func taggings(with jsonArray: [Any]) -> Set { + + let taggingsArray = jsonArray.compactMap { (item) -> FeedbinTagging? in + if let oneDictionary = item as? [String: Any] { + return FeedbinTagging(jsonDictionary: oneDictionary) + } + return nil + } + return Set(taggingsArray) + } +}