forked from zelo72/mastodon-ios
200 lines
5.9 KiB
Swift
200 lines
5.9 KiB
Swift
|
//
|
||
|
// Persistence+Notification.swift
|
||
|
// Mastodon
|
||
|
//
|
||
|
// Created by MainasuK on 2022-1-21.
|
||
|
//
|
||
|
|
||
|
import CoreData
|
||
|
import CoreDataStack
|
||
|
import Foundation
|
||
|
import MastodonSDK
|
||
|
import os.log
|
||
|
import class CoreDataStack.Notification
|
||
|
|
||
|
extension Persistence.Notification {
|
||
|
|
||
|
public struct PersistContext {
|
||
|
public let domain: String
|
||
|
public let entity: Mastodon.Entity.Notification
|
||
|
public let me: MastodonUser
|
||
|
public let networkDate: Date
|
||
|
public let log = OSLog.api
|
||
|
|
||
|
public init(
|
||
|
domain: String,
|
||
|
entity: Mastodon.Entity.Notification,
|
||
|
me: MastodonUser,
|
||
|
networkDate: Date
|
||
|
) {
|
||
|
self.domain = domain
|
||
|
self.entity = entity
|
||
|
self.me = me
|
||
|
self.networkDate = networkDate
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public struct PersistResult {
|
||
|
public let notification: Notification
|
||
|
public let isNewInsertion: Bool
|
||
|
|
||
|
public init(
|
||
|
notification: Notification,
|
||
|
isNewInsertion: Bool
|
||
|
) {
|
||
|
self.notification = notification
|
||
|
self.isNewInsertion = isNewInsertion
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static func createOrMerge(
|
||
|
in managedObjectContext: NSManagedObjectContext,
|
||
|
context: PersistContext
|
||
|
) -> PersistResult {
|
||
|
|
||
|
if let old = fetch(in: managedObjectContext, context: context) {
|
||
|
merge(object: old, context: context)
|
||
|
return PersistResult(
|
||
|
notification: old,
|
||
|
isNewInsertion: false
|
||
|
)
|
||
|
} else {
|
||
|
let accountResult = Persistence.MastodonUser.createOrMerge(
|
||
|
in: managedObjectContext,
|
||
|
context: Persistence.MastodonUser.PersistContext(
|
||
|
domain: context.domain,
|
||
|
entity: context.entity.account,
|
||
|
cache: nil,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
)
|
||
|
let account = accountResult.user
|
||
|
|
||
|
let status: Status? = {
|
||
|
guard let entity = context.entity.status else { return nil }
|
||
|
let result = Persistence.Status.createOrMerge(
|
||
|
in: managedObjectContext,
|
||
|
context: Persistence.Status.PersistContext(
|
||
|
domain: context.domain,
|
||
|
entity: entity,
|
||
|
me: context.me,
|
||
|
statusCache: nil,
|
||
|
userCache: nil,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
)
|
||
|
return result.status
|
||
|
}()
|
||
|
|
||
|
let relationship = Notification.Relationship(
|
||
|
account: account,
|
||
|
status: status
|
||
|
)
|
||
|
|
||
|
let object = create(
|
||
|
in: managedObjectContext,
|
||
|
context: context,
|
||
|
relationship: relationship
|
||
|
)
|
||
|
|
||
|
return PersistResult(
|
||
|
notification: object,
|
||
|
isNewInsertion: true
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
extension Persistence.Notification {
|
||
|
|
||
|
public static func fetch(
|
||
|
in managedObjectContext: NSManagedObjectContext,
|
||
|
context: PersistContext
|
||
|
) -> Notification? {
|
||
|
let request = Notification.sortedFetchRequest
|
||
|
request.predicate = Notification.predicate(
|
||
|
domain: context.me.domain,
|
||
|
userID: context.me.id,
|
||
|
id: context.entity.id
|
||
|
)
|
||
|
request.fetchLimit = 1
|
||
|
do {
|
||
|
return try managedObjectContext.fetch(request).first
|
||
|
} catch {
|
||
|
assertionFailure(error.localizedDescription)
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@discardableResult
|
||
|
public static func create(
|
||
|
in managedObjectContext: NSManagedObjectContext,
|
||
|
context: PersistContext,
|
||
|
relationship: Notification.Relationship
|
||
|
) -> Notification {
|
||
|
let property = Notification.Property(
|
||
|
entity: context.entity,
|
||
|
domain: context.me.domain,
|
||
|
userID: context.me.id,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
let object = Notification.insert(
|
||
|
into: managedObjectContext,
|
||
|
property: property,
|
||
|
relationship: relationship
|
||
|
)
|
||
|
update(object: object, context: context)
|
||
|
return object
|
||
|
}
|
||
|
|
||
|
public static func merge(
|
||
|
object: Notification,
|
||
|
context: PersistContext
|
||
|
) {
|
||
|
guard context.networkDate > object.updatedAt else { return }
|
||
|
let property = Notification.Property(
|
||
|
entity: context.entity,
|
||
|
domain: context.me.domain,
|
||
|
userID: context.me.id,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
object.update(property: property)
|
||
|
|
||
|
if let status = object.status, let entity = context.entity.status {
|
||
|
let property = Status.Property(
|
||
|
entity: entity,
|
||
|
domain: context.domain,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
status.update(property: property)
|
||
|
}
|
||
|
|
||
|
let accountProperty = MastodonUser.Property(
|
||
|
entity: context.entity.account,
|
||
|
domain: context.domain,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
object.account.update(property: accountProperty)
|
||
|
|
||
|
if let author = object.status, let entity = context.entity.status {
|
||
|
let property = Status.Property(
|
||
|
entity: entity,
|
||
|
domain: context.domain,
|
||
|
networkDate: context.networkDate
|
||
|
)
|
||
|
author.update(property: property)
|
||
|
}
|
||
|
|
||
|
update(object: object, context: context)
|
||
|
}
|
||
|
|
||
|
private static func update(
|
||
|
object: Notification,
|
||
|
context: PersistContext
|
||
|
) {
|
||
|
// do nothing
|
||
|
}
|
||
|
|
||
|
}
|