Skip to content

Commit

Permalink
enhance: Remove IndexEndpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Feb 16, 2024
1 parent aa4a8d5 commit 082155f
Show file tree
Hide file tree
Showing 35 changed files with 1,136 additions and 700 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ ctrl.fetch(ArticleResource.get, { id });
### [Programmatic queries](https://dataclient.io/rest/api/Query)

```tsx
const queryTotalVotes = new Query(
const queryTotalVotes = new schema.Query(
new schema.All(Post),
(posts, { userId } = {}) => {
if (userId !== undefined)
Expand All @@ -144,8 +144,8 @@ const queryTotalVotes = new Query(
},
);

const totalVotes = useCache(queryTotalVotes);
const totalVotesForUser = useCache(queryTotalVotes, { userId });
const totalVotes = useQuery(queryTotalVotes);
const totalVotesForUser = useQuery(queryTotalVotes, { userId });
```

### [Powerful Middlewares](https://dataclient.io/docs/concepts/managers)
Expand Down
12 changes: 4 additions & 8 deletions __tests__/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
schema,
AbortOptimistic,
Endpoint,
Index,
createResource,
RestEndpoint,
Schema,
Expand Down Expand Up @@ -519,13 +518,10 @@ export const CoolerArticleDetail = new Endpoint(
export class IndexedUser extends User {
static readonly indexes = ['username'];
}
export const IndexedUserResource = {
...createResource({
path: 'http\\://test.com/user/:id',
schema: IndexedUser,
}),
getIndex: new Index(IndexedUser),
};
export const IndexedUserResource = createResource({
path: 'http\\://test.com/user/:id',
schema: IndexedUser,
});

class InvalidIfStaleEndpoint<
O extends RestGenerics = any,
Expand Down
7 changes: 4 additions & 3 deletions docs/core/api/useCache.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,11 @@ export const UserResource = createResource({
```

```tsx title="UsersPage" {17}
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { UserResource, User } from './UserResource';

const sortedUsers = new Query(
const sortedUsers = new schema.Query(
new schema.All(User),
(entries, { asc } = { asc: false }) => {
const sorted = [...entries].sort((a, b) =>
Expand All @@ -197,7 +198,7 @@ const sortedUsers = new Query(

function UsersPage() {
useFetch(UserResource.getList);
const users = useCache(sortedUsers, { asc: true });
const users = useQuery(sortedUsers, { asc: true });
if (!users) return <div>No users in cache yet</div>;
return (
<div>
Expand Down
7 changes: 4 additions & 3 deletions docs/core/shared/_VoteDemo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ export default function PostItem({ post }: { post: Post }) {
```

```tsx title="TotalVotes" collapsed
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery } from '@data-client/rest';
import { Post } from './PostResource';

const queryTotalVotes = new Query(
const queryTotalVotes = new schema.Query(
new schema.All(Post),
(posts, { userId } = {}) => {
if (userId !== undefined)
Expand All @@ -95,7 +96,7 @@ const queryTotalVotes = new Query(
);

export default function TotalVotes({ userId }: { userId: number }) {
const totalVotes = useCache(queryTotalVotes, { userId });
const totalVotes = useQuery(queryTotalVotes, { userId });
return (
<center>
<small>{totalVotes} votes total</small>
Expand Down
7 changes: 3 additions & 4 deletions docs/rest/api/Entity.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,9 @@ export const UserResource = createResource({
const user = useSuspense(UserResource.get, { username: 'bob' });
```

#### useCache()
#### useQuery()

With [useCache()](/docs/api/useCache), this enables accessing results retrieved inside other requests - even
With [useQuery()](/docs/api/useQuery), this enables accessing results retrieved inside other requests - even
if there is no endpoint it can be fetched from.

```typescript
Expand All @@ -574,7 +574,6 @@ class LatestPrice extends Entity {
price = '0.0';
static indexes = ['symbol' as const];
}
const latestPriceFromCache = new Index(LatestPrice);
```

```typescript
Expand All @@ -601,5 +600,5 @@ const assets = useSuspense(getAssets);
Nested below:

```tsx
const price = useCache(latestPriceFromCache, { symbol: 'BTC' });
const price = useQuery(LatestPrice, { symbol: 'BTC' });
```
31 changes: 0 additions & 31 deletions docs/rest/api/Index.md

This file was deleted.

104 changes: 17 additions & 87 deletions docs/rest/api/Query.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
title: Query
slug: Query
title: schema.Query
---

<head>
Expand All @@ -14,94 +13,22 @@ import HooksPlayground from '@site/src/components/HooksPlayground';
`Query` provides programmatic access to the Reactive Data Client cache while maintaining
the same high performance and referential equality guarantees expected of Reactive Data Client.

```typescript
class Query<S extends SchemaSimple, P extends any[] = []> {
constructor(
schema: S,
process?: (entries: Denormalize<S>, ...args: P) => Denormalize<S>,
);

schema: S;
key(...args: P): string;

process: (entries: Denormalize<S>, ...args: P) => Denormalize<S>;
}
```

`Query` implements the [EndpointInterface](./Endpoint.md) but without the fetch function, which
means it can only be passed to the [data binding hook useCache()](/docs/api/useCache)
`Query` can be rendered using [schema lookup hook useQuery()](/docs/api/useQuery())

## Query members

### schema

[Schema](./schema.md) used to retrieve/denormalize data from the Reactive Data Client cache.
Most cases will use [schema.All](./All.md), which retrieves all entities of a given type found
in the cache.
This accepts any Queryable schema.

### process(entries, ...args) {#process}

Takes the (denormalized) response as entries and arguments and returns the new
response for use with [useCache](/docs/api/useCache)

### key(...args) {#key}

Implements [Endpoint.key](./Endpoint.md#key) Used to determine recomputation of memoized values.
response for use with [useQuery](/docs/api/useQuery)

## Usage

### Simplest

<HooksPlayground groupId="schema" defaultOpen="y" fixtures={[
{
endpoint: new RestEndpoint({path: '/users'}),
args: [],
response: [
{ id: '123', name: 'Jim' },
{ id: '456', name: 'Jane' },
],
delay: 150,
},
]}>

```ts title="api/User.ts" collapsed
export class User extends Entity {
id = '';
name = '';
isAdmin = false;
pk() {
return this.id;
}
}
export const UserResource = createResource({
path: '/users/:id',
schema: User,
});
```

```tsx title="UsersPage.tsx" {4}
import { Query, schema } from '@data-client/rest';
import { UserResource, User } from './api/User';

const allUsers = new Query(new schema.All(User));

function UsersPage() {
useFetch(UserResource.getList);
const users = useCache(allUsers);
if (!users) return <div>No users in cache yet</div>;
return (
<div>
{users.map(user => (
<div key={user.pk()}>{user.name}</div>
))}
</div>
);
}
render(<UsersPage />);
```

</HooksPlayground>

### Sorting & Filtering

<HooksPlayground groupId="schema" defaultOpen="y" fixtures={[
Expand Down Expand Up @@ -133,14 +60,15 @@ export const UserResource = createResource({
```

```tsx title="UsersPage.tsx"
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { UserResource, User } from './api/User';

interface Args {
asc: boolean;
isAdmin?: boolean;
}
const sortedUsers = new Query(
const sortedUsers = new schema.Query(
new schema.All(User),
(entries, { asc, isAdmin }: Args = { asc: false }) => {
let sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
Expand All @@ -153,7 +81,7 @@ const sortedUsers = new Query(

function UsersPage() {
useFetch(UserResource.getList);
const users = useCache(sortedUsers, { asc: true });
const users = useQuery(sortedUsers, { asc: true });
if (!users) return <div>No users in cache yet</div>;
return (
<div>
Expand Down Expand Up @@ -199,10 +127,11 @@ export const UserResource = createResource({
```

```tsx title="UsersPage"
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { UserResource, User } from './api/User';

const getUserCount = new Query(
const getUserCount = new schema.Query(
new schema.All(User),
(entries, { isAdmin } = { }) => {
if (isAdmin !== undefined)
Expand All @@ -213,8 +142,8 @@ const getUserCount = new Query(

function UsersPage() {
useFetch(UserResource.getList);
const userCount = useCache(getUserCount);
const adminCount = useCache(getUserCount, { isAdmin: true });
const userCount = useQuery(getUserCount);
const adminCount = useQuery(getUserCount, { isAdmin: true });
if (userCount === undefined) return <div>No users in cache yet</div>;
return (
<div>
Expand Down Expand Up @@ -279,11 +208,12 @@ export const TodoResource = createResource({
```

```tsx title="TodoJoined.tsx"
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { TodoResource, Todo } from './api/Todo';
import { UserResource, User } from './api/User';

const todosWithUser = new Query(
const todosWithUser = new schema.Query(
new schema.All(Todo),
(entries, { userId = 0 }) => {
return entries.filter(todo => todo.userId?.id === userId);
Expand All @@ -293,7 +223,7 @@ const todosWithUser = new Query(
function TodosPage() {
useFetch(UserResource.getList);
useFetch(TodoResource.getList);
const todos = useCache(todosWithUser, { userId: 1 });
const todos = useQuery(todosWithUser, { userId: 1 });
if (!todos) return <div>No Todos in cache yet</div>;
return (
<div>
Expand Down
9 changes: 5 additions & 4 deletions docs/rest/guides/computed-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,11 @@ export const UserResource = createResource({
```

```tsx title="UsersPage"
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';
import { useQuery, useFetch } from '@data-client/react';
import { UserResource, User } from './api/User';

const getUserCount = new Query(
const getUserCount = new schema.Query(
new schema.All(User),
(entries, { isAdmin } = {}) => {
if (isAdmin !== undefined)
Expand All @@ -127,8 +128,8 @@ const getUserCount = new Query(

function UsersPage() {
useFetch(UserResource.getList);
const userCount = useCache(getUserCount);
const adminCount = useCache(getUserCount, { isAdmin: true });
const userCount = useQuery(getUserCount);
const adminCount = useQuery(getUserCount, { isAdmin: true });
if (userCount === undefined)
return <div>No users in cache yet</div>;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ exports[`Controller.query() query Collection based on args 2`] = `
]
`;

exports[`Controller.query() query Entity based on index 1`] = `
User {
"id": "1",
"username": "bob",
}
`;

exports[`Controller.query() query Entity based on pk 1`] = `
Tacos {
"id": "1",
Expand Down
Loading

1 comment on commit 082155f

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 082155f Previous: 5771da3 Ratio
normalizeLong 390 ops/sec (±2.74%) 447 ops/sec (±1.68%) 1.15
infer All 9994 ops/sec (±0.47%) 9629 ops/sec (±1.67%) 0.96
denormalizeLong 329 ops/sec (±2.37%) 321 ops/sec (±2.22%) 0.98
denormalizeLong donotcache 853 ops/sec (±1.03%) 888 ops/sec (±0.46%) 1.04
denormalizeShort donotcache 500x 1357 ops/sec (±0.39%) 1351 ops/sec (±0.13%) 1.00
denormalizeShort 500x 953 ops/sec (±0.41%) 958 ops/sec (±0.24%) 1.01
denormalizeLong with mixin Entity 310 ops/sec (±0.18%) 303 ops/sec (±0.26%) 0.98
denormalizeLong withCache 7538 ops/sec (±0.19%) 6836 ops/sec (±0.26%) 0.91
denormalizeLongAndShort withEntityCacheOnly 1634 ops/sec (±0.54%) 1562 ops/sec (±0.31%) 0.96
denormalizeLong All withCache 7307 ops/sec (±0.23%) 6337 ops/sec (±0.17%) 0.87
denormalizeLong Query-sorted withCache 7074 ops/sec (±0.43%) 6647 ops/sec (±0.38%) 0.94
getResponse 5421 ops/sec (±1.06%) 4951 ops/sec (±0.88%) 0.91
getResponse (null) 2968919 ops/sec (±0.65%) 2888601 ops/sec (±0.21%) 0.97
getResponse (clear cache) 307 ops/sec (±0.42%) 292 ops/sec (±1.10%) 0.95
getSmallResponse 2274 ops/sec (±0.09%) 2328 ops/sec (±0.30%) 1.02
getSmallInferredResponse 1767 ops/sec (±0.38%) 1765 ops/sec (±0.34%) 1.00
getResponse Query-sorted 788 ops/sec (±1.06%) 687 ops/sec (±1.09%) 0.87
getResponse Collection 5068 ops/sec (±1.49%) 5124 ops/sec (±1.06%) 1.01
setLong 377 ops/sec (±3.14%) 437 ops/sec (±2.25%) 1.16
setLongWithMerge 179 ops/sec (±1.52%) 189 ops/sec (±0.36%) 1.06
setLongWithSimpleMerge 189 ops/sec (±1.58%) 202 ops/sec (±0.27%) 1.07

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.