@ahoo-wang/wow-react 9.2.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,231 @@
1
+ # `@ahoo-wang/wow-react`
2
+
3
+ 面向 [Wow](https://github.com/Ahoo-Wang/Wow) 查询的 React hook:单条、列表、分页、计数和
4
+ 列表流。它们把查询、结果、加载中与错误保存为 React 状态,建立在
5
+ `@ahoo-wang/wow-client` 的查询类型之上。
6
+
7
+ ## 环境要求
8
+
9
+ - **React 19.3 及以上。** 本包用 React Compiler 编译,产物导入只有 React 19 才有的
10
+ `react/compiler-runtime`;不支持 React 18。
11
+ - 工具链与服务端渲染需要 Node.js 22.12 及以上;浏览器以 React 19 支持的为准。
12
+ - `@ahoo-wang/wow-client` 与本包的次版本号一致。
13
+ - TypeScript 6 或更高版本(CI 测试 6.0 到最新的 7.x),使用 `"moduleResolution": "bundler"` 或
14
+ `"module": "nodenext"`。
15
+
16
+ ## 安装
17
+
18
+ ```bash
19
+ pnpm add react react-dom @ahoo-wang/fetcher @ahoo-wang/fetcher-eventstream \
20
+ @ahoo-wang/wow-client @ahoo-wang/wow-react
21
+ ```
22
+
23
+ `@ahoo-wang/fetcher-eventstream` 是 `@ahoo-wang/wow-client` 的 peer,不是本包的。
24
+
25
+ 版本号跟随 Wow,次版本可能带有破坏性改动:用 `save-prefix=~` 或 `--save-exact` 让 Wow 包停在同一个次版本上,见[版本范围](https://wow.ahoo.me/zh/guide/typescript/compatibility#版本范围)。
26
+
27
+ 这些 hook 自带请求状态机:不需要 `@ahoo-wang/fetcher-react`,也不需要
28
+ `@ahoo-wang/fetcher-wow`。
29
+
30
+ 本包只发布 ES 模块。Node.js 22.12+ 上的 CommonJS 代码仍可以
31
+ `require('@ahoo-wang/wow-react')`,因为 Node.js 能通过 `require` 加载 ES 模块。
32
+
33
+ ## 配合查询客户端
34
+
35
+ `use*Query` 这组 hook 接收一个 `execute` 函数。查询客户端的方法——
36
+ `@ahoo-wang/wow-client` 的 `SnapshotQueryClient`,或生成的 `…QueryClientFactory`
37
+ 创建的客户端——签名恰好是 `execute` 需要的 `(query, attributes, abort)`,于是 URL、
38
+ 请求头和响应处理都由客户端负责,不用手写。这些客户端的方法已绑定到实例上,所以
39
+ `execute: client.pagedState` 可以直接写;自己对象上的方法要 `.bind(对象)` 或包一层
40
+ 箭头函数:
41
+
42
+ ```tsx
43
+ import {
44
+ filter,
45
+ pagedQuery,
46
+ type SnapshotQueryClient,
47
+ } from '@ahoo-wang/wow-client';
48
+ import { usePagedQuery } from '@ahoo-wang/wow-react';
49
+
50
+ interface OrderState {
51
+ id: string;
52
+ status: string;
53
+ }
54
+ // 查询可用的字段;生成的客户端会导出这个类型。
55
+ type OrderFields = 'aggregateId' | 'state.status';
56
+
57
+ export function PaidOrders({
58
+ client,
59
+ page,
60
+ }: {
61
+ client: SnapshotQueryClient<OrderState, OrderFields>;
62
+ page: number;
63
+ }) {
64
+ const { result, loading, error } = usePagedQuery<OrderState, OrderFields>({
65
+ query: pagedQuery({
66
+ filter: filter.eq('state.status', 'PAID'),
67
+ pagination: { index: page, size: 20 },
68
+ }),
69
+ execute: client.pagedState,
70
+ });
71
+
72
+ if (error) return <p role="alert">订单加载失败</p>;
73
+ if (loading || !result) return <p>加载中…</p>;
74
+ return (
75
+ <ul>
76
+ {result.list.map(order => (
77
+ <li key={order.id}>{order.status}</li>
78
+ ))}
79
+ </ul>
80
+ );
81
+ }
82
+ ```
83
+
84
+ 像上面这样把客户端的字段类型作为第二个类型参数传入:生成的客户端字段比 `string` 窄,
85
+ 而一旦写出第一个类型参数,TypeScript 就不会再从 `execute` 推断它。
86
+ 记得把 `abortController` 传下去:这样新的查询、`abort()`、`reset()` 和组件卸载都会取消请求。
87
+ 快照查询过滤的是快照文档,聚合状态在它的 `state` 字段下,所以状态字段写作
88
+ `state.status`,而不是 `status`。
89
+
90
+ 聚合查询暂时没有 Hook,通用的 `useQuery` 与聚合 Hook 计划在 9.3 提供。在此之前,在
91
+ effect 里调用 `client.aggregate`,并在清理函数里中止它,写法见
92
+ [参考页](https://wow.ahoo.me/zh/reference/typescript/wow-react/#聚合查询)。
93
+
94
+ 游标查询也还没有 Hook。用 `useSingleQuery` 运行它,把一页当作结果:类型参数传
95
+ `CursorPage<R>` 与 `CursorQuery<Fields>`,`execute` 传 `client.cursorState`(或
96
+ `client.cursor`);`nextCursor` 不为 `null` 时,用
97
+ `setQuery({ ...query, cursor: result.nextCursor })` 翻到下一页。
98
+
99
+ ## 配合端点 URL
100
+
101
+ `useFetcher*Query` 这组 hook 则通过 Fetcher 把查询 POST 到一个 URL:
102
+
103
+ ```tsx
104
+ import { Fetcher } from '@ahoo-wang/fetcher';
105
+ import { filter, pagedQuery } from '@ahoo-wang/wow-client';
106
+ import { useFetcherPagedQuery } from '@ahoo-wang/wow-react';
107
+
108
+ const fetcher = new Fetcher({ baseURL: 'https://api.example.com/' });
109
+
110
+ export function PaidOrders() {
111
+ const { result, loading, error } = useFetcherPagedQuery<OrderState>({
112
+ fetcher,
113
+ url: 'order/snapshot/paged/state',
114
+ initialQuery: pagedQuery({
115
+ filter: filter.eq('state.status', 'PAID'),
116
+ pagination: { index: 1, size: 20 },
117
+ }),
118
+ });
119
+ // …渲染同上
120
+ }
121
+ ```
122
+
123
+ `fetcher` 可以是 Fetcher 实例,也可以是已注册 Fetcher 的名字;省略时用默认 Fetcher。
124
+ 一个聚合的快照路由是 `{aggregate}/snapshot/{single|list|paged}[/state]` 与
125
+ `{aggregate}/snapshot/count`;聚合有上下文别名、owner 或租户路径时,路由前面还要加上它们。
126
+
127
+ ## 流式读取列表
128
+
129
+ `useListStreamQuery` 与 `useFetcherListStreamQuery` 以服务端推送事件(SSE)读取列表,
130
+ 行一到就保存下来。`listQuery()` 只在给出 `limit` 时才发送它:Wow 9.1.5 及以后此时用
131
+ 默认列表大小,Wow 8.11~9.1.3 则以 HTTP 400 拒绝,对这些服务端请传 `limit`:
132
+
133
+ ```tsx
134
+ import { filter, listQuery } from '@ahoo-wang/wow-client';
135
+ import { useFetcherListStreamQuery } from '@ahoo-wang/wow-react';
136
+
137
+ export function PaidOrderFeed() {
138
+ const { items, done, loading, error, abort } =
139
+ useFetcherListStreamQuery<OrderState>({
140
+ fetcher,
141
+ url: 'order/snapshot/list/state',
142
+ initialQuery: listQuery({
143
+ filter: filter.eq('state.status', 'PAID'),
144
+ limit: 100,
145
+ }),
146
+ });
147
+
148
+ if (error) return <p role="alert">{error.message}</p>;
149
+ return (
150
+ <>
151
+ <ul>
152
+ {items.map(order => (
153
+ <li key={order.id}>{order.id}</li>
154
+ ))}
155
+ </ul>
156
+ {loading && <button onClick={abort}>停止</button>}
157
+ {done && <p>共 {items.length} 个订单</p>}
158
+ </>
159
+ );
160
+ }
161
+ ```
162
+
163
+ | 字段 | 含义 |
164
+ | --------- | ----------------------------------------------------------------------------------------------- |
165
+ | `items` | 当前查询到目前为止收到的行,按到达顺序。新查询从空列表开始;`reset()` 清空它。 |
166
+ | `done` | 流正常结束,`items` 已包含全部行。等同于 `status === 'success'`。 |
167
+ | `loading` | 从发出请求直到流结束、出错或被中止。 |
168
+ | `error` | 请求失败时是 `FetcherError`;服务端在流中途发来错误事件时是带服务端 `errorCode` 的 `WowError`。 |
169
+ | `abort()` | 停止读取流并保留已收到的行。`reset()` 停止并清空 `items`。`execute()` 重新执行当前查询。 |
170
+
171
+ 流由 hook 自己持有:它负责读取,无论到达多少行,最多约每帧(16 毫秒)渲染一次,并在新查询开始、
172
+ 调用 `abort()` 或 `reset()`、组件卸载时取消流。组件不接触 reader,所以在 StrictMode 下
173
+ 也是安全的。`useFetcherListStreamQuery` 会发送 `Accept: text/event-stream`——Wow
174
+ 服务端要看到这个请求头才会以流的形式响应;用 `useListStreamQuery` 时,把客户端的
175
+ `listStream` 或 `listStateStream` 作为 `execute` 传入。
176
+
177
+ ## 状态与错误
178
+
179
+ 每个 hook 在挂载时执行查询,之后 `query` 选项(按内容比较)或 `setQuery()` 改变查询时
180
+ 再次执行,`useFetcher*` hook 在 `url` 或 `fetcher` 变化时也会再次执行;设置
181
+ `autoExecute: false` 则只在调用 `execute()` 时执行。新的查询会中止正在进行的请求,所以
182
+ 迟到的响应不会覆盖较新的结果。受控的 `query` 重新变为 `undefined` 时(如
183
+ `id ? singleQuery(…) : undefined`),中止进行中的请求并回到 `idle`,保留上一次结果;
184
+ 再给出查询之前不会执行。`onSuccess`、`onError` 分别以结果和错误为参数调用。
185
+
186
+ 请求失败和 `abort()` 都保留上一次的 `result`,刷新失败不会让界面变空白;`reset()`
187
+ 会中止进行中的请求,并清空 `result` 与 `error`。挂载即执行的 hook 首帧(服务端也一样)
188
+ 就是 `loading`。
189
+
190
+ 每个 hook 都返回 `status`、`loading`、`result`(流式 hook 为 `items` 与 `done`)、
191
+ `error`、`execute`、`abort`、`reset`、`getQuery` 和 `setQuery`。各 hook 的选项与返回
192
+ 类型都扩展本包声明并导出的 `QueryHookOptions` 与 `QueryHookReturn`,同时导出的还有
193
+ `QueryStatus` 与 `QueryExecutor`。`status` 是普通的字符串联合类型
194
+ `'idle' | 'loading' | 'success' | 'error'`,组件 props 或测试里可以直接写字面量。
195
+
196
+ `error` 的类型默认是 `Error`,需要更窄时传入类型参数 `E`:请求失败时是
197
+ `FetcherError`,流中的错误事件是 `WowError`,自定义的 `execute` 则是它抛出的任何错误。
198
+ `@ahoo-wang/wow-client` 的 `toWowError` 能从失败的请求中读出服务端的 `ErrorInfo`:
199
+
200
+ ```ts
201
+ import { ErrorCodes, toWowError } from '@ahoo-wang/wow-client';
202
+
203
+ const wowError = await toWowError(error);
204
+ if (wowError?.errorCode === ErrorCodes.NOT_FOUND) {
205
+ // …
206
+ }
207
+ ```
208
+
209
+ ## Hook 一览
210
+
211
+ | Hook | 查询 | 结果 |
212
+ | ------------------------------------------------- | --------------------------- | ------------------------------- |
213
+ | `useSingleQuery`、`useFetcherSingleQuery` | `singleQuery(…)` | `result`:一条 |
214
+ | `useListQuery`、`useFetcherListQuery` | `listQuery(…)` | `result`:若干行 |
215
+ | `usePagedQuery`、`useFetcherPagedQuery` | `pagedQuery(…)` | `result`:`{ total, list }` |
216
+ | `useCountQuery`、`useFetcherCountQuery` | 一个 `filter.*` 表达式 | `result`:记录数 |
217
+ | `useListStreamQuery`、`useFetcherListStreamQuery` | `listQuery(…)`,以 SSE 事件 | `items` 陆续到达,结束后 `done` |
218
+
219
+ 查询类型默认使用 `@ahoo-wang/wow-client` 的 `filter` API。每个 hook 也接受
220
+ `@ahoo-wang/wow-client/legacy` 中已弃用的 Condition 查询(Wow 8.10 服务端需要);
221
+ 这个重载将在 v10 移除。
222
+
223
+ 在 Wow 9 中从 `@ahoo-wang/fetcher-react`(其中的 Wow hook)迁移而来;版本号跟随 Wow。
224
+
225
+ ## 文档
226
+
227
+ - [TypeScript 指南](https://wow.ahoo.me/zh/guide/typescript/)
228
+ - [wow-react 参考](https://wow.ahoo.me/zh/reference/typescript/wow-react/)
229
+ - [交互式查询 hook Story](https://wow.ahoo.me/storybook/?path=/docs/react-hooks-wow-queries--docs)
230
+
231
+ [English](./README.md) · [许可证](https://github.com/Ahoo-Wang/Wow/blob/main/LICENSE)
@@ -0,0 +1,61 @@
1
+ import { FilterExpression } from '@ahoo-wang/wow-client';
2
+ import { Condition } from '@ahoo-wang/wow-client/legacy';
3
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
4
+ /**
5
+ * Options of {@link useCountQuery}: a filter and an `execute` that resolves to
6
+ * how many rows it matches.
7
+ *
8
+ * @template FIELDS - The field names the filter may use
9
+ * @template E - The error type, `Error` by default
10
+ * @template Q - The filter type: `FilterExpression` by default
11
+ */
12
+ export interface UseCountQueryOptions<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>> extends QueryHookOptions<Q, number, E> {
13
+ }
14
+ /**
15
+ * What {@link useCountQuery} returns: the count as `result`.
16
+ *
17
+ * @template FIELDS - The field names the filter may use
18
+ * @template E - The error type, `Error` by default
19
+ * @template Q - The filter type: `FilterExpression` by default
20
+ */
21
+ export interface UseCountQueryReturn<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>> extends QueryHookReturn<Q, number, E> {
22
+ }
23
+ /**
24
+ * Counts what a filter matches through your own `execute` function and keeps
25
+ * the count as state: typically a query client's `count`.
26
+ *
27
+ * `execute` receives the filter, the `attributes` option and an
28
+ * `AbortController`; hand the controller on so that a newer query, `abort()`
29
+ * or an unmount cancels the request. The count runs on mount and whenever
30
+ * `query` or `setQuery()` changes the filter; set `autoExecute: false` to run
31
+ * it only through `execute()`.
32
+ *
33
+ * Returns `result` (the count, or `undefined` before the first success),
34
+ * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and
35
+ * `setQuery`.
36
+ *
37
+ * @template FIELDS - The field names the filter may use. With a client whose
38
+ * fields are narrower than `string`, as a generated client's are, pass
39
+ * them here; inferred from the first filter, they would admit only its
40
+ * fields in `setQuery()`
41
+ * @template E - The error type, `Error` by default
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import { filter, type SnapshotQueryClient } from '@ahoo-wang/wow-client';
46
+ * import { useCountQuery } from '@ahoo-wang/wow-react';
47
+ *
48
+ * function PaidCount({ client }: { client: SnapshotQueryClient<OrderState, OrderFields> }) {
49
+ * const { result, error } = useCountQuery<OrderFields>({
50
+ * initialQuery: filter.eq('state.status', 'PAID'),
51
+ * execute: (query, attributes, abortController) =>
52
+ * client.count(query, attributes, abortController),
53
+ * });
54
+ * if (error) return <p role="alert">{error.message}</p>;
55
+ * return <p>{result ?? '…'} paid orders</p>;
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function useCountQuery<FIELDS extends string = string, E = Error>(options: UseCountQueryOptions<FIELDS, E, FilterExpression<FIELDS>>): UseCountQueryReturn<FIELDS, E, FilterExpression<FIELDS>>;
60
+ export declare function useCountQuery<FIELDS extends string = string, E = Error>(options: UseCountQueryOptions<FIELDS, E, Condition<FIELDS>>): UseCountQueryReturn<FIELDS, E, Condition<FIELDS>>;
61
+ export declare function useCountQuery<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>>(options: UseCountQueryOptions<FIELDS, E, Q>): UseCountQueryReturn<FIELDS, E, Q>;
@@ -0,0 +1,65 @@
1
+ import { FilterExpression } from '@ahoo-wang/wow-client';
2
+ import { Condition } from '@ahoo-wang/wow-client/legacy';
3
+ import { Endpoint } from '../internal/endpoint.js';
4
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
5
+ /**
6
+ * Options of {@link useFetcherCountQuery}: those of every query hook, with
7
+ * the endpoint and the Fetcher in place of `execute`.
8
+ *
9
+ * @template FIELDS - The field names the filter may use
10
+ * @template E - The error type, `Error` by default
11
+ * @template Q - The filter type: `FilterExpression` by default
12
+ */
13
+ export interface UseFetcherCountQueryOptions<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>> extends Omit<QueryHookOptions<Q, number, E>, 'execute'>, Endpoint {
14
+ }
15
+ /**
16
+ * What {@link useFetcherCountQuery} returns: the count as `result`.
17
+ *
18
+ * @template FIELDS - The field names the filter may use
19
+ * @template E - The error type, `Error` by default
20
+ * @template Q - The filter type: `FilterExpression` by default
21
+ */
22
+ export interface UseFetcherCountQueryReturn<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>> extends QueryHookReturn<Q, number, E> {
23
+ }
24
+ /**
25
+ * POSTs a filter to a Wow count endpoint through a Fetcher and keeps the
26
+ * count as state.
27
+ *
28
+ * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher
29
+ * or the name of a registered one, the default Fetcher when omitted. The
30
+ * count runs on mount and whenever `query` or `setQuery()` changes the
31
+ * filter; set `autoExecute: false` to run it only through `execute()`. A
32
+ * newer filter aborts the request in flight, so a late response never
33
+ * overwrites a newer one; an unmount aborts it too.
34
+ *
35
+ * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is
36
+ * compared by its name, or by its `baseURL` when it has none, so one created
37
+ * inline in render does not run it on every render.
38
+ *
39
+ * Returns `result` (the count, or `undefined` before the first success),
40
+ * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and
41
+ * `setQuery`. A failed request sets `error` to a `FetcherError`;
42
+ * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's
43
+ * `errorCode` from it.
44
+ *
45
+ * @template FIELDS - The field names the filter may use
46
+ * @template E - The error type, `Error` by default
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * import { filter } from '@ahoo-wang/wow-client';
51
+ * import { useFetcherCountQuery } from '@ahoo-wang/wow-react';
52
+ *
53
+ * function PaidCount() {
54
+ * const { result, error } = useFetcherCountQuery({
55
+ * url: 'order/snapshot/count',
56
+ * initialQuery: filter.eq('state.status', 'PAID'),
57
+ * });
58
+ * if (error) return <p role="alert">{error.message}</p>;
59
+ * return <p>{result ?? '…'} paid orders</p>;
60
+ * }
61
+ * ```
62
+ */
63
+ export declare function useFetcherCountQuery<FIELDS extends string = string, E = Error>(options: UseFetcherCountQueryOptions<FIELDS, E, FilterExpression<FIELDS>>): UseFetcherCountQueryReturn<FIELDS, E, FilterExpression<FIELDS>>;
64
+ export declare function useFetcherCountQuery<FIELDS extends string = string, E = Error>(options: UseFetcherCountQueryOptions<FIELDS, E, Condition<FIELDS>>): UseFetcherCountQueryReturn<FIELDS, E, Condition<FIELDS>>;
65
+ export declare function useFetcherCountQuery<FIELDS extends string = string, E = Error, Q extends Condition<FIELDS> | FilterExpression<FIELDS> = FilterExpression<FIELDS>>(options: UseFetcherCountQueryOptions<FIELDS, E, Q>): UseFetcherCountQueryReturn<FIELDS, E, Q>;
@@ -0,0 +1,78 @@
1
+ import { FilterListQuery } from '@ahoo-wang/wow-client';
2
+ import { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';
3
+ import { Endpoint } from '../internal/endpoint.js';
4
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
5
+ /**
6
+ * Options of {@link useFetcherListQuery}: those of every query hook, with the
7
+ * endpoint and the Fetcher in place of `execute`.
8
+ *
9
+ * @template R - One row of the list
10
+ * @template FIELDS - The field names the query may use
11
+ * @template E - The error type, `Error` by default
12
+ * @template Q - The query type: `FilterListQuery` by default
13
+ */
14
+ export interface UseFetcherListQueryOptions<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>> extends Omit<QueryHookOptions<Q, R[], E>, 'execute'>, Endpoint {
15
+ }
16
+ /**
17
+ * What {@link useFetcherListQuery} returns: the rows as `result`.
18
+ *
19
+ * @template R - One row of the list
20
+ * @template FIELDS - The field names the query may use
21
+ * @template E - The error type, `Error` by default
22
+ * @template Q - The query type: `FilterListQuery` by default
23
+ */
24
+ export interface UseFetcherListQueryReturn<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>> extends QueryHookReturn<Q, R[], E> {
25
+ }
26
+ /**
27
+ * POSTs a list query to a Wow endpoint through a Fetcher and keeps the rows
28
+ * as state.
29
+ *
30
+ * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher
31
+ * or the name of a registered one, the default Fetcher when omitted. The
32
+ * query runs on mount and whenever `query` or `setQuery()` changes it; set
33
+ * `autoExecute: false` to run it only through `execute()`. A newer query
34
+ * aborts the request in flight, so a late response never overwrites a newer
35
+ * one; an unmount aborts it too.
36
+ *
37
+ * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is
38
+ * compared by its name, or by its `baseURL` when it has none, so one created
39
+ * inline in render does not run it on every render.
40
+ *
41
+ * Returns `result` (the rows, or `undefined` before the first success),
42
+ * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and
43
+ * `setQuery`. A failed request sets `error` to a `FetcherError`;
44
+ * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's
45
+ * `errorCode` from it.
46
+ *
47
+ * @template R - One row of the list
48
+ * @template FIELDS - The field names the query may use
49
+ * @template E - The error type, `Error` by default
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * import { desc, filter, listQuery } from '@ahoo-wang/wow-client';
54
+ * import { useFetcherListQuery } from '@ahoo-wang/wow-react';
55
+ *
56
+ * function LatestOrders() {
57
+ * const { result, loading, error, execute } = useFetcherListQuery<OrderState>({
58
+ * url: 'order/snapshot/list/state',
59
+ * initialQuery: listQuery({
60
+ * filter: filter.eq('state.status', 'PAID'),
61
+ * sort: [desc('createTime')],
62
+ * limit: 20,
63
+ * }),
64
+ * });
65
+ * if (error) return <p role="alert">{error.message}</p>;
66
+ * if (loading || !result) return <p>Loading…</p>;
67
+ * return (
68
+ * <>
69
+ * <ul>{result.map(order => <li key={order.id}>{order.id}</li>)}</ul>
70
+ * <button onClick={execute}>Refresh</button>
71
+ * </>
72
+ * );
73
+ * }
74
+ * ```
75
+ */
76
+ export declare function useFetcherListQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherListQueryOptions<R, FIELDS, E, FilterListQuery<FIELDS>>): UseFetcherListQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;
77
+ export declare function useFetcherListQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherListQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>): UseFetcherListQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;
78
+ export declare function useFetcherListQuery<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>>(options: UseFetcherListQueryOptions<R, FIELDS, E, Q>): UseFetcherListQueryReturn<R, FIELDS, E, Q>;
@@ -0,0 +1,63 @@
1
+ import { FilterListQuery } from '@ahoo-wang/wow-client';
2
+ import { ListQuery, ListQueryRequest } from '@ahoo-wang/wow-client/legacy';
3
+ import { Endpoint } from '../internal/endpoint.js';
4
+ import { UseListStreamQueryOptions, UseListStreamQueryReturn } from './useListStreamQuery.js';
5
+ /**
6
+ * Options of {@link useFetcherListStreamQuery}: those of `useListStreamQuery`,
7
+ * with the endpoint and the Fetcher in place of `execute`.
8
+ *
9
+ * @template R - One row of the stream: the `data` of each event
10
+ * @template FIELDS - The field names the query may use
11
+ * @template E - The error type, `Error` by default: a failed request
12
+ * rejects with a `FetcherError`, an error event in the stream with a
13
+ * `WowError`
14
+ * @template Q - The query type: `FilterListQuery` by default
15
+ */
16
+ export interface UseFetcherListStreamQueryOptions<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>> extends Omit<UseListStreamQueryOptions<R, FIELDS, E, Q>, 'execute'>, Endpoint {
17
+ }
18
+ /**
19
+ * What {@link useFetcherListStreamQuery} returns; see
20
+ * {@link UseListStreamQueryReturn}.
21
+ */
22
+ export interface UseFetcherListStreamQueryReturn<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>> extends UseListStreamQueryReturn<R, FIELDS, E, Q> {
23
+ }
24
+ /**
25
+ * Streams the rows of a list query from a Wow list endpoint and keeps them as
26
+ * state; see `useListStreamQuery` for the state it returns.
27
+ *
28
+ * It POSTs the query to `url` through `fetcher` (the default Fetcher when
29
+ * omitted) with `Accept: text/event-stream`, the header a Wow server needs to
30
+ * answer with an event stream rather than JSON. An error event in the stream
31
+ * ends it with a `WowError` in `error`.
32
+ *
33
+ * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is
34
+ * compared by its name, or by its `baseURL` when it has none, so one created
35
+ * inline in render does not run it on every render.
36
+ *
37
+ * @template R - One row of the stream: the `data` of each event
38
+ * @template FIELDS - The field names the query may use
39
+ * @template E - The error type
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * import { filter, listQuery } from '@ahoo-wang/wow-client';
44
+ * import { useFetcherListStreamQuery } from '@ahoo-wang/wow-react';
45
+ *
46
+ * function PaidOrders() {
47
+ * const { items, done, loading, error } = useFetcherListStreamQuery<OrderState>({
48
+ * url: 'order/snapshot/list/state',
49
+ * initialQuery: listQuery({ filter: filter.eq('state.status', 'PAID') }),
50
+ * });
51
+ * if (error) return <p role="alert">{error.message}</p>;
52
+ * return (
53
+ * <>
54
+ * <ul>{items.map(order => <li key={order.id}>{order.id}</li>)}</ul>
55
+ * {loading ? <p>Loading…</p> : done && <p>{items.length} orders</p>}
56
+ * </>
57
+ * );
58
+ * }
59
+ * ```
60
+ */
61
+ export declare function useFetcherListStreamQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherListStreamQueryOptions<R, FIELDS, E, FilterListQuery<FIELDS>>): UseFetcherListStreamQueryReturn<R, FIELDS, E, FilterListQuery<FIELDS>>;
62
+ export declare function useFetcherListStreamQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherListStreamQueryOptions<R, FIELDS, E, ListQuery<FIELDS>>): UseFetcherListStreamQueryReturn<R, FIELDS, E, ListQuery<FIELDS>>;
63
+ export declare function useFetcherListStreamQuery<R, FIELDS extends string = string, E = Error, Q extends ListQueryRequest<FIELDS> = FilterListQuery<FIELDS>>(options: UseFetcherListStreamQueryOptions<R, FIELDS, E, Q>): UseFetcherListStreamQueryReturn<R, FIELDS, E, Q>;
@@ -0,0 +1,73 @@
1
+ import { FilterPagedQuery, PagedList } from '@ahoo-wang/wow-client';
2
+ import { PagedQuery, PagedQueryRequest } from '@ahoo-wang/wow-client/legacy';
3
+ import { Endpoint } from '../internal/endpoint.js';
4
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
5
+ /**
6
+ * Options of {@link useFetcherPagedQuery}: those of every query hook, with
7
+ * the endpoint and the Fetcher in place of `execute`.
8
+ *
9
+ * @template R - One row of the page
10
+ * @template FIELDS - The field names the query may use
11
+ * @template E - The error type, `Error` by default
12
+ * @template Q - The query type: `FilterPagedQuery` by default
13
+ */
14
+ export interface UseFetcherPagedQueryOptions<R, FIELDS extends string = string, E = Error, Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>> extends Omit<QueryHookOptions<Q, PagedList<R>, E>, 'execute'>, Endpoint {
15
+ }
16
+ /**
17
+ * What {@link useFetcherPagedQuery} returns: the page (`total` and `list`)
18
+ * as `result`.
19
+ *
20
+ * @template R - One row of the page
21
+ * @template FIELDS - The field names the query may use
22
+ * @template E - The error type, `Error` by default
23
+ * @template Q - The query type: `FilterPagedQuery` by default
24
+ */
25
+ export interface UseFetcherPagedQueryReturn<R, FIELDS extends string = string, E = Error, Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>> extends QueryHookReturn<Q, PagedList<R>, E> {
26
+ }
27
+ /**
28
+ * POSTs a paged query to a Wow endpoint through a Fetcher and keeps the page
29
+ * as state.
30
+ *
31
+ * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher
32
+ * or the name of a registered one, the default Fetcher when omitted. The
33
+ * query runs on mount and whenever `query` or `setQuery()` changes it — turn
34
+ * pages with `setQuery()`; set `autoExecute: false` to run it only through
35
+ * `execute()`. A newer query aborts the request in flight, so a late response
36
+ * never overwrites a newer one; an unmount aborts it too.
37
+ *
38
+ * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is
39
+ * compared by its name, or by its `baseURL` when it has none, so one created
40
+ * inline in render does not run it on every render.
41
+ *
42
+ * Returns `result` (`{ total, list }`, or `undefined` before the first
43
+ * success), `loading`, `error`, `status`, `execute`, `abort`, `reset`,
44
+ * `getQuery` and `setQuery`. A failed request sets `error` to a
45
+ * `FetcherError`; `toWowError(error)` from `@ahoo-wang/wow-client` reads the
46
+ * server's `errorCode` from it.
47
+ *
48
+ * @template R - One row of the page
49
+ * @template FIELDS - The field names the query may use
50
+ * @template E - The error type, `Error` by default
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * import { filter, pagedQuery } from '@ahoo-wang/wow-client';
55
+ * import { useFetcherPagedQuery } from '@ahoo-wang/wow-react';
56
+ *
57
+ * function PaidOrders({ page }: { page: number }) {
58
+ * const { result, loading, error } = useFetcherPagedQuery<OrderState>({
59
+ * url: 'order/snapshot/paged/state',
60
+ * query: pagedQuery({
61
+ * filter: filter.eq('state.status', 'PAID'),
62
+ * pagination: { index: page, size: 20 },
63
+ * }),
64
+ * });
65
+ * if (error) return <p role="alert">{error.message}</p>;
66
+ * if (loading || !result) return <p>Loading…</p>;
67
+ * return <p>{result.list.length} of {result.total}</p>;
68
+ * }
69
+ * ```
70
+ */
71
+ export declare function useFetcherPagedQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherPagedQueryOptions<R, FIELDS, E, FilterPagedQuery<FIELDS>>): UseFetcherPagedQueryReturn<R, FIELDS, E, FilterPagedQuery<FIELDS>>;
72
+ export declare function useFetcherPagedQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherPagedQueryOptions<R, FIELDS, E, PagedQuery<FIELDS>>): UseFetcherPagedQueryReturn<R, FIELDS, E, PagedQuery<FIELDS>>;
73
+ export declare function useFetcherPagedQuery<R, FIELDS extends string = string, E = Error, Q extends PagedQueryRequest<FIELDS> = FilterPagedQuery<FIELDS>>(options: UseFetcherPagedQueryOptions<R, FIELDS, E, Q>): UseFetcherPagedQueryReturn<R, FIELDS, E, Q>;
@@ -0,0 +1,69 @@
1
+ import { FilterSingleQuery } from '@ahoo-wang/wow-client';
2
+ import { SingleQuery, SingleQueryRequest } from '@ahoo-wang/wow-client/legacy';
3
+ import { Endpoint } from '../internal/endpoint.js';
4
+ import { QueryHookOptions, QueryHookReturn } from '../types.js';
5
+ /**
6
+ * Options of {@link useFetcherSingleQuery}: those of every query hook, with
7
+ * the endpoint and the Fetcher in place of `execute`.
8
+ *
9
+ * @template R - The item the query returns
10
+ * @template FIELDS - The field names the query may use
11
+ * @template E - The error type, `Error` by default
12
+ * @template Q - The query type: `FilterSingleQuery` by default
13
+ */
14
+ export interface UseFetcherSingleQueryOptions<R, FIELDS extends string = string, E = Error, Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>> extends Omit<QueryHookOptions<Q, R, E>, 'execute'>, Endpoint {
15
+ }
16
+ /**
17
+ * What {@link useFetcherSingleQuery} returns: the item as `result`.
18
+ *
19
+ * @template R - The item the query returns
20
+ * @template FIELDS - The field names the query may use
21
+ * @template E - The error type, `Error` by default
22
+ * @template Q - The query type: `FilterSingleQuery` by default
23
+ */
24
+ export interface UseFetcherSingleQueryReturn<R, FIELDS extends string = string, E = Error, Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>> extends QueryHookReturn<Q, R, E> {
25
+ }
26
+ /**
27
+ * POSTs a single query to a Wow endpoint through a Fetcher and keeps the
28
+ * result as state.
29
+ *
30
+ * `url` is resolved against the Fetcher's `baseURL`; `fetcher` is a Fetcher
31
+ * or the name of a registered one, the default Fetcher when omitted. The
32
+ * query runs on mount and whenever `query` or `setQuery()` changes it; set
33
+ * `autoExecute: false` to run it only through `execute()`. A newer query
34
+ * aborts the request in flight, so a late response never overwrites a newer
35
+ * one; an unmount aborts it too.
36
+ *
37
+ * A change of `url`, or of `fetcher`, runs the query again. A Fetcher is
38
+ * compared by its name, or by its `baseURL` when it has none, so one created
39
+ * inline in render does not run it on every render.
40
+ *
41
+ * Returns `result` (the item, or `undefined` before the first success),
42
+ * `loading`, `error`, `status`, `execute`, `abort`, `reset`, `getQuery` and
43
+ * `setQuery`. A failed request sets `error` to a `FetcherError`;
44
+ * `toWowError(error)` from `@ahoo-wang/wow-client` reads the server's
45
+ * `errorCode` from it.
46
+ *
47
+ * @template R - The item the query returns
48
+ * @template FIELDS - The field names the query may use
49
+ * @template E - The error type, `Error` by default
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * import { filter, singleQuery } from '@ahoo-wang/wow-client';
54
+ * import { useFetcherSingleQuery } from '@ahoo-wang/wow-react';
55
+ *
56
+ * function OrderStatus({ id }: { id: string }) {
57
+ * const { result, loading, error } = useFetcherSingleQuery<OrderState>({
58
+ * url: 'order/snapshot/single/state',
59
+ * query: singleQuery({ filter: filter.id(id) }),
60
+ * });
61
+ * if (error) return <p role="alert">{error.message}</p>;
62
+ * if (loading || !result) return <p>Loading…</p>;
63
+ * return <p>{result.status}</p>;
64
+ * }
65
+ * ```
66
+ */
67
+ export declare function useFetcherSingleQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherSingleQueryOptions<R, FIELDS, E, FilterSingleQuery<FIELDS>>): UseFetcherSingleQueryReturn<R, FIELDS, E, FilterSingleQuery<FIELDS>>;
68
+ export declare function useFetcherSingleQuery<R, FIELDS extends string = string, E = Error>(options: UseFetcherSingleQueryOptions<R, FIELDS, E, SingleQuery<FIELDS>>): UseFetcherSingleQueryReturn<R, FIELDS, E, SingleQuery<FIELDS>>;
69
+ export declare function useFetcherSingleQuery<R, FIELDS extends string = string, E = Error, Q extends SingleQueryRequest<FIELDS> = FilterSingleQuery<FIELDS>>(options: UseFetcherSingleQueryOptions<R, FIELDS, E, Q>): UseFetcherSingleQueryReturn<R, FIELDS, E, Q>;