Skip to content

v0.16.0-beta.11

Pre-release
Pre-release
Compare
Choose a tag to compare
@dgeb dgeb released this 18 Jul 14:34

🚨 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
    • #678 [BREAKING] Shift some responsibilities for transform-related interfaces to source implementations (@dgeb)

🚀 Enhancement

  • @orbit/coordinator, @orbit/data, @orbit/indexeddb, @orbit/jsonapi, @orbit/local-storage, @orbit/memory
    • #680 [DEPRECATION] Deprecate _transformed in favor of transformed (@dgeb)

🏠 Internal

  • @orbit/jsonapi, @orbit/memory
  • @orbit/data
    • #677 Convert source interface implementations to use async/await (@dgeb)

Committers: 2