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

fetchAll in ListPublisher observer doesnt get new data #486

Open
imrobbyrc opened this issue Jul 27, 2023 · 14 comments
Open

fetchAll in ListPublisher observer doesnt get new data #486

imrobbyrc opened this issue Jul 27, 2023 · 14 comments

Comments

@imrobbyrc
Copy link

hi @JohnEstropia, i have some problem about corestore observer, can you help me?

this my method when fetch data from server and save it into database

try! Omni.dataStack.perform(synchronous: { transaction in
    try! Omni.deactivateAll(transaction: transaction,
                            objects: [Omni.Group.self, Omni.Variant.self, Omni.Product.self,
                                      Omni.Modifier.self, Omni.ModifierGroup.self])

    let groups = try! transaction.importUniqueObjects(Into<Omni.Group>(),
                                                      sourceArray: json["groups"].arrayValue)

    let products = try! transaction.importUniqueObjects(Into<Omni.Product>(),
                                             sourceArray: json["products"].arrayValue)

    let productMapping = products.reduce(into: [Int: Omni.Product]()) { (result, object) in
        result[object.id] = object
    }
    
    let groupMapping = groups.reduce(into: [Int: Omni.Group]()) { (result, object) in
        result[object.id] = object
    }

    _ = try! transaction.importUniqueObjects(
        Into<Omni.Variant>(),
        /**
         json["variants"] represents a list of variant objects obtained from the API.
         JSON Structure:
         [
             {
                "id": Int,
                "code": String,
                "name": String,
                ....
             },
         ]
         Example File: Tests/Resources/JSONFiles/inventories_with_no_modifiers.json
         */
        sourceArray: json["variants"].arrayValue, preProcess: { mapping in
            var variantMapping = [Int: JSON]()
            for (key, variantJSON) in mapping {
                guard var dict = variantJSON.dictionaryObject else { continue }
                if let productId = variantJSON["product_id"].int {
                    dict["product_object"] = productMapping[productId]
                }

                var groupObjects = Set<Omni.Group>()
                for groupId in variantJSON["groups"].arrayValue {
                    if let group = groupMapping[groupId.intValue] {
                        groupObjects.insert(group)
                    }
                }

                dict["group_objects"] = groupObjects
                variantMapping[key] = JSON(dict)
            }
            return variantMapping
        }
    )
})

and i add new observer in viewcontroller to notify when variant get updated, so i will fetch all groups data, but groups data is not get the latest one

variantPublisher.addObserver(self, notifyInitial: true) { [weak self] publisher in
    guard let self else { return }
    let groups = try! Omni.dataStack.fetchAll(
        From<Omni.Group>()
            .where(\.$isActive == true && \.$typeValue == GroupTypes.regular.rawValue)
            .orderBy(.ascending(\.$position))
    )
    self.categories = CategoryViewModel.forDisplay(groups: groups)
}
@imrobbyrc
Copy link
Author

the result between fetchAll between fetchAll+ Where is different, all data should have isActive = true, but when i use where clause it only return 2 data, i have 3 active data with fetchAll only

Screen Shot 2023-07-27 at 22 48 54 Screen Shot 2023-07-27 at 22 49 08

@JohnEstropia
Copy link
Owner

Why do you observe on variantPublisher but fetch different objects inside the observer handler? Your observer handler will run only on the changes affecting whatever predicate you assigned to variantPublisher, so you should be using the publisher.snapshot passed through the observer closure.

@imrobbyrc
Copy link
Author

thanks for reply @JohnEstropia, i fetch different objects because variant have relation with groups, i need to know what groups that available for new data. i can use publisher.snapshot, but i need to iterrate all variants to get correct group

Screen Shot 2023-07-28 at 09 08 10

@JohnEstropia
Copy link
Owner

Your Variant publisher will not be notified even if any of their Groups are updated. You need to "ping" something in your Variant properties to update when their Group changes. Something like a lastGroupUpdateDate

@imrobbyrc
Copy link
Author

even i update groups in Variant ImportableUniqueObject protocol, my Variant publisher will not be notified?
Screen Shot 2023-07-28 at 09 36 25

@imrobbyrc
Copy link
Author

if i change my publisher closure to this, it will get a correct data instead of i use .where(\._isActive == true)

Screen Shot 2023-07-28 at 09 39 55

@JohnEstropia
Copy link
Owner

even i update groups in Variant ImportableUniqueObject protocol, my Variant publisher will not be notified?

Yes, because the Variant.group instances do not change, which means the ListPublisher<Variant> will not have a difference.

I'm not sure how the fetchAll predicate is related to this observer and how it's behaving different depending on the predicate. Can you show what your predicate is for variantPublisher?

@JohnEstropia
Copy link
Owner

You're also using notifyInitial: true which will run the closure immediately. Are you sure that you are looking at the closure after the transaction?

@imrobbyrc
Copy link
Author

i see, thats why observer doesnt get notified. thankyou

sure, this my variantPublisher code, just fetchAll and sorting it
Screen Shot 2023-07-28 at 09 54 43

@imrobbyrc
Copy link
Author

You're also using notifyInitial: true which will run the closure immediately. Are you sure that you are looking at the closure after the transaction?

i think the problem is not notifyInitial: true, because in first load i got a correct data, data will be break if i trigger variant update by using pull to refresh

@JohnEstropia
Copy link
Owner

I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type

@imrobbyrc
Copy link
Author

I see. You should also be careful because sorting with relationship keys only work on the initial list, but not on updates. In general you should avoid relying on relationships when it comes to ListPublisher (NSFetchedResultsController) predicates because they are only reevaluated one level from the original Entity type

oke @JohnEstropia thanks for reminded me, do we have utilities for combine two observer in coreStore?

@JohnEstropia
Copy link
Owner

There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to Variant that your imported entity can update everytime the Group relationship is imported from it.

@imrobbyrc
Copy link
Author

There's no performant way to observe on relationships (i.e. foreign table) so my recommended approach would be to add a private field to Variant that your imported entity can update everytime the Group relationship is imported from it.

i see thankyou @JohnEstropia , i will research new approach before going to use your suggestion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants