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
Update normalized form to follow JSON API #157
Comments
Yup, can see the advantages. Polymorphic relationships would be useful and having as we discussed before having meta data on the relationships will be useful for tracking the load-status (not-loaded, partially-loaded, fully-loaded). We don't use secondary keys so that doesn't effect us. One question though, is there any way to determine the type of a relationship? (hasOne vs hasMany) without going back to the schema? |
I've been puzzling over this myself. The one obvious method would be to require a default value ( |
Having thought about this more, perhaps we're trying to squeeze schema information into the operation where really we should just accept that the schema is necessary to interpret it? We have a schema so we might as well lean on it. The operation encoder is already acting as a convenience layer for dispatching based on the operation's properties. Perhaps we consolidate more here? i.e.
With the operation encoder refactor though I did find that explicitly listing handlers by operation type did really help to clarify what was going on. It also avoided erroneous handling of operations due to misidentification. I think the dispatching could be a little prettier (the switch statement isn't great, particularly when you have multiple cases with the same handler) but it does the job. So perhaps we don't need to worry about hasOne vs hasMany within the operation. The main benefits I see here are handling of polymorphic relationships and the extensible structure. |
@opsb I agree with everything you've said. There's no hard requirement to completely avoid usage of the schema to analyze operations (although minimizing schema references should help performance). And I agree that we probably should expand the operation encoder with more convenience methods. |
This is looking like an extremely useful change at the moment. I'm now seeing that it would be really useful to to track in-progress state for loading of links i.e. loadStatus: not loaded / partially loaded / >>loading<< / fully loaded |
I've been rethinking this proposal and would like to consider using a slightly modified version of the JSON API format for Orbit's normalized form. Here are the proposed changes and reasoning:
Here are the contents of a simple cache using this format (note: UUIDs have been simplified for illustration):
Resource objects could represent server-generated non-UUID keys in
Resource and relationship objects could also contain
|
The meta section certainly satisfies my current requirements (and keeping a timestamp for lastFetched is also a good idea). I wonder how querying against this structure would work (thinking of the MemorySource) and particularly fetchAll. As a structure for synchronising it looks great though. The only thing I'm wondering about is how sources would know when to ignore meta information. Potentially there could be information that makes sense to synchronise remotely whereas some would only make sense locally (e.g. lastFetched). Perhaps the sources will just need to have knowledge of meta information where it's relevant. I see the relationship type isn't indicated anyway, are you thinking we'd refer to the schema for this? |
Taking lastFetched as an example: Given an app has JSON API, localstorage and memory sources when the app is loaded and the memory source synchronises with localstorage, would the lastFetched timestamp reflect the value stored in localstorage or the current timestamp? |
Good question. I've been thinking about introducing indices for caches, which would exist as a sibling of |
I was just throwing an example in here - thinking it would represent fetching from a remote server. We could segment |
Indices would certainly be more flexible. Indices for mappings between keys could go in localstorage, indices on attributes for instance though would need to be refreshed on load (perhaps you weren't considering indices on anything except key and type mappings though). Feels like there's 3 different categories for meta data:
The first two make sense within the normalized form but not the third. |
I am backtracking on my proposal to identify resources only by UUIDs. Although it would work well in theory to simply mandate unique IDs, in practice it could lead to some very thorny problems. For instance, a backend that uses UUIDs is probably only guaranteeing uniqueness across a single table. Shortcuts may have been taken to generate some of those IDs. If the IDs are only merged into a single namespace at the client, those shortcuts could finally come to light, leading to problems in production that are a nightmare to debug. I'm back to believing that the best course is to only require |
The following normalized structure could be used to accommodate the
This again groups data by It also introduces a condensed @opsb regarding per-source meta data: I'm leaning toward separating this into a parallel data structure that could be maintained only in the appropriate source. Per-source meta data won't be represented in the normalized form. |
Seems like a nice solution.
Yeah, that's where I was getting to. |
WIP in the rethink branch. |
Having implemented the |
We will not be moving to a global (i.e. across all types) |
I'd like to update Orbit's normalized form to follow the document structure defined by JSON API.
Instead of flattening attributes, relationships, and keys at a single level, I'd like to structure them as follows:
Some details:
type
- the record type (i.e. model name)id
- the value of the primary key (note that this is Orbit's primary key)attributes
- attributes, previously stored at the record rootrelationships
- relationships, previously stored as__rel
Advantages
Moving to this normalized form should provide the following benefits:
TBD
Secondary keys (e.g. remote IDs) could be stored either:
keys
object for each resource, orIf stored in a map, the map's contents will need to be extractable so it can be kept in browser storage.
I'm leaning towards using a separate
keys
object for simplicity and consistency. Obviously, this element would only be needed for schema that use secondary keys.The text was updated successfully, but these errors were encountered: