metatext/DB/Sources/DB/Content/ContentDatabase.swift

501 lines
20 KiB
Swift
Raw Normal View History

2020-08-18 05:13:37 +00:00
// Copyright © 2020 Metabolist. All rights reserved.
import Combine
2020-09-05 02:31:43 +00:00
import Foundation
2020-08-18 05:13:37 +00:00
import GRDB
2020-09-04 06:12:06 +00:00
import Keychain
2020-08-30 23:33:11 +00:00
import Mastodon
2020-09-04 06:12:06 +00:00
import Secrets
2020-08-18 05:13:37 +00:00
2020-10-27 03:01:12 +00:00
// swiftlint:disable file_length
2020-09-03 03:28:34 +00:00
public struct ContentDatabase {
2020-10-03 20:50:46 +00:00
public let activeFiltersPublisher: AnyPublisher<[Filter], Error>
2020-09-28 03:11:49 +00:00
private let databaseWriter: DatabaseWriter
2020-08-18 05:13:37 +00:00
2020-10-27 03:01:12 +00:00
public init(id: Identity.Id,
useHomeTimelineLastReadId: Bool,
useNotificationsLastReadId: Bool,
inMemory: Bool,
keychain: Keychain.Type) throws {
2020-09-03 03:28:34 +00:00
if inMemory {
2020-09-28 03:11:49 +00:00
databaseWriter = DatabaseQueue()
2020-08-18 05:13:37 +00:00
} else {
2020-10-05 22:50:05 +00:00
let path = try Self.fileURL(id: id).path
2020-09-04 06:12:06 +00:00
var configuration = Configuration()
2020-09-07 14:25:26 +00:00
configuration.prepareDatabase {
2020-10-05 22:50:05 +00:00
try $0.usePassphrase(Secrets.databaseKey(identityId: id, keychain: keychain))
2020-09-04 06:12:06 +00:00
}
2020-09-28 03:11:49 +00:00
databaseWriter = try DatabasePool(path: path, configuration: configuration)
2020-08-18 05:13:37 +00:00
}
2020-10-03 20:50:46 +00:00
try Self.migrator.migrate(databaseWriter)
2020-10-27 03:01:12 +00:00
try Self.clean(
databaseWriter,
useHomeTimelineLastReadId: useHomeTimelineLastReadId,
useNotificationsLastReadId: useNotificationsLastReadId)
2020-10-03 20:50:46 +00:00
activeFiltersPublisher = ValueObservation.tracking {
try Filter.filter(Filter.Columns.expiresAt == nil || Filter.Columns.expiresAt > Date()).fetchAll($0)
}
.removeDuplicates()
.publisher(in: databaseWriter)
.eraseToAnyPublisher()
2020-08-18 05:13:37 +00:00
}
}
2020-09-03 03:28:34 +00:00
public extension ContentDatabase {
2020-10-05 22:50:05 +00:00
static func delete(id: Identity.Id) throws {
try FileManager.default.removeItem(at: fileURL(id: id))
2020-09-03 01:14:33 +00:00
}
2020-09-02 09:39:44 +00:00
func insert(status: Status) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher(updates: status.save)
2020-09-02 09:39:44 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-04 08:39:54 +00:00
func insert(
statuses: [Status],
timeline: Timeline,
loadMoreAndDirection: (LoadMore, LoadMore.Direction)? = nil) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-10-02 07:41:30 +00:00
let timelineRecord = TimelineRecord(timeline: timeline)
try timelineRecord.save($0)
2020-10-05 22:50:05 +00:00
let maxIdPresent = try String.fetchOne($0, timelineRecord.statuses.select(max(StatusRecord.Columns.id)))
2020-08-18 05:13:37 +00:00
for status in statuses {
2020-09-02 09:39:44 +00:00
try status.save($0)
2020-08-18 05:13:37 +00:00
2020-09-02 09:39:44 +00:00
try TimelineStatusJoin(timelineId: timeline.id, statusId: status.id).save($0)
2020-09-02 02:39:06 +00:00
}
2020-10-02 07:41:30 +00:00
2020-10-05 22:50:05 +00:00
if let maxIdPresent = maxIdPresent,
let minIdInserted = statuses.map(\.id).min(),
minIdInserted > maxIdPresent {
2020-10-04 08:39:54 +00:00
try LoadMoreRecord(
timelineId: timeline.id,
2020-10-05 22:50:05 +00:00
afterStatusId: minIdInserted,
beforeStatusId: maxIdPresent)
2020-10-04 08:39:54 +00:00
.save($0)
}
guard let (loadMore, direction) = loadMoreAndDirection else { return }
try LoadMoreRecord(
timelineId: loadMore.timeline.id,
afterStatusId: loadMore.afterStatusId,
beforeStatusId: loadMore.beforeStatusId)
.delete($0)
switch direction {
case .up:
2020-10-05 22:50:05 +00:00
if let maxIdInserted = statuses.map(\.id).max(), maxIdInserted < loadMore.afterStatusId {
2020-10-04 08:39:54 +00:00
try LoadMoreRecord(
timelineId: loadMore.timeline.id,
afterStatusId: loadMore.afterStatusId,
2020-10-05 22:50:05 +00:00
beforeStatusId: maxIdInserted)
2020-10-04 08:39:54 +00:00
.save($0)
}
case .down:
2020-10-05 22:50:05 +00:00
if let minIdInserted = statuses.map(\.id).min(), minIdInserted > loadMore.beforeStatusId {
2020-10-04 08:39:54 +00:00
try LoadMoreRecord(
timelineId: loadMore.timeline.id,
2020-10-05 22:50:05 +00:00
afterStatusId: minIdInserted,
2020-10-04 08:39:54 +00:00
beforeStatusId: loadMore.beforeStatusId)
.save($0)
}
2020-10-02 07:41:30 +00:00
}
2020-09-02 02:39:06 +00:00
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-05 22:50:05 +00:00
func insert(context: Context, parentId: Status.Id) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-10-03 09:19:05 +00:00
for (index, status) in context.ancestors.enumerated() {
2020-09-02 09:39:44 +00:00
try status.save($0)
2020-10-05 22:50:05 +00:00
try StatusAncestorJoin(parentId: parentId, statusId: status.id, index: index).save($0)
2020-09-02 02:39:06 +00:00
}
2020-10-03 09:19:05 +00:00
for (index, status) in context.descendants.enumerated() {
try status.save($0)
2020-10-05 22:50:05 +00:00
try StatusDescendantJoin(parentId: parentId, statusId: status.id, index: index).save($0)
2020-08-18 05:13:37 +00:00
}
2020-10-03 09:19:05 +00:00
try StatusAncestorJoin.filter(
2020-10-05 22:50:05 +00:00
StatusAncestorJoin.Columns.parentId == parentId
2020-10-03 09:19:05 +00:00
&& !context.ancestors.map(\.id).contains(StatusAncestorJoin.Columns.statusId))
.deleteAll($0)
try StatusDescendantJoin.filter(
2020-10-05 22:50:05 +00:00
StatusDescendantJoin.Columns.parentId == parentId
2020-10-03 09:19:05 +00:00
&& !context.descendants.map(\.id).contains(StatusDescendantJoin.Columns.statusId))
.deleteAll($0)
2020-08-18 05:13:37 +00:00
}
2020-08-26 09:19:38 +00:00
.ignoreOutput()
2020-08-18 05:13:37 +00:00
.eraseToAnyPublisher()
}
2020-10-05 22:50:05 +00:00
func insert(pinnedStatuses: [Status], accountId: Account.Id) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-09-18 00:16:41 +00:00
for (index, status) in pinnedStatuses.enumerated() {
try status.save($0)
2020-10-05 22:50:05 +00:00
try AccountPinnedStatusJoin(accountId: accountId, statusId: status.id, index: index).save($0)
2020-09-18 00:16:41 +00:00
}
try AccountPinnedStatusJoin.filter(
2020-10-05 22:50:05 +00:00
AccountPinnedStatusJoin.Columns.accountId == accountId
2020-09-29 06:06:25 +00:00
&& !pinnedStatuses.map(\.id).contains(AccountPinnedStatusJoin.Columns.statusId))
2020-09-18 00:16:41 +00:00
.deleteAll($0)
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-14 00:03:01 +00:00
func toggleShowContent(id: Status.Id) -> AnyPublisher<Never, Error> {
2020-10-07 21:06:26 +00:00
databaseWriter.writePublisher {
2020-10-14 00:03:01 +00:00
if let toggle = try StatusShowContentToggle
.filter(StatusShowContentToggle.Columns.statusId == id)
2020-10-07 21:06:26 +00:00
.fetchOne($0) {
try toggle.delete($0)
} else {
2020-10-14 00:03:01 +00:00
try StatusShowContentToggle(statusId: id).save($0)
2020-10-07 21:06:26 +00:00
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-14 00:03:01 +00:00
func toggleShowAttachments(id: Status.Id) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
if let toggle = try StatusShowAttachmentsToggle
.filter(StatusShowAttachmentsToggle.Columns.statusId == id)
.fetchOne($0) {
try toggle.delete($0)
} else {
try StatusShowAttachmentsToggle(statusId: id).save($0)
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
func expand(ids: Set<Status.Id>) -> AnyPublisher<Never, Error> {
2020-10-07 21:06:26 +00:00
databaseWriter.writePublisher {
for id in ids {
2020-10-14 00:03:01 +00:00
try StatusShowContentToggle(statusId: id).save($0)
try StatusShowAttachmentsToggle(statusId: id).save($0)
2020-10-07 21:06:26 +00:00
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-14 00:03:01 +00:00
func collapse(ids: Set<Status.Id>) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
try StatusShowContentToggle
.filter(ids.contains(StatusShowContentToggle.Columns.statusId))
.deleteAll($0)
try StatusShowAttachmentsToggle
.filter(ids.contains(StatusShowContentToggle.Columns.statusId))
.deleteAll($0)
}
.ignoreOutput()
.eraseToAnyPublisher()
2020-10-07 21:06:26 +00:00
}
2020-10-25 02:31:44 +00:00
func update(id: Status.Id, poll: Poll) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
let data = try StatusRecord.databaseJSONEncoder(for: StatusRecord.Columns.poll.name).encode(poll)
try StatusRecord.filter(StatusRecord.Columns.id == id)
.updateAll($0, StatusRecord.Columns.poll.set(to: data))
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-09-28 22:40:03 +00:00
func append(accounts: [Account], toList list: AccountList) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-09-28 22:40:03 +00:00
try list.save($0)
let count = try list.accounts.fetchCount($0)
for (index, account) in accounts.enumerated() {
2020-09-22 06:53:11 +00:00
try account.save($0)
2020-09-28 22:40:03 +00:00
try AccountListJoin(accountId: account.id, listId: list.id, index: count + index).save($0)
2020-09-22 06:53:11 +00:00
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-09-26 03:28:50 +00:00
func setLists(_ lists: [List]) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-08-29 03:50:58 +00:00
for list in lists {
2020-10-02 07:41:30 +00:00
try TimelineRecord(timeline: Timeline.list(list)).save($0)
2020-08-29 03:50:58 +00:00
}
2020-10-01 02:35:06 +00:00
try TimelineRecord
.filter(!lists.map(\.id).contains(TimelineRecord.Columns.listId)
&& TimelineRecord.Columns.listTitle != nil)
2020-09-09 05:40:49 +00:00
.deleteAll($0)
2020-08-29 03:50:58 +00:00
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-09-26 03:28:50 +00:00
func createList(_ list: List) -> AnyPublisher<Never, Error> {
2020-10-02 07:41:30 +00:00
databaseWriter.writePublisher(updates: TimelineRecord(timeline: Timeline.list(list)).save)
2020-08-29 03:50:58 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-05 22:50:05 +00:00
func deleteList(id: List.Id) -> AnyPublisher<Never, Error> {
2020-10-01 02:35:06 +00:00
databaseWriter.writePublisher(updates: TimelineRecord.filter(TimelineRecord.Columns.listId == id).deleteAll)
2020-08-29 10:26:26 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
func setFilters(_ filters: [Filter]) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher {
2020-08-29 10:26:26 +00:00
for filter in filters {
try filter.save($0)
}
2020-09-29 06:06:25 +00:00
try Filter.filter(!filters.map(\.id).contains(Filter.Columns.id)).deleteAll($0)
2020-08-29 10:26:26 +00:00
}
2020-08-29 03:50:58 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-08-29 10:26:26 +00:00
func createFilter(_ filter: Filter) -> AnyPublisher<Never, Error> {
2020-09-28 03:11:49 +00:00
databaseWriter.writePublisher(updates: filter.save)
2020-08-29 10:26:26 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-05 22:50:05 +00:00
func deleteFilter(id: Filter.Id) -> AnyPublisher<Never, Error> {
2020-09-29 06:06:25 +00:00
databaseWriter.writePublisher(updates: Filter.filter(Filter.Columns.id == id).deleteAll)
2020-08-29 10:26:26 +00:00
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-27 03:01:12 +00:00
func setLastReadId(_ id: String, markerTimeline: Marker.Timeline) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher(updates: LastReadIdRecord(markerTimeline: markerTimeline, id: id).save)
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-30 07:11:24 +00:00
func insert(notifications: [MastodonNotification]) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
for notification in notifications {
try notification.save($0)
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-29 06:03:45 +00:00
func insert(conversations: [Conversation]) -> AnyPublisher<Never, Error> {
databaseWriter.writePublisher {
for conversation in conversations {
try conversation.save($0)
}
}
.ignoreOutput()
.eraseToAnyPublisher()
}
2020-10-06 20:44:22 +00:00
func timelinePublisher(_ timeline: Timeline) -> AnyPublisher<[[CollectionItem]], Error> {
2020-10-03 20:50:46 +00:00
ValueObservation.tracking(
TimelineItemsInfo.request(TimelineRecord.filter(TimelineRecord.Columns.id == timeline.id)).fetchOne)
.removeDuplicates()
.publisher(in: databaseWriter)
.combineLatest(activeFiltersPublisher)
.compactMap { $0?.items(filters: $1) }
.eraseToAnyPublisher()
2020-08-19 22:16:03 +00:00
}
2020-08-29 03:50:58 +00:00
2020-10-06 20:44:22 +00:00
func contextPublisher(id: Status.Id) -> AnyPublisher<[[CollectionItem]], Error> {
2020-10-03 20:50:46 +00:00
ValueObservation.tracking(
2020-10-05 22:50:05 +00:00
ContextItemsInfo.request(StatusRecord.filter(StatusRecord.Columns.id == id)).fetchOne)
2020-10-03 20:50:46 +00:00
.removeDuplicates()
.publisher(in: databaseWriter)
.combineLatest(activeFiltersPublisher)
.compactMap { $0?.items(filters: $1) }
.eraseToAnyPublisher()
2020-09-18 00:16:41 +00:00
}
2020-10-06 20:44:22 +00:00
func listsPublisher() -> AnyPublisher<[Timeline], Error> {
2020-10-01 02:35:06 +00:00
ValueObservation.tracking(TimelineRecord.filter(TimelineRecord.Columns.listId != nil)
.order(TimelineRecord.Columns.listTitle.asc)
2020-08-29 03:50:58 +00:00
.fetchAll)
2020-08-29 10:26:26 +00:00
.removeDuplicates()
2020-09-28 03:11:49 +00:00
.publisher(in: databaseWriter)
2020-10-03 09:19:05 +00:00
.tryMap { $0.map(Timeline.init(record:)).compactMap { $0 } }
2020-08-29 10:26:26 +00:00
.eraseToAnyPublisher()
}
2020-10-06 20:44:22 +00:00
func expiredFiltersPublisher() -> AnyPublisher<[Filter], Error> {
2020-10-03 20:50:46 +00:00
ValueObservation.tracking { try Filter.filter(Filter.Columns.expiresAt < Date()).fetchAll($0) }
2020-08-30 00:32:34 +00:00
.removeDuplicates()
2020-09-28 03:11:49 +00:00
.publisher(in: databaseWriter)
2020-08-30 00:32:34 +00:00
.eraseToAnyPublisher()
}
2020-09-22 06:53:11 +00:00
2020-10-06 20:44:22 +00:00
func accountPublisher(id: Account.Id) -> AnyPublisher<Account, Error> {
2020-09-29 23:56:09 +00:00
ValueObservation.tracking(AccountInfo.request(AccountRecord.filter(AccountRecord.Columns.id == id)).fetchOne)
2020-09-22 06:53:11 +00:00
.removeDuplicates()
2020-10-01 02:35:06 +00:00
.publisher(in: databaseWriter)
2020-10-03 20:55:07 +00:00
.compactMap { $0 }
.map(Account.init(info:))
2020-09-22 06:53:11 +00:00
.eraseToAnyPublisher()
}
2020-09-28 22:40:03 +00:00
2020-10-06 20:44:22 +00:00
func accountListPublisher(_ list: AccountList) -> AnyPublisher<[Account], Error> {
2020-09-28 22:40:03 +00:00
ValueObservation.tracking(list.accounts.fetchAll)
.removeDuplicates()
2020-09-29 23:56:09 +00:00
.map { $0.map(Account.init(info:)) }
2020-10-01 02:35:06 +00:00
.publisher(in: databaseWriter)
2020-09-28 22:40:03 +00:00
.eraseToAnyPublisher()
}
2020-10-27 03:01:12 +00:00
2020-10-30 07:11:24 +00:00
func notificationsPublisher() -> AnyPublisher<[[CollectionItem]], Error> {
ValueObservation.tracking(
NotificationInfo.request(
NotificationRecord.order(NotificationRecord.Columns.id.desc)).fetchAll)
.removeDuplicates()
.publisher(in: databaseWriter)
.map { [$0.map {
let configuration: CollectionItem.StatusConfiguration?
if $0.record.type == .mention, let statusInfo = $0.statusInfo {
configuration = CollectionItem.StatusConfiguration(
showContentToggled: statusInfo.showContentToggled,
showAttachmentsToggled: statusInfo.showAttachmentsToggled)
} else {
configuration = nil
}
return .notification(MastodonNotification(info: $0), configuration)
}] }
.eraseToAnyPublisher()
}
2020-10-29 06:03:45 +00:00
func conversationsPublisher() -> AnyPublisher<[Conversation], Error> {
ValueObservation.tracking(ConversationInfo.request(ConversationRecord.all()).fetchAll)
.removeDuplicates()
.publisher(in: databaseWriter)
.map {
$0.sorted { $0.lastStatusInfo.record.createdAt > $1.lastStatusInfo.record.createdAt }
.map(Conversation.init(info:))
}
.eraseToAnyPublisher()
}
2020-10-27 03:01:12 +00:00
func lastReadId(_ markerTimeline: Marker.Timeline) -> String? {
try? databaseWriter.read {
try String.fetchOne(
$0,
LastReadIdRecord.filter(LastReadIdRecord.Columns.markerTimeline == markerTimeline.rawValue)
.select(LastReadIdRecord.Columns.id))
}
}
2020-08-18 05:13:37 +00:00
}
private extension ContentDatabase {
2020-10-27 03:01:12 +00:00
static let cleanAfterLastReadIdCount = 40
2020-10-05 22:50:05 +00:00
static func fileURL(id: Identity.Id) throws -> URL {
try FileManager.default.databaseDirectoryURL(name: id.uuidString)
2020-09-03 01:14:33 +00:00
}
2020-11-03 04:24:56 +00:00
// swiftlint:disable:next function_body_length
2020-10-27 03:01:12 +00:00
static func clean(_ databaseWriter: DatabaseWriter,
useHomeTimelineLastReadId: Bool,
useNotificationsLastReadId: Bool) throws {
2020-09-29 06:35:11 +00:00
try databaseWriter.write {
2020-11-03 04:24:56 +00:00
let notificationAccountIds: [Account.Id]
let notificationStatusIds: [Status.Id]
2020-10-29 06:03:45 +00:00
try ConversationRecord.deleteAll($0)
2020-11-03 04:24:56 +00:00
if useNotificationsLastReadId {
var notificationIds = try MastodonNotification.Id.fetchAll(
$0,
NotificationRecord.select(NotificationRecord.Columns.id)
.order(NotificationRecord.Columns.id.desc))
if let lastReadId = try MastodonNotification.Id.fetchOne(
$0,
LastReadIdRecord.filter(
LastReadIdRecord.Columns.markerTimeline == Marker.Timeline.notifications.rawValue)
.select(LastReadIdRecord.Columns.id))
?? notificationIds.first,
let index = notificationIds.firstIndex(of: lastReadId) {
notificationIds = Array(notificationIds.prefix(index + Self.cleanAfterLastReadIdCount))
}
try NotificationRecord.filter(!notificationIds.contains(NotificationRecord.Columns.id)).deleteAll($0)
notificationAccountIds = try Account.Id.fetchAll(
$0,
NotificationRecord.select(NotificationRecord.Columns.accountId))
notificationStatusIds = try Status.Id.fetchAll(
$0,
NotificationRecord.filter(
NotificationRecord.Columns.statusId != nil)
.select(NotificationRecord.Columns.statusId))
} else {
try NotificationRecord.deleteAll($0)
notificationAccountIds = []
notificationStatusIds = []
}
2020-10-30 07:11:24 +00:00
2020-10-27 03:01:12 +00:00
if useHomeTimelineLastReadId {
try TimelineRecord.filter(TimelineRecord.Columns.id != Timeline.home.id).deleteAll($0)
var statusIds = try Status.Id.fetchAll(
$0,
TimelineStatusJoin.select(TimelineStatusJoin.Columns.statusId)
.order(TimelineStatusJoin.Columns.statusId.desc))
if let lastReadId = try Status.Id.fetchOne(
$0,
LastReadIdRecord.filter(LastReadIdRecord.Columns.markerTimeline == Marker.Timeline.home.rawValue)
.select(LastReadIdRecord.Columns.id))
?? statusIds.first,
let index = statusIds.firstIndex(of: lastReadId) {
statusIds = Array(statusIds.prefix(index + Self.cleanAfterLastReadIdCount))
}
2020-11-03 04:24:56 +00:00
statusIds += notificationStatusIds
2020-10-27 03:01:12 +00:00
statusIds += try Status.Id.fetchAll(
$0,
StatusRecord.filter(statusIds.contains(StatusRecord.Columns.id)
&& StatusRecord.Columns.reblogId != nil)
.select(StatusRecord.Columns.reblogId))
2020-11-03 04:24:56 +00:00
try StatusRecord.filter(!statusIds.contains(StatusRecord.Columns.id)).deleteAll($0)
2020-10-27 03:01:12 +00:00
var accountIds = try Account.Id.fetchAll($0, StatusRecord.select(StatusRecord.Columns.accountId))
2020-11-03 04:24:56 +00:00
accountIds += notificationAccountIds
2020-10-27 03:01:12 +00:00
accountIds += try Account.Id.fetchAll(
$0,
AccountRecord.filter(accountIds.contains(AccountRecord.Columns.id)
&& AccountRecord.Columns.movedId != nil)
.select(AccountRecord.Columns.movedId))
try AccountRecord.filter(!accountIds.contains(AccountRecord.Columns.id)).deleteAll($0)
} else {
try TimelineRecord.deleteAll($0)
2020-11-03 04:24:56 +00:00
try StatusRecord.filter(!notificationStatusIds.contains(StatusRecord.Columns.id)).deleteAll($0)
try AccountRecord.filter(!notificationAccountIds.contains(AccountRecord.Columns.id)).deleteAll($0)
2020-10-27 03:01:12 +00:00
}
2020-09-28 22:40:03 +00:00
try AccountList.deleteAll($0)
2020-09-29 06:35:11 +00:00
}
}
2020-08-18 05:13:37 +00:00
}
2020-10-27 03:01:12 +00:00
// swiftlint:enable file_length