Convert API objects to CoreData models and save them
This commit is contained in:
parent
7deb4fc5b4
commit
102fe6ed91
|
@ -12,29 +12,29 @@ import CoreData
|
|||
import Pachyderm
|
||||
|
||||
@objc(AccountMO)
|
||||
public class AccountMO: NSManagedObject {
|
||||
public final class AccountMO: NSManagedObject {
|
||||
|
||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<AccountMO> {
|
||||
return NSFetchRequest<AccountMO>(entityName: "Account")
|
||||
}
|
||||
|
||||
@NSManaged public var acct: String?
|
||||
@NSManaged public var avatar: URL?
|
||||
@NSManaged public var acct: String
|
||||
@NSManaged public var avatar: URL
|
||||
@NSManaged public var bot: Bool
|
||||
@NSManaged public var createdAt: Date?
|
||||
@NSManaged public var displayName: String?
|
||||
@NSManaged public var emojisData: Data?
|
||||
@NSManaged public var fieldsData: Data?
|
||||
@NSManaged public var followersCount: Int64
|
||||
@NSManaged public var followingCount: Int64
|
||||
@NSManaged public var header: URL?
|
||||
@NSManaged public var id: String?
|
||||
@NSManaged public var createdAt: Date
|
||||
@NSManaged public var displayName: String
|
||||
@NSManaged private var emojisData: Data?
|
||||
@NSManaged private var fieldsData: Data?
|
||||
@NSManaged public var followersCount: Int
|
||||
@NSManaged public var followingCount: Int
|
||||
@NSManaged public var header: URL
|
||||
@NSManaged public var id: String
|
||||
@NSManaged public var locked: Bool
|
||||
@NSManaged public var moved: Bool
|
||||
@NSManaged public var note: String?
|
||||
@NSManaged public var statusesCount: Int64
|
||||
@NSManaged public var url: URL?
|
||||
@NSManaged public var username: String?
|
||||
@NSManaged public var note: String
|
||||
@NSManaged public var statusesCount: Int
|
||||
@NSManaged public var url: URL
|
||||
@NSManaged public var username: String
|
||||
@NSManaged public var movedTo: AccountMO?
|
||||
|
||||
@LazilyDecoding(arrayFrom: \AccountMO.emojisData)
|
||||
|
@ -44,3 +44,40 @@ public class AccountMO: NSManagedObject {
|
|||
var fields: [Account.Field]
|
||||
|
||||
}
|
||||
|
||||
extension AccountMO {
|
||||
convenience init(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore, context: NSManagedObjectContext) {
|
||||
self.init(context: context)
|
||||
self.updateFrom(apiAccount: account, container: container)
|
||||
}
|
||||
|
||||
func updateFrom(apiAccount account: Pachyderm.Account, container: MastodonCachePersistentStore) {
|
||||
guard let context = managedObjectContext else {
|
||||
// we've been deleted, don't bother updating
|
||||
return
|
||||
}
|
||||
|
||||
self.acct = account.acct
|
||||
self.avatar = account.avatar
|
||||
self.bot = account.bot ?? false
|
||||
self.createdAt = account.createdAt
|
||||
self.displayName = account.displayName
|
||||
self.emojis = account.emojis
|
||||
self.fields = account.fields ?? []
|
||||
self.followersCount = account.followersCount
|
||||
self.followingCount = account.followingCount
|
||||
self.header = account.header
|
||||
self.id = account.id
|
||||
self.locked = account.locked
|
||||
self.moved = account.moved ?? false
|
||||
self.note = account.note
|
||||
self.statusesCount = account.statusesCount
|
||||
self.url = account.url
|
||||
self.username = account.username
|
||||
if let movedTo = account.movedTo {
|
||||
self.movedTo = container.account(for: movedTo.id, in: context) ?? AccountMO(apiAccount: movedTo, container: container, context: context)
|
||||
} else {
|
||||
self.movedTo = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import Pachyderm
|
||||
|
||||
class MastodonCachePersistentStore: NSPersistentContainer {
|
||||
|
||||
private(set) lazy var backgroundContext = newBackgroundContext()
|
||||
|
||||
init(for controller: MastodonController) {
|
||||
let url = Bundle.main.url(forResource: "Tusker", withExtension: "momd")!
|
||||
let model = NSManagedObjectModel(contentsOf: url)!
|
||||
|
@ -22,26 +25,54 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
}
|
||||
}
|
||||
|
||||
func status(for id: String) -> StatusMO? {
|
||||
func status(for id: String, in context: NSManagedObjectContext? = nil) -> StatusMO? {
|
||||
let context = context ?? viewContext
|
||||
let request: NSFetchRequest<StatusMO> = StatusMO.fetchRequest()
|
||||
request.predicate = NSPredicate(format: "id = %@", id)
|
||||
request.fetchLimit = 1
|
||||
if let result = try? viewContext.fetch(request), let status = result.first {
|
||||
if let result = try? context.fetch(request), let status = result.first {
|
||||
return status
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func account(for id: String) -> AccountMO? {
|
||||
func addOrUpdate(status: Status, save: Bool = true) {
|
||||
backgroundContext.perform {
|
||||
if let statusMO = self.status(for: status.id, in: self.backgroundContext) {
|
||||
statusMO.updateFrom(apiStatus: status, container: self)
|
||||
} else {
|
||||
_ = StatusMO(apiStatus: status, container: self, context: self.backgroundContext)
|
||||
}
|
||||
if save, self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func account(for id: String, in context: NSManagedObjectContext? = nil) -> AccountMO? {
|
||||
let context = context ?? viewContext
|
||||
let request: NSFetchRequest<AccountMO> = AccountMO.fetchRequest()
|
||||
request.predicate = NSPredicate(format: "id = %@", id)
|
||||
request.fetchLimit = 1
|
||||
if let result = try? viewContext.fetch(request), let account = result.first {
|
||||
if let result = try? context.fetch(request), let account = result.first {
|
||||
return account
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func addOrUpdate(account: Account, save: Bool = true) {
|
||||
backgroundContext.perform {
|
||||
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
||||
accountMO.updateFrom(apiAccount: account, container: self)
|
||||
} else {
|
||||
_ = AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
||||
}
|
||||
if save, self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public final class StatusMO: NSManagedObject {
|
|||
}
|
||||
|
||||
@NSManaged public var application: String?
|
||||
@NSManaged public var attachmentsData: Data?
|
||||
@NSManaged private var attachmentsData: Data?
|
||||
@NSManaged public var bookmarked: Bool
|
||||
@NSManaged public var content: String
|
||||
@NSManaged public var createdAt: Date
|
||||
|
@ -28,25 +28,25 @@ public final class StatusMO: NSManagedObject {
|
|||
@NSManaged public var favouritesCount: Int
|
||||
@NSManaged public var hashtagsData: Data?
|
||||
@NSManaged public var id: String
|
||||
@NSManaged public var mentionsData: Data?
|
||||
@NSManaged public var inReplyToAccountID: String?
|
||||
@NSManaged public var inReplyToID: String?
|
||||
@NSManaged private var mentionsData: Data?
|
||||
@NSManaged public var muted: Bool
|
||||
@NSManaged public var pinned: Bool
|
||||
@NSManaged public var reblogged: Bool
|
||||
@NSManaged public var reblogsCount: Int
|
||||
@NSManaged public var sensitive: Bool
|
||||
@NSManaged public var uri: String
|
||||
@NSManaged public var uri: String // todo: are both uri and url necessary?
|
||||
@NSManaged public var url: URL?
|
||||
@NSManaged public var visibility: String?
|
||||
@NSManaged private var visibilityString: String
|
||||
@NSManaged public var account: AccountMO
|
||||
@NSManaged public var inReplyTo: StatusMO?
|
||||
@NSManaged public var inReplyToAccount: AccountMO?
|
||||
@NSManaged public var reblog: StatusMO?
|
||||
|
||||
@LazilyDecoding(arrayFrom: \StatusMO.attachmentsData)
|
||||
var attachments: [Attachment]
|
||||
|
||||
@LazilyDecoding(arrayFrom: \StatusMO.emojisData)
|
||||
var emoji: [Emoji]
|
||||
var emojis: [Emoji]
|
||||
|
||||
@LazilyDecoding(arrayFrom: \StatusMO.hashtagsData)
|
||||
var hashtags: [Hashtag]
|
||||
|
@ -54,4 +54,54 @@ public final class StatusMO: NSManagedObject {
|
|||
@LazilyDecoding(arrayFrom: \StatusMO.mentionsData)
|
||||
var mentions: [Mention]
|
||||
|
||||
var visibility: Status.Visibility {
|
||||
get {
|
||||
Pachyderm.Status.Visibility(rawValue: visibilityString) ?? .public
|
||||
}
|
||||
set {
|
||||
visibilityString = newValue.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension StatusMO {
|
||||
convenience init(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore, context: NSManagedObjectContext) {
|
||||
self.init(context: context)
|
||||
self.updateFrom(apiStatus: status, container: container)
|
||||
}
|
||||
|
||||
func updateFrom(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore) {
|
||||
guard let context = managedObjectContext else {
|
||||
// we have been deleted, don't bother updating
|
||||
return
|
||||
}
|
||||
|
||||
self.application = status.application?.name
|
||||
self.attachments = status.attachments
|
||||
self.bookmarked = status.bookmarked ?? false
|
||||
self.content = status.content
|
||||
self.createdAt = status.createdAt
|
||||
self.emojis = status.emojis
|
||||
self.favourited = status.favourited ?? false
|
||||
self.favouritesCount = status.favouritesCount
|
||||
self.hashtags = status.hashtags
|
||||
self.inReplyToAccountID = status.inReplyToAccountID
|
||||
self.inReplyToID = status.inReplyToID
|
||||
self.id = status.id
|
||||
self.mentions = status.mentions
|
||||
self.muted = status.muted ?? false
|
||||
self.pinned = status.pinned ?? false
|
||||
self.reblogged = status.reblogged ?? false
|
||||
self.reblogsCount = status.reblogsCount
|
||||
self.sensitive = status.sensitive
|
||||
self.uri = status.uri
|
||||
self.visibility = status.visibility
|
||||
self.account = container.account(for: status.account.id, in: context) ?? AccountMO(apiAccount: status.account, container: container, context: context)
|
||||
if let reblog = status.reblog {
|
||||
self.reblog = container.status(for: reblog.id, in: context) ?? StatusMO(apiStatus: reblog, container: container, context: context)
|
||||
} else {
|
||||
self.reblog = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
<attribute name="favouritesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="hashtagsData" attributeType="Binary"/>
|
||||
<attribute name="id" attributeType="String"/>
|
||||
<attribute name="inReplyToAccountID" optional="YES" attributeType="String"/>
|
||||
<attribute name="inReplyToID" optional="YES" attributeType="String"/>
|
||||
<attribute name="mentionsData" attributeType="Binary"/>
|
||||
<attribute name="muted" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="pinned" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
|
@ -44,10 +46,8 @@
|
|||
<attribute name="sensitive" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="uri" attributeType="String"/>
|
||||
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||
<attribute name="visibility" attributeType="String"/>
|
||||
<attribute name="visibilityString" attributeType="String"/>
|
||||
<relationship name="account" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
||||
<relationship name="inReplyTo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status"/>
|
||||
<relationship name="inReplyToAccount" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
||||
<relationship name="reblog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
|
|
|
@ -59,10 +59,17 @@ class MastodonCache {
|
|||
|
||||
func add(status: Status) {
|
||||
set(status: status, for: status.id)
|
||||
mastodonController?.persistentContainer.addOrUpdate(status: status)
|
||||
}
|
||||
|
||||
func addAll(statuses: [Status]) {
|
||||
statuses.forEach(add)
|
||||
if let container = mastodonController?.persistentContainer {
|
||||
statuses.forEach { container.addOrUpdate(status: $0, save: false) }
|
||||
container.backgroundContext.perform {
|
||||
try! container.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accounts
|
||||
|
@ -92,10 +99,17 @@ class MastodonCache {
|
|||
|
||||
func add(account: Account) {
|
||||
set(account: account, for: account.id)
|
||||
mastodonController?.persistentContainer.addOrUpdate(account: account)
|
||||
}
|
||||
|
||||
func addAll(accounts: [Account]) {
|
||||
accounts.forEach(add)
|
||||
if let container = mastodonController?.persistentContainer {
|
||||
accounts.forEach { container.addOrUpdate(account: $0, save: false) }
|
||||
container.backgroundContext.perform {
|
||||
try! container.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Relationships
|
||||
|
|
Loading…
Reference in New Issue