Releases: reactive/data-client
@data-client/endpoint@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3461
939a4b0Thanks @ntucker! - Add delegate.INVALID to queryKeyThis 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
939a4b0Thanks @ntucker! - Add delegate.invalidate() to normalizationBefore
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
1f491a9Thanks @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
4dde1d6Thanks @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
939a4b0Thanks @ntucker! - RemoveINVALIDsymbol exportSchemas can use delegate.invalidate() in normalize() or return delegate.INVALID in queryKey().
-
#3449
1f491a9Thanks @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
1f491a9Thanks @ntucker! - Fix: ensure string id in Entity set when process returns undefined (meaning INVALID) -
#3560
ba31c9bThanks @ntucker! - Add Collection.removectrl.set(MyResource.getList.schema.remove, { id });
const removeItem = MyResource.delete.extend({ schema: MyResource.getList.schema.remove, });
-
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional 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
bab907cThanks @Tomaszal! - fix: export types needed for EntityMixin -
#3501
5699005Thanks @ntucker! - Fix: schema.All() polymorphic handling of Invalidated entitiesIn case an Entity is invalidated, schema.All will continue to properly
filter it out of its list. -
#3558
fcb7d7dThanks @ntucker! - Unions can query() without type discriminatorBefore
// @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
@data-client/core@0.15.0-beta-20251006024044-92bd01c4976f2921993b8c9f1e4dbb87af87ba7b
Minor Changes
-
#3449
1f491a9Thanks @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
4939456Thanks @ntucker! - state.entityMeta -> state.entitiesMeta -
#3394
d44d36aThanks @ntucker! - Change NetworkManager bookkeeping data structure for inflight fetchesBREAKING CHANGE: NetworkManager.fetched, NetworkManager.rejectors, NetworkManager.resolvers, NetworkManager.fetchedAt
-> NetworkManager.fetchingBefore
if (action.key in this.fetched)
After
if (this.fetching.has(action.key))
-
#3449
1f491a9Thanks @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
1f491a9Thanks @ntucker! - Fix controller.get and controller.getQueryMeta 'state' argument types -
#3558
fcb7d7dThanks @ntucker! - Normalize delegate.invalidate() first argument only haskeyparam.indexesoptional 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; }
-
#3468
4dde1d6Thanks @ntucker! - Improve performance of get/denormalize for small responses- 10-20% performance improvement due to removing immutablejs check for every call
-
Updated dependencies [
4dde1d6,246cde6,4dde1d6,939a4b0,939a4b0,fcb7d7d,66e1906,1f491a9,4dde1d6,4939456,25b153a,4dde1d6,1f491a9]:
@data-client/[email protected]
@data-client/[email protected]
Patch Changes
-
#3417
a6af54cThanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta -
#3407
d84899dThanks @ntucker! - Support dynamic invalidation/deletesReturning
undefinedfrom 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]
@data-client/[email protected]
@data-client/[email protected]
Patch Changes
-
#3417
a6af54cThanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta -
#3407
d84899dThanks @ntucker! - Support dynamic invalidation/deletesReturning
undefinedfrom 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]
@data-client/[email protected]
Patch Changes
-
#3417
a6af54cThanks @ntucker! - Update getOptimisticResponse snapshot types to include getResponseMeta -
#3407
d84899dThanks @ntucker! - Support dynamic invalidation/deletesReturning
undefinedfrom 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]
Patch Changes
-
#3390
32cccdbThanks @ntucker! - Improve performance by using Map() instead of Object for unbounded keys -
#3390
32cccdbThanks @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]
@data-client/[email protected]
Patch Changes
-
d41f658Thanks @ntucker! - Improve performance by using Map() instead of Object for unbounded keys #3390 -
Updated dependencies [
d41f658]:- @data-client/[email protected]