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

Question About Using OCKAny Object #661

Open
shirblc opened this issue Jun 25, 2022 · 6 comments
Open

Question About Using OCKAny Object #661

shirblc opened this issue Jun 25, 2022 · 6 comments

Comments

@shirblc
Copy link

shirblc commented Jun 25, 2022

Hi!

Thank you so much for all the work you do on CareKit and ResearchKit.

I have a question about the Any types (OCKAnyPatient etc). I've been trying to add my own custom type of patient to the store, but I keep getting this error: CareKitStore.OCKStoreError.addFailed(reason: "Failed to add patients. Not all patients were of the correct type: OCKPatient").

I've done some digging and it looks like my app fails here. The debugger shows that:

1 Patient.self
2 
(CareKitStore.OCKStore.Patient.Type) $R0 = CareKitStore.OCKPatient

Which I'm guessing means that instead of using the associated Patient type defined in the OCKReadablePatientStore, it uses the default OCKStore Patient type. I couldn't find where it's set, but it looks like the OCKStore accepted types definition, hence my guess.

The same thing also happens when I try to add a custom plan. I haven't tried the other types, but I doubt it'll go any differently.

Is that supposed to be happening? Am I missing a step in adding a custom type? (e.g., do I have to create a custom store in order to create a custom type?) I've made sure my patient type conforms to OCKAnyPatient and I'm using the store.addAnyPatients method, which according to the docs seems like it should be enough, but it's entirely possible I missed something.

Thank you!

@gavirawson-apple
Copy link
Collaborator

(e.g., do I have to create a custom store in order to create a custom type?)

Yep! The OCKStore only knows how to store the OCK<Entity> types. Once you start adding new properties, you'll have to write store methods that will store/fetch those new properties. Once you write a few of the custom methods, some others will be synthesized automatically for you (IE fetchEvent(...) if you conform your task to OCKAnyVersionableTask).

If you have just a few new properties that you don't need to query against, there is a lightweight alternative you can consider. Each entity has a userInfo dictionary where you can put those properties to be later retrieved.

var task = OCKTask(...)
task.userInfo["priority"] = "1"

store.addTask(task)

@shirblc
Copy link
Author

shirblc commented Jun 27, 2022

I see, thank you very much for the full explanation!

In that case, wouldn't it be clearer not to have the default OCKStore conforming to the Any<Entity> protocols? Or at least make sure that the error and/or documentation indicate that it's required? (Or is it stated somewhere and I missed it?)

Also, is there any documentation on how to create/handle custom stores (other than this bit from the README)? Since there are different store protocols, does that mean I can recreate just the parts I need to customise, or do I have to recreate the entire store? Do I need to set up the whole CoreData stack, too, or it it enough to define the relevant classes?

Thank you again!

@gavirawson-apple
Copy link
Collaborator

In that case, wouldn't it be clearer not to have the default OCKStore conforming to the Any protocols?

Conforming to the type-erased entity protocols allows developers to use any type of store across CareKit. While it does provides flexibility, the downside is that you lose type safety. See this method below as an example of a seam where type safety is lost:

Screen Shot 2022-07-05 at 9 13 04 AM

We can try and explore some ways to bring type safety back while maintaining the flexibility of using any store. There have been some recent changes to Swift that will be very helpful.

Also, is there any documentation on how to create/handle custom stores

We unfortunately do not have a good example, but feel free to post questions here and I can help you out along the way. If you're interested, you can document the process and modify the Readme!

does that mean I can recreate just the parts I need to customise

Great question, it depends. If you're calling CRUD methods on your store, you can absolutely split it up into parts. But if you're using the CareKit view controllers, they require the full fledged OCKAnyStoreProtocol. We're working on modifying what the view controller needs so that you don't need to implement the full store protocol.

@shirblc
Copy link
Author

shirblc commented Jul 16, 2022

That makes sense. But since the methods don't work, shouldn't there be a warning (at least; it might make more sense to make it a fatal error), to let people know that a custom OCKAnyStore is required? (Although, as you've said, with Swift 5.6 we might not even need it.)

Thank you! I will definitely document the entire thing so that it's easier for anyone else interested in this. Is there any other written documentation I can add to, other than the README and carekit-apple.github.io? Or a way to add to the latter? Would love to write an in-depth guide on how to use it, but it might be too long for the README...

I'm using a couple of CareKit's view controllers, so as per your comment, I've started building an entire store. I think most of the methods are pretty straightforward, since they seem to be based around regular Core Data objects, but I'm not sure how to handle events and adherence. I thought an event would have its own model, but it doesn't seem to, so how/where are events stored? I know the OCKAnyStore protocol only requires read methods, but since I'm not sure how they're stored, I'm not sure how to read them either. And also, I assumed the CareKitStore handles the logic of creating events and updating them with outcomes once those are available, but if I'm creating my own store, do I need to do that myself, or is that handled by CareKit's extensions, like the one mentioned in the AnyStore section of the README?

As far as the Core Data store handling goes, I'm guessing I'll need to create the model for any object that I change, right? So how much of the original Core Data functionality do I need to rebuild for these Any objects? I saw CareKit's models are defined in CareKitStore/CoreData, and the code is generated manually and is based on OCKCDVersionedObject (which is a subclass of OCKCDObject), so do I need to rebuild all that functionality as well?

Thank you again for all the help and the detailed answers!

@shirblc
Copy link
Author

shirblc commented Jul 22, 2022

I've only just noticed the OCKAnyVersionableTask protocol (while setting up my Core Data stack). Is that how CareKit handles events? (Xcode still insists I'm missing required methods for Events in my custom OCKAnyStore, which makes me think I'm missing something. Probably something in how it's all connected and stored in Core Data, which I'm still not sure about.)

@gavirawson-apple
Copy link
Collaborator

But since the methods don't work, shouldn't there be a warning (at least; it might make more sense to make it a fatal error)

We pass back an error to the caller, I would definitely recommend checking that whenever adding tasks to the store. There are a few issues that could pop up.

Is there any other written documentation I can add to

The Readme is the best spot!

how much of the original Core Data functionality do I need to rebuild for these Any objects

The answer there sort of depends on what your custom models look like. What model requirements have led you to create custom models?

I've only just noticed the OCKAnyVersionableTask protocol

Yep. If you'd like your task to be versioned, you can conform your task to that protocol. As an added benefit, you'll get the fetchEvent methods synthesized for you for free.

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