Skip to content

Releases: reactive/data-client

@data-client/endpoint@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b

06 Oct 02:47
742a7c1

Choose a tag to compare

Minor Changes

  • #3461 939a4b0 Thanks @ntucker! - Add delegate.INVALID to queryKey

    This is used in schema.All.queryKey().

    Before

    queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any {
      if (!found) return INVALID;
    }

    After

    queryKey(args: any, unvisit: any, delegate: IQueryDelegate): any {
      if (!found) return delegate.INVALID;
    }
  • #3461 939a4b0 Thanks @ntucker! - Add delegate.invalidate() to normalization

    Before

    normalize(
      input: any,
      parent: any,
      key: string | undefined,
      args: any[],
      visit: (...args: any) => any,
      delegate: INormalizeDelegate,
    ): string {
      delegate.setEntity(this as any, pk, INVALID);
    }

    After

    normalize(
      input: any,
      parent: any,
      key: string | undefined,
      args: any[],
      visit: (...args: any) => any,
      delegate: INormalizeDelegate,
    ): string {
      delegate.invalidate(this as any, pk);
    }
  • #3449 1f491a9 Thanks @ntucker! - BREAKING CHANGE: schema.normalize(...args, addEntity, getEntity, checkLoop) -> schema.normalize(...args, delegate)

    We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument.

    /** Helpers during schema.normalize() */
    export interface INormalizeDelegate {
      /** Action meta-data for this normalize call */
      readonly meta: { fetchedAt: number; date: number; expiresAt: number };
      /** Gets any previously normalized entity from store */
      getEntity: GetEntity;
      /** Updates an entity using merge lifecycles when it has previously been set */
      mergeEntity(
        schema: Mergeable & { indexes?: any },
        pk: string,
        incomingEntity: any,
      ): void;
      /** Sets an entity overwriting any previously set values */
      setEntity(
        schema: { key: string; indexes?: any },
        pk: string,
        entity: any,
        meta?: { fetchedAt: number; date: number; expiresAt: number },
      ): void;
      /** Returns true when we're in a cycle, so we should not continue recursing */
      checkLoop(key: string, pk: string, input: object): boolean;
    }

    Before

    addEntity(this, processedEntity, id);

    After

    delegate.mergeEntity(this, id, processedEntity);
  • #3468 4dde1d6 Thanks @ntucker! - delegate.getEntity(key) -> delegate.getEntities(this.key)

    Return value is a restricted interface with keys() and entries() iterator methods.
    This applies to both schema.queryKey and schema.normalize method delegates.

    const entities = delegate.getEntities(key);
    
    // foreach on keys
    for (const key of entities.keys()) {
    }
    // Object.keys() (convert to array)
    return [...entities.keys()];
    // foreach on full entry
    for (const [key, entity] of entities.entries()) {
    }

    Before

    const entities = delegate.getEntity(this.key);
    if (entities)
      Object.keys(entities).forEach(collectionPk => {
        if (!filterCollections(JSON.parse(collectionPk))) return;
        delegate.mergeEntity(this, collectionPk, normalizedValue);
      });

    After

    const entities = delegate.getEntities(this.key);
    if (entities)
      for (const collectionKey of entities.keys()) {
        if (!filterCollections(JSON.parse(collectionKey))) continue;
        delegate.mergeEntity(this, collectionKey, normalizedValue);
      }
  • #3461 939a4b0 Thanks @ntucker! - Remove INVALID symbol export

    Schemas can use delegate.invalidate() in normalize() or return delegate.INVALID in queryKey().

  • #3449 1f491a9 Thanks @ntucker! - BREAKING CHANGE: schema.queryKey(args, queryKey, getEntity, getIndex) -> schema.queryKey(args, unvisit, delegate)
    BREAKING CHANGE: delegate.getIndex() returns the index directly, rather than object.

    We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument.

    Our recursive call is renamed from queryKey to unvisit, and does not require the last two arguments.

    /** Accessors to the currently processing state while building query */
    export interface IQueryDelegate {
      getEntity: GetEntity;
      getIndex: GetIndex;
    }

    Before

    queryKey(args, queryKey, getEntity, getIndex) {
      getIndex(schema.key, indexName, value)[value];
      getEntity(this.key, id);
      return queryKey(this.schema, args, getEntity, getIndex);
    }

    After

    queryKey(args, unvisit, delegate) {
      delegate.getIndex(schema.key, indexName, value);
      delegate.getEntity(this.key, id);
      return unvisit(this.schema, args);
    }

