adding support of persistent history tracking #249

Open
opened 2025-12-29 18:24:55 +01:00 by adam · 10 comments
Owner

Originally created by @dlavlinskyi on GitHub (Dec 26, 2018).

Apple added NSPersistentContainer which makes setup of CoreData much easier, same as part of CoreStore does.
CoreStore is really cool CD wrapper, I would love to use it in my project, except one "but":

I'm trying to use NSPersistentHistory classes to fetch changes from persistent store, to do so i have to add set true to NSPersistentHistoryTrackingKey key for store options. Apple provided following API:

let description: NSPersistentStoreDescription = ... // Your default configuration here
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)

let container = ... // Your default configuration here
container.persistentStoreDescriptions = [description]

than to fetch history:

let historyFetchRequest = NSPersistentHistoryChangeRequest.fetchHistory(after: timestamp)
let context = CoreStore.defaultStack.unsafeContext()
do {
      let result = try context.execute(historyFetchRequest) as? NSPersistentHistoryResult
      let transactions = result?.result as! [NSPersistentHistoryTransaction]
      print(transactions)
} catch {
      print(error)
}

I tried to add this option using CoreStore in SQLiteSore class:

public let storeOptions: [AnyHashable: Any]? = autoreleasepool {
        
        var storeOptions: [AnyHashable: Any] = [NSSQLitePragmasOption: ["journal_mode": "WAL"]]
        if #available(iOS 11.0, macOS 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *) {

            storeOptions[NSBinaryStoreInsecureDecodingCompatibilityOption] = true
            storeOptions[NSPersistentHistoryTrackingKey] = true
        }
        return storeOptions
    }

but history fetch request fails with "very informative" error nilError. So, I suppose persistent history tracking works only when persistent stores was initialized by NSPersistentContainer. Do you have any other ideas or any suggestions how to solve this issue? Am I doing something wrong?
One of my ideas was to make abstraction of DataStack (instead of class DataStack use protocol DataStack). Protocol will have all properties required by Transactions and Quering extensions. Will it be good idea to start with? Won't it cause a break of main architecture ideas?

Originally created by @dlavlinskyi on GitHub (Dec 26, 2018). Apple added NSPersistentContainer which makes setup of CoreData much easier, same as part of CoreStore does. CoreStore is really cool CD wrapper, I would love to use it in my project, except one "but": I'm trying to use NSPersistentHistory classes to fetch changes from persistent store, to do so i have to add set `true` to `NSPersistentHistoryTrackingKey` key for store options. Apple provided following API: ``` let description: NSPersistentStoreDescription = ... // Your default configuration here description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) let container = ... // Your default configuration here container.persistentStoreDescriptions = [description] ``` than to fetch history: ``` let historyFetchRequest = NSPersistentHistoryChangeRequest.fetchHistory(after: timestamp) let context = CoreStore.defaultStack.unsafeContext() do { let result = try context.execute(historyFetchRequest) as? NSPersistentHistoryResult let transactions = result?.result as! [NSPersistentHistoryTransaction] print(transactions) } catch { print(error) } ``` I tried to add this option using CoreStore in `SQLiteSore` class: ``` public let storeOptions: [AnyHashable: Any]? = autoreleasepool { var storeOptions: [AnyHashable: Any] = [NSSQLitePragmasOption: ["journal_mode": "WAL"]] if #available(iOS 11.0, macOS 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *) { storeOptions[NSBinaryStoreInsecureDecodingCompatibilityOption] = true storeOptions[NSPersistentHistoryTrackingKey] = true } return storeOptions } ``` but history fetch request fails with "very informative" error `nilError`. So, I suppose persistent history tracking works only when persistent stores was initialized by `NSPersistentContainer`. Do you have any other ideas or any suggestions how to solve this issue? Am I doing something wrong? One of my ideas was to make abstraction of DataStack (instead of class DataStack use protocol DataStack). Protocol will have all properties required by `Transactions` and `Quering` extensions. Will it be good idea to start with? Won't it cause a break of main architecture ideas?
Author
Owner

@andris-zalitis commented on GitHub (Feb 8, 2019):

I had the same issue (though unrelated to CoreStore). Turns out that in order to be able to fetch persistent history transactions, NSManagedObjectContext must be created using NSPersistentContainer API.

@andris-zalitis commented on GitHub (Feb 8, 2019): I had the same issue (though unrelated to CoreStore). Turns out that in order to be able to fetch persistent history transactions, `NSManagedObjectContext` must be created using `NSPersistentContainer` API.
Author
Owner

@JohnEstropia commented on GitHub (Sep 30, 2021):

I have plans to support this, but I've only just begun prototyping for stores that support persistent history tracking, with "shared stores" as the main use-case for sharing data between multiple apps and extensions. I've heard mentions about it requiring NSPersistentContainer, but I personally believe it should be doable with manually managed NSPersistentStoreCoordinator, we'd just have to find the right parameters for the setup. If it's needed, CoreStore might need to migrate to using NSPersistentContainer, which is another big refactor in itself.

That said, I cannot promise a release date and it may be a long time before we'd have a working branch for it.

