Skip to content

Commit

Permalink
fix: Properly vary cache when nested pk is a number (#2961)
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker authored Feb 22, 2024
1 parent a62349d commit 446f0b9
Show file tree
Hide file tree
Showing 26 changed files with 307 additions and 72 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-mayflies-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@data-client/normalizr": patch
---

fix: Missing nested entities should appear once they are present (When nesting pk was a number type)
48 changes: 48 additions & 0 deletions .changeset/serious-dogs-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
"@data-client/normalizr": patch
'@data-client/endpoint': patch
---

Always normalize pk to string type

Warning: This will affect contents of the store state (some numbers will appear as strings)

Before:

```json
{
"Article": {
"123": {
"author": 8472,
"id": 123,
"title": "A Great Article",
},
},
"User": {
"8472": {
"id": 8472,
"name": "Paul",
},
},
}
```

After:

```json
{
"Article": {
"123": {
"author": "8472",
"id": 123,
"title": "A Great Article",
},
},
"User": {
"8472": {
"id": 8472,
"name": "Paul",
},
},
}
```
2 changes: 1 addition & 1 deletion .changeset/tough-panthers-compare.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"@data-client/normalizr": patch
---

fix: Missing nested entities should appear once they are present \
fix: Missing nested entities should appear once they are present

29 changes: 29 additions & 0 deletions .changeset/two-foxes-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
'@data-client/endpoint': patch
'@data-client/graphql': patch
'@data-client/rest': patch
---

Allow pk() to return numbers

Before:

```ts
class MyEntity extends Entity {
id = 0;
pk() {
return `${this.id}`;
}
}
```

After:

```ts
class MyEntity extends Entity {
id = 0;
pk() {
return this.id;
}
}
```
1 change: 1 addition & 0 deletions docs/rest/api/Query.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ function TodosPage() {
useFetch(TodoResource.getList);
const todos = useCache(todosWithUser, { userId: 1 });
if (!todos) return <div>No Todos in cache yet</div>;
if (!todos.length) return <div>No Todos match user</div>;
return (
<div>
{todos.map(todo => (
Expand Down
2 changes: 1 addition & 1 deletion docs/rest/api/schema.Entity.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class UserEntity extends schema.Entity(User, {

</TypeScriptEditor>

### pk: string | (value, parent?, key?, args?) => string | undefined = 'id' {#pk}
### pk: string | (value, parent?, key?, args?) => string | number | undefined = 'id' {#pk}

Specifies the [Entity.pk](./Entity.md#pk)

Expand Down
8 changes: 4 additions & 4 deletions packages/endpoint/src-4.0-types/schemas/Entity.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ declare const Entity_base: import('./EntitySchema.js').IEntityClass<
parent?: any,
key?: string | undefined,
args?: readonly any[] | undefined,
): string | undefined;
): string | number | undefined;
}
> &
(new (...args: any[]) => {
pk(
parent?: any,
key?: string | undefined,
args?: readonly any[] | undefined,
): string | undefined;
): string | number | undefined;
});
/**
* Represents data that should be deduped by specifying a primary key.
Expand All @@ -33,7 +33,7 @@ export default abstract class Entity extends Entity_base {
parent?: any,
key?: string,
args?: readonly any[],
): string | undefined;
): string | number | undefined;

/** Control how automatic schema validation is handled
*
Expand Down Expand Up @@ -68,7 +68,7 @@ export default abstract class Entity extends Entity_base {
parent?: any,
key?: string,
args?: any[],
) => string | undefined;
) => string | number | undefined;

/** Do any transformations when first receiving input
*
Expand Down
26 changes: 21 additions & 5 deletions packages/endpoint/src-4.0-types/schemas/EntitySchema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@ export type IDClass = new (...args: any[]) => {
id: string | number | undefined;
};
export type PKClass = new (...args: any[]) => {
pk(parent?: any, key?: string, args?: readonly any[]): string | undefined;
pk(
parent?: any,
key?: string,
args?: readonly any[],
): string | number | undefined;
};
type ValidSchemas<TInstance> = {
[k in keyof TInstance]?: Schema;
};
export type EntityOptions<TInstance extends {}> = {
readonly schema?: ValidSchemas<TInstance>;
readonly pk?:
| ((value: TInstance, parent?: any, key?: string) => string | undefined)
| ((
value: TInstance,
parent?: any,
key?: string,
) => string | number | undefined)
| keyof TInstance;
readonly key?: string;
} & {
Expand All @@ -33,7 +41,11 @@ export type EntityOptions<TInstance extends {}> = {
export interface RequiredPKOptions<TInstance extends {}>
extends EntityOptions<TInstance> {
readonly pk:
| ((value: TInstance, parent?: any, key?: string) => string | undefined)
| ((
value: TInstance,
parent?: any,
key?: string,
) => string | number | undefined)
| keyof TInstance;
}
export default function EntitySchema<TBase extends Constructor>(
Expand Down Expand Up @@ -84,7 +96,7 @@ export interface IEntityClass<TBase extends Constructor = any> {
parent?: any,
key?: string,
args?: any[],
): string | undefined;
): string | number | undefined;
/** Return true to merge incoming data; false keeps existing entity
*
* @see https://dataclient.io/docs/api/schema.Entity#useIncoming
Expand Down Expand Up @@ -235,6 +247,10 @@ export interface IEntityInstance {
* @param [key] When normalizing, the key where this entity was found
* @param [args] ...args sent to Endpoint
*/
pk(parent?: any, key?: string, args?: readonly any[]): string | undefined;
pk(
parent?: any,
key?: string,
args?: readonly any[],
): string | number | undefined;
}
export {};
7 changes: 6 additions & 1 deletion packages/endpoint/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ export interface SchemaClass<T = any, N = T | undefined>

export interface EntityInterface<T = any> extends SchemaSimple {
createIfValid(props: any): any;
pk(params: any, parent?: any, key?: string, args?: any[]): string | undefined;
pk(
params: any,
parent?: any,
key?: string,
args?: any[],
): string | number | undefined;
readonly key: string;
merge(existing: any, incoming: any): any;
mergeWithStore(
Expand Down
2 changes: 1 addition & 1 deletion packages/endpoint/src/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ export function Entity<TBase extends Constructor>(
Base: TBase,
opt?: EntityOptions<keyof InstanceType<TBase>>,
): (abstract new (...args: any[]) => {
pk(parent?: any, key?: string): string | undefined;
pk(parent?: any, key?: string): string | number | undefined;
}) &
IEntityClass<TBase> &
TBase;
Expand Down
10 changes: 7 additions & 3 deletions packages/endpoint/src/schemas/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { AbstractInstanceType } from '../normal.js';
import { Entity as EntitySchema } from '../schema.js';

const EmptyBase = class {} as any as abstract new (...args: any[]) => {
pk(parent?: any, key?: string, args?: readonly any[]): string | undefined;
pk(
parent?: any,
key?: string,
args?: readonly any[],
): string | number | undefined;
};

/**
Expand All @@ -24,7 +28,7 @@ export default abstract class Entity extends EntitySchema(EmptyBase) {
parent?: any,
key?: string,
args?: readonly any[],
): string | undefined;
): string | number | undefined;

/** Control how automatic schema validation is handled
*
Expand Down Expand Up @@ -61,7 +65,7 @@ export default abstract class Entity extends EntitySchema(EmptyBase) {
parent?: any,
key?: string,
args?: any[],
) => string | undefined;
) => string | number | undefined;

/** Do any transformations when first receiving input
*
Expand Down
32 changes: 25 additions & 7 deletions packages/endpoint/src/schemas/EntitySchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export type IDClass = abstract new (...args: any[]) => {
id: string | number | undefined;
};
export type PKClass = abstract new (...args: any[]) => {
pk(parent?: any, key?: string, args?: readonly any[]): string | undefined;
pk(
parent?: any,
key?: string,
args?: readonly any[],
): string | number | undefined;
};

// TODO: Figure out what Schema must be for each key
Expand All @@ -17,7 +21,11 @@ type ValidSchemas<TInstance> = { [k in keyof TInstance]?: Schema };
export type EntityOptions<TInstance extends {}> = {
readonly schema?: ValidSchemas<TInstance>;
readonly pk?:
| ((value: TInstance, parent?: any, key?: string) => string | undefined)
| ((
value: TInstance,
parent?: any,
key?: string,
) => string | number | undefined)
| keyof TInstance;
readonly key?: string;
} & {
Expand All @@ -37,7 +45,11 @@ export type EntityOptions<TInstance extends {}> = {
export interface RequiredPKOptions<TInstance extends {}>
extends EntityOptions<TInstance> {
readonly pk:
| ((value: TInstance, parent?: any, key?: string) => string | undefined)
| ((
value: TInstance,
parent?: any,
key?: string,
) => string | number | undefined)
| keyof TInstance;
}

Expand Down Expand Up @@ -77,7 +89,7 @@ export default function EntitySchema<TBase extends Constructor>(
parent?: any,
key?: string,
args?: readonly any[],
): string | undefined;
): string | number | undefined;

/** Returns the globally unique identifier for the static Entity */
declare static key: string;
Expand All @@ -101,7 +113,7 @@ export default function EntitySchema<TBase extends Constructor>(
parent?: any,
key?: string,
args?: readonly any[],
): string | undefined {
): string | number | undefined {
return this.prototype.pk.call(value, parent, key, args);
}

Expand Down Expand Up @@ -281,6 +293,8 @@ export default function EntitySchema<TBase extends Constructor>(
(error as any).status = 400;
throw error;
}
} else {
id = `${id}`;
}
const entityType = this.key;

Expand Down Expand Up @@ -523,7 +537,7 @@ export interface IEntityClass<TBase extends Constructor = any> {
parent?: any,
key?: string,
args?: any[],
): string | undefined;
): string | number | undefined;
/** Return true to merge incoming data; false keeps existing entity
*
* @see https://dataclient.io/docs/api/schema.Entity#useIncoming
Expand Down Expand Up @@ -672,7 +686,11 @@ export interface IEntityInstance {
* @param [key] When normalizing, the key where this entity was found
* @param [args] ...args sent to Endpoint
*/
pk(parent?: any, key?: string, args?: readonly any[]): string | undefined;
pk(
parent?: any,
key?: string,
args?: readonly any[],
): string | number | undefined;
}

function inferId(schema: any, args: readonly any[], indexes: NormalizedIndex) {
Expand Down
2 changes: 1 addition & 1 deletion packages/endpoint/src/schemas/Invalidate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default class Invalidate<
visitedEntities: Record<string, any>,
storeEntities: Record<string, any>,
args?: any[],
): string | undefined {
): string | number | undefined {
// TODO: what's store needs to be a differing type from fromJS
const processedEntity = this._entity.process(input, parent, key, args);
const id = this._entity.pk(processedEntity, parent, key, args);
Expand Down
2 changes: 1 addition & 1 deletion packages/endpoint/typescript-tests/relationships.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class IDEntity extends Entity {
* @param [parent] When normalizing, the object which included the entity
* @param [key] When normalizing, the key where this entity was found
*/
pk(parent?: any, key?: string): string | undefined {
pk(parent?: any, key?: string): string | number | undefined {
return `${this.id}`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ exports[`normalize can use fully custom entity classes 1`] = `
"Food": {
"1234": {
"children": [
4,
"4",
],
"name": "tacos",
"uuid": "1234",
Expand Down Expand Up @@ -425,6 +425,24 @@ exports[`normalize can use fully custom entity classes 1`] = `
}
`;

exports[`normalize handles number ids when nesting 1`] = `
{
"Article": {
"123": {
"author": "8472",
"id": 123,
"title": "A Great Article",
},
},
"User": {
"8472": {
"id": 8472,
"name": "Paul",
},
},
}
`;

exports[`normalize ignores null values 1`] = `
{
"entities": {},
Expand Down
Loading

0 comments on commit 446f0b9

Please sign in to comment.