Patch Changes

  • #3449 1f491a9 Thanks @ntucker! - Fix: ensure string id in Entity set when process returns undefined (meaning INVALID)

  • #3560 ba31c9b Thanks @ntucker! - Add Collection.remove

    ctrl.set(MyResource.getList.schema.remove, { id });
    const removeItem = MyResource.delete.extend({
      schema: MyResource.getList.schema.remove,
    });
  • #3558 fcb7d7d Thanks @ntucker! - Normalize delegate.invalidate() first argument only has key param.

    indexes optional param no longer provided as it was never used.

    normalize(
      input: any,
      parent: any,
      key: string | undefined,
      args: any[],
      visit: (...args: any) => any,
      delegate: INormalizeDelegate,
    ): string {
      delegate.invalidate({ key: this._entity.key }, pk);
      return pk;
    }
  • #3480 bab907c Thanks @Tomaszal! - fix: export types needed for EntityMixin

  • #3501 5699005 Thanks @ntucker! - Fix: schema.All() polymorphic handling of Invalidated entities

    In case an Entity is invalidated, schema.All will continue to properly
    filter it out of its list.

  • #3558 fcb7d7d Thanks @ntucker! - Unions can query() without type discriminator

    Before

    // @ts-expect-error
    const event = useQuery(EventUnion, { id });
    // event is undefined
    const newsEvent = useQuery(EventUnion, { id, type: 'news' });
    // newsEvent is found

    After

    const event = useQuery(EventUnion, { id });
    // event is found
    const newsEvent = useQuery(EventUnion, { id, type: 'news' });
    // newsEvent is found
  • 35552c7 Thanks @ntucker! - Include GPT link badge in readme

@data-client/core@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b

06 Oct 02:47
742a7c1

Choose a tag to compare

Minor Changes

  • #3449 1f491a9 Thanks @ntucker! - BREAKING CHANGE: schema.normalize(...args, addEntity, getEntity, checkLoop) -> schema.normalize(...args, delegate)

    We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument.

    /** Helpers during schema.normalize() */
    export interface INormalizeDelegate {
      /** Action meta-data for this normalize call */
      readonly meta: { fetchedAt: number; date: number; expiresAt: number };
      /** Gets any previously normalized entity from store */
      getEntity: GetEntity;
      /** Updates an entity using merge lifecycles when it has previously been set */
      mergeEntity(
        schema: Mergeable & { indexes?: any },
        pk: string,
        incomingEntity: any,
      ): void;
      /** Sets an entity overwriting any previously set values */
      setEntity(
        schema: { key: string; indexes?: any },
        pk: string,
        entity: any,
        meta?: { fetchedAt: number; date: number; expiresAt: number },
      ): void;
      /** Returns true when we're in a cycle, so we should not continue recursing */
      checkLoop(key: string, pk: string, input: object): boolean;
    }

    Before

    addEntity(this, processedEntity, id);

    After

    delegate.mergeEntity(this, id, processedEntity);
  • #3451 4939456 Thanks @ntucker! - state.entityMeta -> state.entitiesMeta

  • #3394 d44d36a Thanks @ntucker! - Change NetworkManager bookkeeping data structure for inflight fetches

    BREAKING CHANGE: NetworkManager.fetched, NetworkManager.rejectors, NetworkManager.resolvers, NetworkManager.fetchedAt
    -> NetworkManager.fetching

    Before

    if (action.key in this.fetched)

    After

    if (this.fetching.has(action.key))
  • #3449 1f491a9 Thanks @ntucker! - BREAKING CHANGE: schema.queryKey(args, queryKey, getEntity, getIndex) -> schema.queryKey(args, unvisit, delegate)
    BREAKING CHANGE: delegate.getIndex() returns the index directly, rather than object.

    We consolidate all 'callback' functions during recursion calls into a single 'delegate' argument.

    Our recursive call is renamed from queryKey to unvisit, and does not require the last two arguments.

    /** Accessors to the currently processing state while building query */
    export interface IQueryDelegate {
      getEntity: GetEntity;
      getIndex: GetIndex;
    }

    Before

    queryKey(args, queryKey, getEntity, getIndex) {
      getIndex(schema.key, indexName, value)[value];
      getEntity(this.key, id);
      return queryKey(this.schema, args, getEntity, getIndex);
    }

    After

    queryKey(args, unvisit, delegate) {
      delegate.getIndex(schema.key, indexName, value);
      delegate.getEntity(this.key, id);
      return unvisit(this.schema, args);
    }