@JohnEstropia commented on GitHub (Sep 30, 2021): I have plans to support this, but I've only just begun prototyping for stores that support persistent history tracking, with "shared stores" as the main use-case for sharing data between multiple apps and extensions. I've heard mentions about it requiring `NSPersistentContainer`, but I personally believe it should be doable with manually managed `NSPersistentStoreCoordinator`, we'd just have to find the right parameters for the setup. If it's needed, CoreStore might need to migrate to using `NSPersistentContainer`, which is another big refactor in itself. That said, I cannot promise a release date and it may be a long time before we'd have a working branch for it.
Author
Owner

@spacedema commented on GitHub (Jan 20, 2022):

Hi @JohnEstropia, any updates on this?

@spacedema commented on GitHub (Jan 20, 2022): Hi @JohnEstropia, any updates on this?
Author
Owner

@JohnEstropia commented on GitHub (Jan 21, 2022):

I'm still in the experimental stages for this since I don't have a project that urgently needs it right now. I do have the interface in place already for shared stores using App Group Identifiers, but the internal implementation is still in progress.

@JohnEstropia commented on GitHub (Jan 21, 2022): I'm still in the experimental stages for this since I don't have a project that urgently needs it right now. I do have the interface in place already for shared stores using App Group Identifiers, but the internal implementation is still in progress.
Author
Owner

@spacedema commented on GitHub (Jan 21, 2022):

Ok, thanks for the answer
https://github.com/JohnEstropia/CoreStore/issues/440
it will be possible to implement showcase app data in Spotlight https://developer.apple.com/videos/play/wwdc2021/10098/ and Access Attributes of a Deleted Object https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes

There is a problem with 1->M relationship and cascade delete in ListMonotor, when deleting the root object, nested records that are deleted cascaded have all fields null ("" or 0) in ListMonitor

I think Implementing Persistent History Tracking will solve many problems and be useful to many Core Store users.

@spacedema commented on GitHub (Jan 21, 2022): Ok, thanks for the answer [https://github.com/JohnEstropia/CoreStore/issues/440](https://github.com/JohnEstropia/CoreStore/issues/440) it will be possible to implement showcase app data in Spotlight [https://developer.apple.com/videos/play/wwdc2021/10098/](https://developer.apple.com/videos/play/wwdc2021/10098/) and Access Attributes of a Deleted Object [https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes](https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes) There is a problem with 1->M relationship and cascade delete in ListMonotor, when deleting the root object, nested records that are deleted cascaded have all fields null ("" or 0) in ListMonitor I think Implementing Persistent History Tracking will solve many problems and be useful to many Core Store users.
Author
Owner

@JohnEstropia commented on GitHub (Jan 21, 2022):

Yes, history tracking will enable app extensions (such as the Spotlight Import extension) to share Core Data records with the main app.

I'm not sure the ListMonitor issue(?) you mentioned is related though. Does your relationship have correct delete rules on both Entities of the relationship?

@JohnEstropia commented on GitHub (Jan 21, 2022): Yes, history tracking will enable app extensions (such as the Spotlight Import extension) to share Core Data records with the main app. I'm not sure the ListMonitor issue(?) you mentioned is related though. Does your relationship have correct delete rules on both Entities of the relationship?
Author
Owner

@spacedema commented on GitHub (Jan 21, 2022):

The method described in https://github.com/JohnEstropia/CoreStore/issues/362 solves the problem of deleting Attachments entities, but if I delete the Root object, which will cascade delete Attachments, in Attachments ListMonitor listMonitorWillChange, all fields will be null("" or 0). Therefore, I thought that Access Attributes of a Deleted Object could solve this problem.
And yes, relationship has correct delete rules on both Entities of the relationship (Cascade for Root entity attachments collection and Nullify for Attachments entity)

@spacedema commented on GitHub (Jan 21, 2022): The method described in [https://github.com/JohnEstropia/CoreStore/issues/362](https://github.com/JohnEstropia/CoreStore/issues/362) solves the problem of deleting Attachments entities, but if I delete the Root object, which will cascade delete Attachments, in Attachments ListMonitor `listMonitorWillChange`, all fields will be null("" or 0). Therefore, I thought that Access Attributes of a Deleted Object could solve this problem. And yes, relationship has correct delete rules on both Entities of the relationship (Cascade for Root entity attachments collection and Nullify for Attachments entity)
Author
Owner

@spacedema commented on GitHub (Jan 21, 2022):

Should I create a separate issue for this case, @JohnEstropia ?

@spacedema commented on GitHub (Jan 21, 2022): Should I create a separate issue for this case, @JohnEstropia ?
Author
Owner

@JohnEstropia commented on GitHub (Jan 21, 2022):

Yes, thanks @spacedema! Please include relevant code for the affected Entities

@JohnEstropia commented on GitHub (Jan 21, 2022): Yes, thanks @spacedema! Please include relevant code for the affected Entities
Author
Owner

@spacedema commented on GitHub (Jan 21, 2022):

@JohnEstropia
https://github.com/JohnEstropia/CoreStore/issues/447

@spacedema commented on GitHub (Jan 21, 2022): @JohnEstropia https://github.com/JohnEstropia/CoreStore/issues/447
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore-JohnEstropia#249