Skip to content

Commit 5469db0

Browse files
committed
docs: Show Query schema combined with Collection for sorting
1 parent 2ba4823 commit 5469db0

File tree

4 files changed

+115
-53
lines changed

4 files changed

+115
-53
lines changed

docs/core/api/useQuery.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ interface Queryable {
7171

7272
<!-- TODO: Add examples for each Queryable schema type and the different args that can be sent (like index, vs pk; union needing 'type') -->
7373

74-
### Client-side User sorting
74+
### Sorting & Filtering
7575

7676
[Query](/rest/api/Query) provides programmatic access to the Reactive Data Client store.
7777

@@ -104,17 +104,21 @@ export const UserResource = createResource({
104104
});
105105
```
106106

107-
```tsx title="UsersPage" {18}
107+
```tsx title="UsersPage" {22}
108108
import { schema } from '@data-client/rest';
109109
import { useQuery, useFetch } from '@data-client/react';
110110
import { UserResource, User } from './UserResource';
111111

112+
interface Args {
113+
asc: boolean;
114+
isAdmin?: boolean;
115+
}
112116
const sortedUsers = new schema.Query(
113117
new schema.All(User),
114-
(entries, { asc } = { asc: false }) => {
115-
const sorted = [...entries].sort((a, b) =>
116-
a.name.localeCompare(b.name),
117-
);
118+
(entries, { asc, isAdmin }: Args = { asc: false }) => {
119+
let sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
120+
if (isAdmin !== undefined)
121+
sorted = sorted.filter(user => user.isAdmin === isAdmin);
118122
if (asc) return sorted;
119123
return sorted.reverse();
120124
},

docs/rest/api/Collection.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,17 @@ class Post extends Entity {
312312
export const getPosts = new RestEndpoint({
313313
path: '/:group/posts',
314314
searchParams: {} as { orderBy?: string; author?: string },
315-
schema: new schema.Collection([Post], {
316-
nonFilterArgumentKeys: /orderBy/,
317-
}),
315+
schema: new schema.Query(
316+
new schema.Collection([Post], {
317+
nonFilterArgumentKeys: /orderBy/,
318+
}),
319+
(posts, { orderBy } = {}) => {
320+
if (orderBy && posts) {
321+
return [...posts].sort((a, b) => a[orderBy].localeCompare(b[orderBy]));
322+
}
323+
return posts;
324+
},
325+
)
318326
});
319327
```
320328

docs/rest/api/Query.md

Lines changed: 92 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,69 +30,114 @@ response for use with [useQuery](/docs/api/useQuery)
3030

3131
## Usage
3232

33-
### Sorting & Filtering
33+
### Maintaining sort after creates {#sorting}
3434

35-
<HooksPlayground groupId="schema" defaultOpen="y" fixtures={[
36-
{
37-
endpoint: new RestEndpoint({path: '/users'}),
38-
args: [],
39-
response: [
40-
{ id: '123', name: 'Jim' },
41-
{ id: '456', name: 'Jane' },
42-
{ id: '777', name: 'Albatras', isAdmin: true },
43-
],
44-
delay: 150,
45-
},
46-
]}>
35+
import { postFixtures,getInitialInterceptorData } from '@site/src/fixtures/posts-collection';
4736

48-
```ts title="api/User.ts" collapsed
49-
export class User extends Entity {
37+
Here we have an API that sorts based on the `orderBy` field. By wrapping our [Collection](./Collection.md)
38+
in a `Query` that sorts, we can ensure we maintain the correct order after [pushing](./RestEndpoint.md#push)
39+
new posts.
40+
41+
Our example code starts sorting by `title`. Try adding some posts and see them inserted in the correct sort
42+
order.
43+
44+
<HooksPlayground fixtures={postFixtures} getInitialInterceptorData={getInitialInterceptorData} row>
45+
46+
```ts title="getPosts" {20-27}
47+
import { Entity, RestEndpoint } from '@data-client/rest';
48+
49+
class Post extends Entity {
5050
id = '';
51-
name = '';
52-
isAdmin = false;
51+
title = '';
52+
group = '';
53+
author = '';
54+
5355
pk() {
5456
return this.id;
5557
}
5658
}
57-
export const UserResource = createResource({
58-
path: '/users/:id',
59-
schema: User,
59+
export const getPosts = new RestEndpoint({
60+
path: '/:group/posts',
61+
searchParams: {} as { orderBy?: string; author?: string },
62+
schema: new schema.Query(
63+
new schema.Collection([Post], {
64+
nonFilterArgumentKeys: /orderBy/,
65+
}),
66+
(posts, { orderBy } = {}) => {
67+
if (orderBy && posts) {
68+
return [...posts].sort((a, b) =>
69+
a[orderBy].localeCompare(b[orderBy]),
70+
);
71+
}
72+
return posts;
73+
},
74+
),
6075
});
6176
```
6277

63-
```tsx title="UsersPage.tsx"
64-
import { schema } from '@data-client/rest';
65-
import { useQuery, useFetch } from '@data-client/react';
66-
import { UserResource, User } from './api/User';
78+
```tsx title="NewPost" collapsed
79+
import { useLoading } from '@data-client/hooks';
80+
import { getPosts } from './getPosts';
81+
82+
export default function NewPost({ user }: { user: string }) {
83+
const ctrl = useController();
84+
85+
const [handlePress, loading] = useLoading(async e => {
86+
if (e.key === 'Enter') {
87+
const title = e.currentTarget.value;
88+
e.currentTarget.value = '';
89+
await ctrl.fetch(getPosts.push, {group: 'react'}, {
90+
title,
91+
author: user,
92+
});
93+
}
94+
});
6795

68-
interface Args {
69-
asc: boolean;
70-
isAdmin?: boolean;
96+
return (
97+
<div>
98+
<input type="text" onKeyDown={handlePress} />{loading ? ' ...' : ''}
99+
</div>
100+
);
71101
}
72-
const sortedUsers = new schema.Query(
73-
new schema.All(User),
74-
(entries, { asc, isAdmin }: Args = { asc: false }) => {
75-
let sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
76-
if (isAdmin !== undefined)
77-
sorted = sorted.filter(user => user.isAdmin === isAdmin);
78-
if (asc) return sorted;
79-
return sorted.reverse();
80-
},
81-
);
102+
```
82103

83-
function UsersPage() {
84-
useFetch(UserResource.getList);
85-
const users = useQuery(sortedUsers, { asc: true });
86-
if (!users) return <div>No users in cache yet</div>;
104+
```tsx title="PostList" collapsed
105+
import { useSuspense } from '@data-client/react';
106+
import { getPosts } from './getPosts';
107+
import NewPost from './NewPost';
108+
109+
export default function PostList({
110+
user,
111+
}) {
112+
const posts = useSuspense(getPosts, { author: user, orderBy: 'title', group: 'react' });
113+
return (
114+
<div>
115+
{posts.map(post => (
116+
<div key={post.pk()}>{post.title}</div>
117+
))}
118+
<NewPost user={user} />
119+
</div>
120+
);
121+
}
122+
```
123+
124+
```tsx title="UserList" collapsed
125+
import PostList from './PostList';
126+
127+
function UserList() {
128+
const users = ['bob', 'clara']
87129
return (
88130
<div>
89131
{users.map(user => (
90-
<div key={user.pk()}>{user.name}</div>
132+
<section key={user}>
133+
<h3>{user}</h3>
134+
<PostList user={user} />
135+
</section>
91136
))}
92137
</div>
93138
);
94139
}
95-
render(<UsersPage />);
140+
render(<UserList />);
96141
```
97142

98143
</HooksPlayground>
@@ -291,7 +336,10 @@ import { UserResource } from './api/User';
291336
const groupTodoByUser = new schema.Query(
292337
TodoResource.getList.schema,
293338
todos => {
294-
return Object.groupBy(todos, todo => todo?.userId?.username) as Record<string, Todo[]>;
339+
return Object.groupBy(todos, todo => todo?.userId?.username) as Record<
340+
string,
341+
Todo[]
342+
>;
295343
},
296344
);
297345

website/src/gtagfix.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ if (ExecutionEnvironment.canUseDOM) {
77
console.info(args);
88
};
99
}
10+
// fix devmode webpack bug
11+
if (!('installedCssChunks' in window)) window.installedCssChunks = {};
1012
}

0 commit comments

Comments
 (0)