Search code examples
angulartypescriptngrxngrx-entityangular-ngrx-data

Using @ngrx/data, how can you form JSON patch documents from updates to entities on a custom data service?


My use case of @ngrx/data requires that I build custom entity data services by extending DefaultDataService<T>. The API I am working with accepts JSON patch documents for updates. EntityCollectionDataService<T> defines the following function for updates:

update(update: Update<T>): Observable<T>;

Where Update<T> has the member changes which is of type Partial<T>. The issue I am facing here is that I am not able to form a JSON patch document with only a slice of the changed fields of the entity. I would need both the unchanged and changed state of the entity.

The only solution I can see here would be to access the EntityChangeTracker through the EntityCollectionService for my entity, I'm just a bit confused about how to use the change tracker, as it's just an observable stream of changes through the EntityCollectionService's changeState$ field.

Is there a simpler way I'm not seeing here? I also thought to just access the store and pull the current state of the entity, but I'd prefer to use optimistic concurrency, so the store has already changed by the time the DefaultDataService I am writing is called through a side effect for the update.


Solution

  • It turns out that you can form patch documents by observing changes that occur in the EntityChangeTracker as I expected. Simply subscribe to the changeState$, check to see if the state change was an update, then proceed to compare the original content versus the modified content.

    I do this by returning an Observable in my data service on the update method, and checking to see if the updated content has a key in the changeState map.

    update = (entity: Update<TEntity>): Observable<TEntity> => {
        /**
         * Since we are needing to perform extra logic to
         * retrieve an original copy of the modified entity,
         * we are returning a new Observable.
         */
        return new Observable<TEntity>((subscriber) => {
          // Pull the entity change state for this updated model
          // from the entity change tracker.
          const entityChangeState: ChangeState<TEntity> | undefined = this.changeStateMap[entity.id];
    
         // Here, check the entityChangeState and compare it with the original record 
    
    ...