Skip to content

Commit

Permalink
docs: Various improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Sep 23, 2023
1 parent 9d2d722 commit 484ad35
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 166 deletions.
3 changes: 3 additions & 0 deletions docs/core/api/Controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ title: Controller
import LanguageTabs from '@site/src/components/LanguageTabs';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import StackBlitz from '@site/src/components/StackBlitz';

```ts
class Controller {
Expand Down Expand Up @@ -175,6 +176,8 @@ An [example](https://stackblitz.com/github/reactive/data-client/tree/master/exam
},
```

<StackBlitz app="github-app" file="src/routing/routes.tsx" view="editor" />

## expireAll(\{ testKey }) {#expireAll}

Sets all responses' [expiry status](../concepts/expiry-policy.md) matching `testKey` to [Stale](../concepts/expiry-policy.md#stale).
Expand Down
148 changes: 1 addition & 147 deletions docs/rest/api/schema.Entity.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,153 +92,7 @@ Specifies the [Entity.schema](./Entity.md#schema)

## Methods

`schema.Entity` has the same methods as [Entity](./Entity.md) with an improved `mergeWithStore()` lifecycle.

This method uses [shouldReorder()](#shouldReorder) to handle race conditions rather than [useIncoming()](#useIncoming),
which is better able to handle [partial field entities](../guides/partial-entities.md).

Eventually `Entity` will also be converted to use this default implementation. You can prepare for this by copying
the [mergeWithStore](#mergeWithStore) default implementation below.

### static mergeWithStore(existingMeta, incomingMeta, existing, incoming): mergedValue {#mergeWithStore}

```typescript
static mergeWithStore(
existingMeta: {
date: number;
fetchedAt: number;
},
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
) {
const useIncoming = this.useIncoming(
existingMeta,
incomingMeta,
existing,
incoming,
);

if (useIncoming) {
// distinct types are not mergeable (like delete symbol), so just replace
if (typeof incoming !== typeof existing) {
return incoming;
} else {
return this.shouldReorder(
existingMeta,
incomingMeta,
existing,
incoming,
)
? this.merge(incoming, existing)
: this.merge(existing, incoming);
}
} else {
return existing;
}
}
```

`mergeWithStore()` is called during normalization when a processed entity is already found in the store.

This calls [useIncoming()](#useIncoming), [shouldReorder()](#shouldOrder) and potentially [merge()](#merge)

### static useIncoming(existingMeta, incomingMeta, existing, incoming): boolean {#useIncoming}

```typescript
static useIncoming(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
) {
return true;
}
```

#### Preventing updates

useIncoming can also be used to short-circuit an entity update.

```typescript
import deepEqual from 'deep-equal';

class ArticleEntity extends schema.Entity(
class {
id = '';
title = '';
content = '';
published = false;
},
) {
static useIncoming(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
) {
return !deepEqual(incoming, existing);
}
}
```

### static shouldReorder(existingMeta, incomingMeta, existing, incoming): boolean {#shouldReorder}

```typescript
static shouldReorder(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: any,
incoming: any,
) {
return incomingMeta.fetchedAt < existingMeta.fetchedAt;
}
```

`true` return value will reorder incoming vs in-store entity argument order in merge. With
the default merge, this will cause the fields of existing entities to override those of incoming,
rather than the other way around.

#### Example

<TypeScriptEditor>

```typescript
class LatestPriceEntity extends schema.Entity(
class {
id = '';
updatedAt = 0;
price = '0.0';
symbol = '';
},
) {
static shouldReorder(
existingMeta: { date: number; fetchedAt: number },
incomingMeta: { date: number; fetchedAt: number },
existing: { updatedAt: number },
incoming: { updatedAt: number },
) {
return incoming.updatedAt < existing.updatedAt;
}
}
```

</TypeScriptEditor>

### static merge(existing, incoming): mergedValue {#merge}

```typescript
static merge(existing: any, incoming: any) {
return {
...existing,
...incoming,
};
}
```

Merge is used to handle cases when an incoming entity is already found. This is called directly
when the same entity is found in one response. By default it is also called when [mergeWithStore()](#mergeWithStore)
determines the incoming entity should be merged with an entity already persisted in the Reactive Data Client store.
`schema.Entity` mixin has the same [methods as the Entity](./Entity.md#methods) class.

## const vs class

Expand Down
9 changes: 7 additions & 2 deletions docs/rest/guides/computed-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ title: Computed Properties
import { RestEndpoint } from '@data-client/rest';
import HooksPlayground from '@site/src/components/HooksPlayground';

## Singular computations

[Entity](../api/Entity.md) classes are just normal classes, so any common derived data can just be added as
getters to the class itself.

Expand Down Expand Up @@ -47,17 +49,19 @@ class User extends Entity {

:::tip

If you simply want to [deserialize a field](./network-transform.md#deserializing-fields) to a more useful form like [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) or [BigNumber](https://github.com/MikeMcl/bignumber.js), you can use
If you simply want to [deserialize a field](./network-transform.md#deserializing-fields) to a more useful form like [Temporal.Instant](https://tc39.es/proposal-temporal/docs/instant.html) or [BigNumber](https://github.com/MikeMcl/bignumber.js), you can use
the declarative [static schema](./network-transform.md#deserializing-fields).

```typescript
import { Entity } from '@data-client/rest';
import BigNumber from 'bignumber.js';

class User extends Entity {
id = '';
firstName = '';
lastName = '';
createdAt = Temporal.Instant.fromEpochSeconds(0);
lifetimeBlinkCount = BigNumber(0);

pk() {
return this.id;
Expand All @@ -67,6 +71,7 @@ class User extends Entity {
// highlight-start
static schema = {
createdAt: Temporal.Instant.from,
lifetimeBlinkCount: BigNumber,
};
// highlight-end
}
Expand All @@ -77,7 +82,7 @@ class User extends Entity {
## Global computations

[Query](../api/Query.md) can be used for computations of derived data from more than
one entity.
one entity. We generally call these aggregates.

<HooksPlayground row fixtures={[
{
Expand Down
9 changes: 9 additions & 0 deletions examples/github-app/src/routing/lazyPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { lazy } from '@anansi/router';

export const lazyPage = (pageName: string) =>
lazy(
() =>
import(
/* webpackChunkName: '[request]', webpackPrefetch: true */ `pages/${pageName}`
),
);
26 changes: 9 additions & 17 deletions examples/github-app/src/routing/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
import { lazy, Route } from '@anansi/router';
import { getImage } from '@data-client/img';
import { Controller } from '@data-client/react';
import CommentResource from 'resources/Comment';
import { EventResource } from 'resources/Event';
import IssueResource from 'resources/Issue';
import PullResource from 'resources/Pull';
import ReactionResource from 'resources/Reaction';
import RepositoryResource from 'resources/Repository';
import UserResource from 'resources/User';

const lazyPage = (pageName: string) =>
lazy(
() =>
import(
/* webpackChunkName: '[request]', webpackPrefetch: true */ `pages/${pageName}`
),
);

export const namedPaths = {
Home: '/',
PullList: '/:owner/:repo/pulls',
IssueList: '/:owner/:repo/issues',
IssueDetail: '/:owner/:repo/issue/:number',
ProfileDetail: '/users/:login',
};
import { lazyPage } from './lazyPage';

export const routes = [
{
Expand Down Expand Up @@ -106,3 +90,11 @@ export const routes = [
},
},
];

export const namedPaths = {
Home: '/',
PullList: '/:owner/:repo/pulls',
IssueList: '/:owner/:repo/issues',
IssueDetail: '/:owner/:repo/issue/:number',
ProfileDetail: '/users/:login',
};

0 comments on commit 484ad35

Please sign in to comment.