Patch Changes

@data-client/[email protected]

01 May 05:33
a109e56

Choose a tag to compare

Patch Changes

@data-client/[email protected]

12 Mar 17:52
69ae187

Choose a tag to compare

Patch Changes

  • #3417 a6af54c Thanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta

  • #3407 d84899d Thanks @ntucker! - Support dynamic invalidation/deletes

    Returning undefined from Entity.process
    will cause the Entity to be invalidated.
    This this allows us to invalidate dynamically; based on the particular response data.

    class PriceLevel extends Entity {
      price = 0;
      amount = 0;
    
      pk() {
        return this.price;
      }
    
      static process(
        input: [number, number],
        parent: any,
        key: string | undefined,
      ): any {
        const [price, amount] = input;
        if (amount === 0) return undefined;
        return { price, amount };
      }
    }
  • Updated dependencies [a6af54c, d84899d]:

@data-client/[email protected]

12 Mar 17:52
69ae187

Choose a tag to compare

Patch Changes

  • #3398 d716159 Thanks @ntucker! - Use controller.getResponseMeta() in hooks

    No behavior change, just anticipating API updates to controller

  • d6eab29 Thanks @ntucker! - docs: Add links to platforms

@data-client/[email protected]

12 Mar 17:52
69ae187

Choose a tag to compare

Patch Changes

  • #3417 a6af54c Thanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta

  • #3407 d84899d Thanks @ntucker! - Support dynamic invalidation/deletes

    Returning undefined from Entity.process
    will cause the Entity to be invalidated.
    This this allows us to invalidate dynamically; based on the particular response data.

    class PriceLevel extends Entity {
      price = 0;
      amount = 0;
    
      pk() {
        return this.price;
      }
    
      static process(
        input: [number, number],
        parent: any,
        key: string | undefined,
      ): any {
        const [price, amount] = input;
        if (amount === 0) return undefined;
        return { price, amount };
      }
    }
  • Updated dependencies [a6af54c, d84899d]:

@data-client/[email protected]

12 Mar 17:52
69ae187

Choose a tag to compare

Patch Changes

  • #3417 a6af54c Thanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta

  • #3407 d84899d Thanks @ntucker! - Support dynamic invalidation/deletes

    Returning undefined from Entity.process
    will cause the Entity to be invalidated.
    This this allows us to invalidate dynamically; based on the particular response data.

    class PriceLevel extends Entity {
      price = 0;
      amount = 0;
    
      pk() {
        return this.price;
      }
    
      static process(
        input: [number, number],
        parent: any,
        key: string | undefined,
      ): any {
        const [price, amount] = input;
        if (amount === 0) return undefined;
        return { price, amount };
      }
    }

@data-client/[email protected]

01 Mar 13:57
56d8beb

Choose a tag to compare

Patch Changes

  • #3390 32cccdb Thanks @ntucker! - Improve performance by using Map() instead of Object for unbounded keys

  • #3390 32cccdb Thanks @ntucker! - Interceptors that have args specified will still work, and warn about args.

    Example:

    {
      endpoint: TodoResource.getList.push,
      args: [{ userId: '5' }, {}],
      response({ userId }, body) {
        return { id: Math.random(), userId, ...ensurePojo(body) };
      },
    }

    This is clearly an interceptor, but args were accidentally specified. Before
    this would make it not register, and TypeScript couldn't detect the issue.

    Now this is treated as an interceptor (args ignored); and there is a console warning

@data-client/[email protected]

01 Mar 13:57
56d8beb

Choose a tag to compare

Patch Changes

  • #3390 32cccdb Thanks @ntucker! - Improve performance by using Map() instead of Object for unbounded keys

@data-client/[email protected]

01 Mar 14:32
39f9f7b

Choose a tag to compare

Patch Changes