mastodon-ios/Mastodon/Persistence/Persistence+Notification.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
}
}