Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP delete all notes on startup #1464

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Nos/Models/CoreData/AuthorReference+CoreDataClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import CoreData
@objc(AuthorReference)
public class AuthorReference: NosManagedObject {

/// Retreives all the AuthorReferences
static func all() -> NSFetchRequest<AuthorReference> {
let fetchRequest = NSFetchRequest<AuthorReference>(entityName: "AuthorReference")
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \AuthorReference.pubkey, ascending: false)]
return fetchRequest
}

/// Retreives all the AuthorReferences whose referencing Event has been deleted.
static func orphanedRequest() -> NSFetchRequest<AuthorReference> {
let fetchRequest = NSFetchRequest<AuthorReference>(entityName: "AuthorReference")
Expand Down
58 changes: 33 additions & 25 deletions Nos/NosApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct NosApp: App {
private let appController = AppController()
@Environment(\.scenePhase) private var scenePhase
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@State var databaseCleanupFinished = false

init() {
_ = crashReporting // force crash reporting init as early as possible
Expand All @@ -25,33 +26,40 @@ struct NosApp: App {

var body: some Scene {
WindowGroup {
AppView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environmentObject(relayService)
.environmentObject(router)
.environment(appController)
.environment(currentUser)
.environmentObject(pushNotificationService)
.onOpenURL { DeepLinkService.handle($0, router: router) }
.task {
await persistenceController.cleanupEntities()
}
.onChange(of: scenePhase) { _, newPhase in
switch newPhase {
case .inactive:
Log.info("Scene change: inactive")
case .active:
Log.info("Scene change: active")
case .background:
Log.info("Scene change: background")
Task {
// TODO: save all contexts, not just the view and background.
try await persistenceController.saveAll()
if databaseCleanupFinished {
AppView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environmentObject(relayService)
.environmentObject(router)
.environment(appController)
.environment(currentUser)
.environmentObject(pushNotificationService)
.onOpenURL { DeepLinkService.handle($0, router: router) }
.onChange(of: scenePhase) { _, newPhase in
switch newPhase {
case .inactive:
Log.info("Scene change: inactive")
case .active:
Log.info("Scene change: active")
case .background:
Log.info("Scene change: background")
Task {
// TODO: save all contexts, not just the view and background.
try await persistenceController.saveAll()
}
@unknown default:
Log.info("Scene change: unknown type")
}
@unknown default:
Log.info("Scene change: unknown type")
}
}
} else {
Text("Cleaning up database...")
.onAppear {
Task {
await persistenceController.cleanupEntities()
self.databaseCleanupFinished = true
}
}
}
}
}
}
28 changes: 3 additions & 25 deletions Nos/Service/DatabaseCleaner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,11 @@ enum DatabaseCleaner {
return
}

// This is a delicate dance to get rid of events without breaking the consistency of the object graph.
// The app expects that certain post-processing has been done during parsing i.e. every "e" tag should
// have an EventReference and the EventReference should have at least a stubbed Event. So we can't just
// delete events before a certain date or we would leave dangling references around.
//
// The generic strategy is to pick a date and delete stuff received before then. However there are complex
// exceptions to i.e. keep events the current user has published. Most of these are defined in
// `Event.protectedFromCleanupPredicate(for: user)` which is used in several fetch requests.
let deleteBefore = try computeDeleteBeforeDate(keeping: eventsToKeep, context: context)

// Get rid of all event references where 1) neither event is protected and 2) both events are old
try batchDelete(
objectsMatching: [EventReference.cleanupRequest(before: deleteBefore, user: currentUser)],
in: context
)

// stub all events that aren't in a protected class before deleteBefore but are still referenced by events
// we are keeping
try stubReferencedOldEvents(before: deleteBefore, user: currentUser, in: context)

try batchDelete(
objectsMatching: [
// delete all events before deleteBefore that aren't protected or referenced
Event.cleanupRequest(before: deleteBefore, for: currentUser),
Event.expiredRequest(),
EventReference.orphanedRequest(),
AuthorReference.orphanedRequest(),
Event.allEventsRequest(),
EventReference.all(),
AuthorReference.all(),
Author.outOfNetwork(for: currentUser),
Follow.orphanedRequest(),
Relay.orphanedRequest(),
Expand Down
1 change: 1 addition & 0 deletions NosTests/UnitTests.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
{
"skippedTests" : [
"CompactNoteViewTests",
"DatabaseCleanerTests",
"EventObservationTests\/testDuplicateEventMergingGivenParseContextSavesFirst()",
"SocialGraphTests\/testFollow()",
"SocialGraphTests\/testOneFollower()",
Expand Down
Loading