v0.16.0-beta.11
Pre-release🚨 If you are an author of any sources, please focus on the breaking changes in this release! 🚨
While testing the hinting feature and its interactions with different source interfaces, @tchak uncovered some scenarios in which hints could fail to return expected results (see #612). This led to a quest to understand those problems and fix them across source interfaces. Unfortunately, in order to guarantee predictable and consistent behavior, we needed to move some responsibilities to source implementations that were previously handled in Orbit's private implementations of those interfaces.
Thus, if you're writing sources, please ensure that you do the following in any of your internal implementation methods that work with transforms (e.g. _update
, _sync
, etc.):
-
Check the
transformLog
for the requested transform to see if work actually needs to be done before doing it. -
Invoke
transformed
for any transforms that are applied.
By moving these responsibilities to source implementations, we allow more flexibility in implementations. For instance, _update
can ignore re-applying transforms that may have been sync'd via beforeUpdate
listeners, while still returning results that are specified via the hints
argument.
In order to update the @orbit/memory
source to both support hints and respond to the above requirements, the following changes were needed:
/////////////////////////////////////////////////////////////////////////////
// Syncable interface implementation
/////////////////////////////////////////////////////////////////////////////
async _sync(transform: Transform): Promise<void> {
- this._applyTransform(transform);
+ if (!this.transformLog.contains(transform.id)) {
+ this._applyTransform(transform); // <- internal implementation that applies the transform to the source's cache
+ await this.transformed([transform]);
+ }
}
/////////////////////////////////////////////////////////////////////////////
// Updatable interface implementation
/////////////////////////////////////////////////////////////////////////////
async _update(transform: Transform, hints?: any): Promise<any> {
- return this._applyTransform(transform);
+ let results: PatchResultData[];
+
+ if (!this.transformLog.contains(transform.id)) {
+ results = this._applyTransform(transform); // <- internal implementation that applies the transform to the source's cache
+ await this.transformed([transform]);
+ }
+
+ if (hints && hints.data) {
+ if (transform.operations.length > 1 && Array.isArray(hints.data)) {
+ return hints.data.map((idOrIds: RecordIdentity | RecordIdentity[]) =>
+ this._retrieveFromCache(idOrIds)
+ );
+ } else {
+ return this._retrieveFromCache(hints.data);
+ }
+ } else if (results) {
+ if (transform.operations.length === 1 && Array.isArray(results)) {
+ return results[0];
+ } else {
+ return results;
+ }
+ }
}
/////////////////////////////////////////////////////////////////////////////
// Queryable interface implementation
/////////////////////////////////////////////////////////////////////////////
async _query(query: Query, hints?: any): Promise<any> {
- return this._cache.query(query);
+ if (hints && hints.data) {
+ return this._retrieveFromCache(hints.data);
+ } else {
+ return this._cache.query(query);
+ }
}
Please review your custom sources to make any necessary changes. If your methods don't support hints, the diffs should rather small, like in the _sync
method above. If you want to support hints
, you'll need to provide alternate code paths for when hints are provided and not, like in the _update
and _query
methods above.
We're planning to include a guide to writing your own sources with the v0.16 release to clarify all these responsibilities.
Changelog
💥 Breaking Change
@orbit/data
,@orbit/indexeddb
,@orbit/jsonapi
,@orbit/local-storage
,@orbit/memory
🚀 Enhancement
@orbit/coordinator
,@orbit/data
,@orbit/indexeddb
,@orbit/jsonapi
,@orbit/local-storage
,@orbit/memory
🏠 Internal
@orbit/jsonapi
,@orbit/memory
@orbit/data