@ahoo-wang/fetcher-wow 1.2.1 → 1.2.3
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.
- package/README.md +174 -87
- package/README.zh-CN.md +169 -87
- package/dist/command/commandClient.d.ts +46 -85
- package/dist/command/commandClient.d.ts.map +1 -1
- package/dist/index.es.js +178 -54
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/query/event/eventStreamQueryClient.d.ts +84 -3
- package/dist/query/event/eventStreamQueryClient.d.ts.map +1 -1
- package/dist/query/queryApi.d.ts +4 -4
- package/dist/query/queryApi.d.ts.map +1 -1
- package/dist/query/snapshot/snapshotQueryApi.d.ts +4 -4
- package/dist/query/snapshot/snapshotQueryApi.d.ts.map +1 -1
- package/dist/query/snapshot/snapshotQueryClient.d.ts +183 -8
- package/dist/query/snapshot/snapshotQueryClient.d.ts.map +1 -1
- package/package.json +4 -4
package/README.zh-CN.md
CHANGED
|
@@ -18,7 +18,12 @@
|
|
|
18
18
|
- **📡 实时事件流**:内置对服务器发送事件的支持,用于接收实时命令结果和数据更新
|
|
19
19
|
- **🔄 CQRS 模式实现**:对命令查询责任分离架构模式的一流支持
|
|
20
20
|
- **🧱 DDD 基础构件**:基本的领域驱动设计构建块,包括聚合、事件和值对象
|
|
21
|
-
- **🔍
|
|
21
|
+
- **🔍 查询客户端**:专门用于查询快照和事件流数据的客户端,支持全面的查询操作:
|
|
22
|
+
- 资源计数
|
|
23
|
+
- 资源列表查询
|
|
24
|
+
- 以服务器发送事件形式流式传输资源
|
|
25
|
+
- 资源分页
|
|
26
|
+
- 单个资源检索
|
|
22
27
|
|
|
23
28
|
## 🚀 快速开始
|
|
24
29
|
|
|
@@ -52,46 +57,65 @@ import { CommandResult, CommandStage } from '@ahoo-wang/fetcher-wow';
|
|
|
52
57
|
用于向 Wow 框架发送命令的 HTTP 客户端。该客户端提供了同步或流式接收命令结果的方法。
|
|
53
58
|
|
|
54
59
|
```typescript
|
|
55
|
-
import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
60
|
+
import { Fetcher, FetchExchange, RequestInterceptor, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
56
61
|
import '@ahoo-wang/fetcher-eventstream';
|
|
57
62
|
import {
|
|
58
63
|
CommandClient,
|
|
59
64
|
CommandRequest,
|
|
60
65
|
HttpMethod,
|
|
61
66
|
CommandHttpHeaders,
|
|
62
|
-
CommandStage
|
|
67
|
+
CommandStage
|
|
63
68
|
} from '@ahoo-wang/fetcher-wow';
|
|
64
69
|
import { idGenerator } from '@ahoo-wang/fetcher-cosec';
|
|
65
70
|
|
|
66
|
-
//
|
|
67
|
-
const
|
|
71
|
+
// 使用基础配置创建 fetcher 实例
|
|
72
|
+
const exampleFetcher = new Fetcher({
|
|
68
73
|
baseURL: 'http://localhost:8080/',
|
|
69
74
|
});
|
|
70
75
|
|
|
71
|
-
//
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
// 定义当前用户 ID
|
|
77
|
+
const currentUserId = idGenerator.generateId();
|
|
78
|
+
|
|
79
|
+
// 创建处理 URL 参数的拦截器
|
|
80
|
+
class AppendOwnerId implements RequestInterceptor {
|
|
81
|
+
readonly name: string = 'AppendOwnerId';
|
|
82
|
+
readonly order: number = URL_RESOLVE_INTERCEPTOR_ORDER - 1;
|
|
83
|
+
|
|
84
|
+
intercept(exchange: FetchExchange) {
|
|
77
85
|
exchange.request.urlParams = {
|
|
78
86
|
path: {
|
|
79
87
|
...exchange.request.urlParams?.path,
|
|
80
|
-
ownerId,
|
|
88
|
+
ownerId: currentUserId,
|
|
81
89
|
},
|
|
82
90
|
query: exchange.request.urlParams?.query,
|
|
83
91
|
};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 注册拦截器
|
|
96
|
+
exampleFetcher.interceptors.request.use(new AppendOwnerId());
|
|
86
97
|
|
|
87
98
|
// 创建命令客户端
|
|
88
|
-
const
|
|
89
|
-
fetcher:
|
|
99
|
+
const cartCommandClient = new CommandClient({
|
|
100
|
+
fetcher: exampleFetcher,
|
|
90
101
|
basePath: 'owner/{ownerId}/cart',
|
|
91
102
|
});
|
|
92
103
|
|
|
93
|
-
//
|
|
94
|
-
|
|
104
|
+
// 定义命令端点
|
|
105
|
+
class CartCommandEndpoints {
|
|
106
|
+
static readonly addCartItem = 'add_cart_item';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 定义命令接口
|
|
110
|
+
interface AddCartItem {
|
|
111
|
+
productId: string;
|
|
112
|
+
quantity: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type AddCartItemCommand = CommandRequest<AddCartItem>
|
|
116
|
+
|
|
117
|
+
// 创建命令请求
|
|
118
|
+
const addCartItemCommand: AddCartItemCommand = {
|
|
95
119
|
method: HttpMethod.POST,
|
|
96
120
|
headers: {
|
|
97
121
|
[CommandHttpHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
|
|
@@ -103,12 +127,15 @@ const command: CommandRequest = {
|
|
|
103
127
|
};
|
|
104
128
|
|
|
105
129
|
// 发送命令并等待结果
|
|
106
|
-
const commandResult = await
|
|
130
|
+
const commandResult = await cartCommandClient.send(
|
|
131
|
+
CartCommandEndpoints.addCartItem,
|
|
132
|
+
addCartItemCommand,
|
|
133
|
+
);
|
|
107
134
|
|
|
108
135
|
// 发送命令并接收流式结果
|
|
109
|
-
const commandResultStream = await
|
|
110
|
-
|
|
111
|
-
|
|
136
|
+
const commandResultStream = await cartCommandClient.sendAndWaitStream(
|
|
137
|
+
CartCommandEndpoints.addCartItem,
|
|
138
|
+
addCartItemCommand,
|
|
112
139
|
);
|
|
113
140
|
for await (const commandResultEvent of commandResultStream) {
|
|
114
141
|
console.log('收到命令结果:', commandResultEvent.data);
|
|
@@ -173,10 +200,10 @@ const dateConditions = [
|
|
|
173
200
|
|
|
174
201
|
#### SnapshotQueryClient
|
|
175
202
|
|
|
176
|
-
|
|
203
|
+
用于查询物化快照的客户端,支持全面的查询操作:
|
|
177
204
|
|
|
178
205
|
```typescript
|
|
179
|
-
import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
206
|
+
import { Fetcher, FetchExchange, RequestInterceptor, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
180
207
|
import '@ahoo-wang/fetcher-eventstream';
|
|
181
208
|
import {
|
|
182
209
|
SnapshotQueryClient,
|
|
@@ -192,59 +219,64 @@ interface CartItem {
|
|
|
192
219
|
quantity: number;
|
|
193
220
|
}
|
|
194
221
|
|
|
195
|
-
interface CartState {
|
|
196
|
-
id: string;
|
|
222
|
+
interface CartState extends Identifier {
|
|
197
223
|
items: CartItem[];
|
|
198
224
|
}
|
|
199
225
|
|
|
200
|
-
//
|
|
201
|
-
const
|
|
226
|
+
// 使用基础配置创建 fetcher 实例
|
|
227
|
+
const exampleFetcher = new Fetcher({
|
|
202
228
|
baseURL: 'http://localhost:8080/',
|
|
203
229
|
});
|
|
204
230
|
|
|
205
|
-
//
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
231
|
+
// 定义当前用户 ID
|
|
232
|
+
const currentUserId = idGenerator.generateId();
|
|
233
|
+
|
|
234
|
+
// 创建处理 URL 参数的拦截器
|
|
235
|
+
class AppendOwnerId implements RequestInterceptor {
|
|
236
|
+
readonly name: string = 'AppendOwnerId';
|
|
237
|
+
readonly order: number = URL_RESOLVE_INTERCEPTOR_ORDER - 1;
|
|
238
|
+
|
|
239
|
+
intercept(exchange: FetchExchange) {
|
|
211
240
|
exchange.request.urlParams = {
|
|
212
241
|
path: {
|
|
213
242
|
...exchange.request.urlParams?.path,
|
|
214
|
-
ownerId,
|
|
243
|
+
ownerId: currentUserId,
|
|
215
244
|
},
|
|
216
245
|
query: exchange.request.urlParams?.query,
|
|
217
246
|
};
|
|
218
|
-
}
|
|
219
|
-
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 注册拦截器
|
|
251
|
+
exampleFetcher.interceptors.request.use(new AppendOwnerId());
|
|
220
252
|
|
|
221
253
|
// 创建快照查询客户端
|
|
222
|
-
const
|
|
223
|
-
fetcher:
|
|
254
|
+
const cartSnapshotQueryClient = new SnapshotQueryClient<CartState>({
|
|
255
|
+
fetcher: exampleFetcher,
|
|
224
256
|
basePath: 'owner/{ownerId}/cart',
|
|
225
257
|
});
|
|
226
258
|
|
|
227
259
|
// 统计快照数量
|
|
228
|
-
const count = await
|
|
260
|
+
const count = await cartSnapshotQueryClient.count(all());
|
|
229
261
|
|
|
230
262
|
// 列出快照
|
|
231
263
|
const listQuery: ListQuery = {
|
|
232
264
|
condition: all(),
|
|
233
265
|
};
|
|
234
|
-
const list = await
|
|
266
|
+
const list = await cartSnapshotQueryClient.list(listQuery);
|
|
235
267
|
|
|
236
268
|
// 以流的形式列出快照
|
|
237
|
-
const listStream = await
|
|
269
|
+
const listStream = await cartSnapshotQueryClient.listStream(listQuery);
|
|
238
270
|
for await (const event of listStream) {
|
|
239
271
|
const snapshot = event.data;
|
|
240
272
|
console.log('收到快照:', snapshot);
|
|
241
273
|
}
|
|
242
274
|
|
|
243
275
|
// 列出快照状态
|
|
244
|
-
const stateList = await
|
|
276
|
+
const stateList = await cartSnapshotQueryClient.listState(listQuery);
|
|
245
277
|
|
|
246
278
|
// 以流的形式列出快照状态
|
|
247
|
-
const stateStream = await
|
|
279
|
+
const stateStream = await cartSnapshotQueryClient.listStateStream(listQuery);
|
|
248
280
|
for await (const event of stateStream) {
|
|
249
281
|
const state = event.data;
|
|
250
282
|
console.log('收到状态:', state);
|
|
@@ -254,27 +286,41 @@ for await (const event of stateStream) {
|
|
|
254
286
|
const pagedQuery: PagedQuery = {
|
|
255
287
|
condition: all(),
|
|
256
288
|
};
|
|
257
|
-
const paged = await
|
|
289
|
+
const paged = await cartSnapshotQueryClient.paged(pagedQuery);
|
|
258
290
|
|
|
259
291
|
// 分页查询快照状态
|
|
260
|
-
const pagedState = await
|
|
292
|
+
const pagedState = await cartSnapshotQueryClient.pagedState(pagedQuery);
|
|
261
293
|
|
|
262
294
|
// 查询单个快照
|
|
263
295
|
const singleQuery: SingleQuery = {
|
|
264
296
|
condition: all(),
|
|
265
297
|
};
|
|
266
|
-
const single = await
|
|
298
|
+
const single = await cartSnapshotQueryClient.single(singleQuery);
|
|
267
299
|
|
|
268
300
|
// 查询单个快照状态
|
|
269
|
-
const singleState = await
|
|
301
|
+
const singleState = await cartSnapshotQueryClient.singleState(singleQuery);
|
|
270
302
|
```
|
|
271
303
|
|
|
304
|
+
##### 方法
|
|
305
|
+
|
|
306
|
+
- `count(condition: Condition): Promise<number>` - 统计匹配给定条件的快照数量。
|
|
307
|
+
- `list(listQuery: ListQuery): Promise<Partial<MaterializedSnapshot<S>>[]>` - 检索物化快照列表。
|
|
308
|
+
- `listStream(listQuery: ListQuery): Promise<ReadableStream<JsonServerSentEvent<Partial<MaterializedSnapshot<S>>>>>` -
|
|
309
|
+
以服务器发送事件的形式检索物化快照流。
|
|
310
|
+
- `listState(listQuery: ListQuery): Promise<Partial<S>[]>` - 检索快照状态列表。
|
|
311
|
+
- `listStateStream(listQuery: ListQuery): Promise<ReadableStream<JsonServerSentEvent<Partial<S>>>>` -
|
|
312
|
+
以服务器发送事件的形式检索快照状态流。
|
|
313
|
+
- `paged(pagedQuery: PagedQuery): Promise<PagedList<Partial<MaterializedSnapshot<S>>>>` - 检索物化快照的分页列表。
|
|
314
|
+
- `pagedState(pagedQuery: PagedQuery): Promise<PagedList<Partial<S>>>` - 检索快照状态的分页列表。
|
|
315
|
+
- `single(singleQuery: SingleQuery): Promise<Partial<MaterializedSnapshot<S>>>` - 检索单个物化快照。
|
|
316
|
+
- `singleState(singleQuery: SingleQuery): Promise<Partial<S>>` - 检索单个快照状态。
|
|
317
|
+
|
|
272
318
|
#### EventStreamQueryClient
|
|
273
319
|
|
|
274
|
-
|
|
320
|
+
用于查询领域事件流的客户端,支持全面的查询操作:
|
|
275
321
|
|
|
276
322
|
```typescript
|
|
277
|
-
import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
323
|
+
import { Fetcher, FetchExchange, RequestInterceptor, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
278
324
|
import '@ahoo-wang/fetcher-eventstream';
|
|
279
325
|
import {
|
|
280
326
|
EventStreamQueryClient,
|
|
@@ -284,44 +330,50 @@ import {
|
|
|
284
330
|
} from '@ahoo-wang/fetcher-wow';
|
|
285
331
|
import { idGenerator } from '@ahoo-wang/fetcher-cosec';
|
|
286
332
|
|
|
287
|
-
//
|
|
288
|
-
const
|
|
333
|
+
// 使用基础配置创建 fetcher 实例
|
|
334
|
+
const exampleFetcher = new Fetcher({
|
|
289
335
|
baseURL: 'http://localhost:8080/',
|
|
290
336
|
});
|
|
291
337
|
|
|
292
|
-
//
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
338
|
+
// 定义当前用户 ID
|
|
339
|
+
const currentUserId = idGenerator.generateId();
|
|
340
|
+
|
|
341
|
+
// 创建处理 URL 参数的拦截器
|
|
342
|
+
class AppendOwnerId implements RequestInterceptor {
|
|
343
|
+
readonly name: string = 'AppendOwnerId';
|
|
344
|
+
readonly order: number = URL_RESOLVE_INTERCEPTOR_ORDER - 1;
|
|
345
|
+
|
|
346
|
+
intercept(exchange: FetchExchange) {
|
|
298
347
|
exchange.request.urlParams = {
|
|
299
348
|
path: {
|
|
300
349
|
...exchange.request.urlParams?.path,
|
|
301
|
-
ownerId,
|
|
350
|
+
ownerId: currentUserId,
|
|
302
351
|
},
|
|
303
352
|
query: exchange.request.urlParams?.query,
|
|
304
353
|
};
|
|
305
|
-
}
|
|
306
|
-
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// 注册拦截器
|
|
358
|
+
exampleFetcher.interceptors.request.use(new AppendOwnerId());
|
|
307
359
|
|
|
308
360
|
// 创建事件流查询客户端
|
|
309
|
-
const
|
|
310
|
-
fetcher:
|
|
361
|
+
const cartEventStreamQueryClient = new EventStreamQueryClient({
|
|
362
|
+
fetcher: exampleFetcher,
|
|
311
363
|
basePath: 'owner/{ownerId}/cart',
|
|
312
364
|
});
|
|
313
365
|
|
|
314
366
|
// 统计事件流数量
|
|
315
|
-
const count = await
|
|
367
|
+
const count = await cartEventStreamQueryClient.count(all());
|
|
316
368
|
|
|
317
369
|
// 列出事件流
|
|
318
370
|
const listQuery: ListQuery = {
|
|
319
371
|
condition: all(),
|
|
320
372
|
};
|
|
321
|
-
const list = await
|
|
373
|
+
const list = await cartEventStreamQueryClient.list(listQuery);
|
|
322
374
|
|
|
323
375
|
// 以流的形式列出事件流
|
|
324
|
-
const listStream = await
|
|
376
|
+
const listStream = await cartEventStreamQueryClient.listStream(listQuery);
|
|
325
377
|
for await (const event of listStream) {
|
|
326
378
|
const domainEventStream = event.data;
|
|
327
379
|
console.log('收到事件流:', domainEventStream);
|
|
@@ -331,15 +383,23 @@ for await (const event of listStream) {
|
|
|
331
383
|
const pagedQuery: PagedQuery = {
|
|
332
384
|
condition: all(),
|
|
333
385
|
};
|
|
334
|
-
const paged = await
|
|
386
|
+
const paged = await cartEventStreamQueryClient.paged(pagedQuery);
|
|
335
387
|
```
|
|
336
388
|
|
|
389
|
+
##### 方法
|
|
390
|
+
|
|
391
|
+
- `count(condition: Condition): Promise<number>` - 统计匹配给定条件的领域事件流数量。
|
|
392
|
+
- `list(listQuery: ListQuery): Promise<Partial<DomainEventStream>[]>` - 检索领域事件流列表。
|
|
393
|
+
- `listStream(listQuery: ListQuery): Promise<ReadableStream<JsonServerSentEvent<Partial<DomainEventStream>>>>` -
|
|
394
|
+
以服务器发送事件的形式检索领域事件流。
|
|
395
|
+
- `paged(pagedQuery: PagedQuery): Promise<PagedList<Partial<DomainEventStream>>>` - 检索领域事件流的分页列表。
|
|
396
|
+
|
|
337
397
|
## 🛠️ 高级用法
|
|
338
398
|
|
|
339
399
|
### 完整的命令和查询流程示例
|
|
340
400
|
|
|
341
401
|
```typescript
|
|
342
|
-
import { Fetcher, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
402
|
+
import { Fetcher, FetchExchange, RequestInterceptor, URL_RESOLVE_INTERCEPTOR_ORDER } from '@ahoo-wang/fetcher';
|
|
343
403
|
import '@ahoo-wang/fetcher-eventstream';
|
|
344
404
|
import {
|
|
345
405
|
CommandClient,
|
|
@@ -364,39 +424,58 @@ interface CartState {
|
|
|
364
424
|
}
|
|
365
425
|
|
|
366
426
|
// 创建 fetcher 实例
|
|
367
|
-
const
|
|
427
|
+
const exampleFetcher = new Fetcher({
|
|
368
428
|
baseURL: 'http://localhost:8080/',
|
|
369
429
|
});
|
|
370
430
|
|
|
371
|
-
//
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
431
|
+
// 定义当前用户 ID
|
|
432
|
+
const currentUserId = idGenerator.generateId();
|
|
433
|
+
|
|
434
|
+
// 创建处理 URL 参数的拦截器
|
|
435
|
+
class AppendOwnerId implements RequestInterceptor {
|
|
436
|
+
readonly name: string = 'AppendOwnerId';
|
|
437
|
+
readonly order: number = URL_RESOLVE_INTERCEPTOR_ORDER - 1;
|
|
438
|
+
|
|
439
|
+
intercept(exchange: FetchExchange) {
|
|
377
440
|
exchange.request.urlParams = {
|
|
378
441
|
path: {
|
|
379
442
|
...exchange.request.urlParams?.path,
|
|
380
|
-
ownerId,
|
|
443
|
+
ownerId: currentUserId,
|
|
381
444
|
},
|
|
382
445
|
query: exchange.request.urlParams?.query,
|
|
383
446
|
};
|
|
384
|
-
}
|
|
385
|
-
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// 注册拦截器
|
|
451
|
+
exampleFetcher.interceptors.request.use(new AppendOwnerId());
|
|
386
452
|
|
|
387
453
|
// 创建客户端
|
|
388
|
-
const
|
|
389
|
-
fetcher:
|
|
454
|
+
const cartCommandClient = new CommandClient({
|
|
455
|
+
fetcher: exampleFetcher,
|
|
390
456
|
basePath: 'owner/{ownerId}/cart',
|
|
391
457
|
});
|
|
392
458
|
|
|
393
|
-
const
|
|
394
|
-
fetcher:
|
|
459
|
+
const cartSnapshotQueryClient = new SnapshotQueryClient<CartState>({
|
|
460
|
+
fetcher: exampleFetcher,
|
|
395
461
|
basePath: 'owner/{ownerId}/cart',
|
|
396
462
|
});
|
|
397
463
|
|
|
464
|
+
// 定义命令端点
|
|
465
|
+
class CartCommandEndpoints {
|
|
466
|
+
static readonly addCartItem = 'add_cart_item';
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 定义命令接口
|
|
470
|
+
interface AddCartItem {
|
|
471
|
+
productId: string;
|
|
472
|
+
quantity: number;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
type AddCartItemCommand = CommandRequest<AddCartItem>
|
|
476
|
+
|
|
398
477
|
// 1. 发送命令添加商品到购物车
|
|
399
|
-
const addItemCommand:
|
|
478
|
+
const addItemCommand: AddCartItemCommand = {
|
|
400
479
|
method: HttpMethod.POST,
|
|
401
480
|
headers: {
|
|
402
481
|
[CommandHttpHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
|
|
@@ -407,21 +486,24 @@ const addItemCommand: CommandRequest = {
|
|
|
407
486
|
},
|
|
408
487
|
};
|
|
409
488
|
|
|
410
|
-
const commandResult = await
|
|
489
|
+
const commandResult = await cartCommandClient.send(
|
|
490
|
+
CartCommandEndpoints.addCartItem,
|
|
491
|
+
addItemCommand
|
|
492
|
+
);
|
|
411
493
|
console.log('命令执行完成:', commandResult);
|
|
412
494
|
|
|
413
495
|
// 2. 查询更新后的购物车
|
|
414
496
|
const listQuery: ListQuery = {
|
|
415
497
|
condition: all(),
|
|
416
498
|
};
|
|
417
|
-
const carts = await
|
|
499
|
+
const carts = await cartSnapshotQueryClient.list(listQuery);
|
|
418
500
|
|
|
419
501
|
for (const cart of carts) {
|
|
420
502
|
console.log('购物车:', cart.state);
|
|
421
503
|
}
|
|
422
504
|
|
|
423
505
|
// 3. 流式监听购物车更新
|
|
424
|
-
const listStream = await
|
|
506
|
+
const listStream = await cartSnapshotQueryClient.listStream(listQuery);
|
|
425
507
|
for await (const event of listStream) {
|
|
426
508
|
const cart = event.data;
|
|
427
509
|
console.log('购物车更新:', cart.state);
|
|
@@ -451,4 +533,4 @@ Apache-2.0
|
|
|
451
533
|
|
|
452
534
|
<p align="center">
|
|
453
535
|
<a href="https://github.com/Ahoo-Wang/fetcher">Fetcher</a> 生态系统的一部分
|
|
454
|
-
</p>
|
|
536
|
+
</p>
|
|
@@ -1,73 +1,51 @@
|
|
|
1
|
+
import { ClientOptions } from '../types';
|
|
2
|
+
import { CommandRequest } from './commandRequest';
|
|
1
3
|
import { CommandResult, CommandResultEventStream } from './commandResult';
|
|
2
4
|
import { ResultExtractor } from '@ahoo-wang/fetcher-decorator';
|
|
3
|
-
import { CommandRequest } from './commandRequest';
|
|
4
|
-
import { ClientOptions } from '../types';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Command Client for sending commands to the server.
|
|
7
|
+
*
|
|
8
|
+
* The CommandClient is responsible for sending commands to the server and handling the responses.
|
|
9
|
+
* It provides methods for both regular command execution and streaming command results.
|
|
9
10
|
*
|
|
10
11
|
* @example
|
|
11
12
|
* ```typescript
|
|
12
|
-
* // Create a
|
|
13
|
-
* const
|
|
14
|
-
* baseURL: 'http://localhost:8080/',
|
|
15
|
-
* }
|
|
13
|
+
* // Create a client options configuration
|
|
14
|
+
* const clientOptions: ClientOptions = {
|
|
15
|
+
* fetcher: new Fetcher({ baseURL: 'http://localhost:8080/' }),
|
|
16
|
+
* basePath: 'owner/{ownerId}/cart'
|
|
17
|
+
* };
|
|
16
18
|
*
|
|
17
|
-
* //
|
|
18
|
-
*
|
|
19
|
-
* name: 'UrlParamsInterceptor',
|
|
20
|
-
* order: URL_RESOLVE_INTERCEPTOR_ORDER - 1,
|
|
21
|
-
* intercept(exchange) {
|
|
22
|
-
* exchange.request.urlParams = {
|
|
23
|
-
* path: {
|
|
24
|
-
* ...exchange.request.urlParams?.path,
|
|
25
|
-
* },
|
|
26
|
-
* query: exchange.request.urlParams?.query,
|
|
27
|
-
* };
|
|
28
|
-
* },
|
|
29
|
-
* });
|
|
19
|
+
* // Create a command client instance
|
|
20
|
+
* const commandClient = new CommandClient(clientOptions);
|
|
30
21
|
*
|
|
31
|
-
* //
|
|
32
|
-
* const
|
|
33
|
-
* fetcher: wowFetcher,
|
|
34
|
-
* basePath: 'owner/{ownerId}/cart'
|
|
35
|
-
* });
|
|
22
|
+
* // Define command endpoint
|
|
23
|
+
* const addCartItem = 'add_cart_item';
|
|
36
24
|
*
|
|
37
|
-
* //
|
|
38
|
-
* const
|
|
25
|
+
* // Create a command request
|
|
26
|
+
* const addCartItemCommand: CommandRequest<AddCartItem> = {
|
|
39
27
|
* method: HttpMethod.POST,
|
|
40
28
|
* headers: {
|
|
41
|
-
* [
|
|
42
|
-
* },
|
|
43
|
-
* urlParams: {
|
|
44
|
-
* path: {
|
|
45
|
-
* ownerId: 'ownerId',
|
|
46
|
-
* },
|
|
29
|
+
* [CommandHttpHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
|
|
47
30
|
* },
|
|
48
31
|
* body: {
|
|
49
32
|
* productId: 'productId',
|
|
50
33
|
* quantity: 1,
|
|
51
|
-
* }
|
|
34
|
+
* }
|
|
52
35
|
* };
|
|
53
36
|
*
|
|
54
|
-
*
|
|
37
|
+
* // Send command and get result
|
|
38
|
+
* const commandResult = await commandClient.send(addCartItem, addCartItemCommand);
|
|
39
|
+
*
|
|
40
|
+
* // Send command and get result as stream
|
|
41
|
+
* const commandResultStream = await commandClient.sendAndWaitStream(addCartItem, addCartItemCommand);
|
|
42
|
+
* for await (const commandResultEvent of commandResultStream) {
|
|
43
|
+
* console.log('Received:', commandResultEvent.data);
|
|
44
|
+
* }
|
|
55
45
|
* ```
|
|
56
46
|
*/
|
|
57
47
|
export declare class CommandClient {
|
|
58
48
|
protected readonly options: ClientOptions;
|
|
59
|
-
/**
|
|
60
|
-
* Creates a new CommandClient instance.
|
|
61
|
-
* @param options - The client configuration options including the fetcher and base path
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* ```typescript
|
|
65
|
-
* const CommandClient = new CommandClient({
|
|
66
|
-
* fetcher: wowFetcher,
|
|
67
|
-
* basePath: 'owner/{ownerId}/cart'
|
|
68
|
-
* });
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
49
|
constructor(options: ClientOptions);
|
|
72
50
|
/**
|
|
73
51
|
* Sends a command to the specified path and returns the result.
|
|
@@ -80,64 +58,47 @@ export declare class CommandClient {
|
|
|
80
58
|
*/
|
|
81
59
|
protected sendCommand<R>(path: string, commandHttpRequest: CommandRequest, extractor?: ResultExtractor): Promise<R>;
|
|
82
60
|
/**
|
|
83
|
-
*
|
|
61
|
+
* Send a command to the server and wait for the result.
|
|
84
62
|
*
|
|
85
63
|
* @param path - The endpoint path to send the command to
|
|
86
|
-
* @param commandHttpRequest - The command
|
|
87
|
-
* @returns A promise that resolves to
|
|
64
|
+
* @param commandHttpRequest - The command request to send
|
|
65
|
+
* @returns A promise that resolves to the command execution result
|
|
88
66
|
*
|
|
89
67
|
* @example
|
|
90
68
|
* ```typescript
|
|
91
|
-
* const
|
|
69
|
+
* const commandResult = await commandClient.send('add_cart_item', {
|
|
92
70
|
* method: HttpMethod.POST,
|
|
93
|
-
* headers: {
|
|
94
|
-
* [CommandHeaders.WAIT_STAGE]: CommandStage.SNAPSHOT,
|
|
95
|
-
* },
|
|
96
|
-
* urlParams: {
|
|
97
|
-
* path: {
|
|
98
|
-
* ownerId: 'ownerId',
|
|
99
|
-
* },
|
|
100
|
-
* },
|
|
101
71
|
* body: {
|
|
102
|
-
* productId: '
|
|
103
|
-
* quantity:
|
|
104
|
-
* }
|
|
105
|
-
* };
|
|
106
|
-
*
|
|
107
|
-
* const result = await CommandClient.send('add_cart_item', command);
|
|
108
|
-
* console.log('Command result:', result);
|
|
72
|
+
* productId: 'product-1',
|
|
73
|
+
* quantity: 2
|
|
74
|
+
* }
|
|
75
|
+
* });
|
|
109
76
|
* ```
|
|
110
77
|
*/
|
|
111
78
|
send(path: string, commandHttpRequest: CommandRequest): Promise<CommandResult>;
|
|
112
79
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
80
|
+
* Send a command to the server and wait for the result as a stream.
|
|
81
|
+
* This is useful for long-running commands that produce multiple events.
|
|
115
82
|
*
|
|
116
83
|
* @param path - The endpoint path to send the command to
|
|
117
|
-
* @param commandHttpRequest - The command
|
|
118
|
-
* @returns A promise that resolves to a
|
|
84
|
+
* @param commandHttpRequest - The command request to send
|
|
85
|
+
* @returns A promise that resolves to a stream of command execution results
|
|
119
86
|
*
|
|
120
87
|
* @example
|
|
121
88
|
* ```typescript
|
|
122
|
-
* const
|
|
89
|
+
* const commandResultStream = await commandClient.sendAndWaitStream('add_cart_item', {
|
|
123
90
|
* method: HttpMethod.POST,
|
|
124
91
|
* headers: {
|
|
125
|
-
*
|
|
126
|
-
* },
|
|
127
|
-
* urlParams: {
|
|
128
|
-
* path: {
|
|
129
|
-
* ownerId: 'ownerId',
|
|
130
|
-
* },
|
|
92
|
+
* Accept: ContentTypeValues.TEXT_EVENT_STREAM
|
|
131
93
|
* },
|
|
132
94
|
* body: {
|
|
133
|
-
* productId: '
|
|
134
|
-
* quantity:
|
|
135
|
-
* }
|
|
136
|
-
* };
|
|
95
|
+
* productId: 'product-1',
|
|
96
|
+
* quantity: 2
|
|
97
|
+
* }
|
|
98
|
+
* });
|
|
137
99
|
*
|
|
138
|
-
* const commandResultStream = await CommandClient.sendAndWaitStream('add_cart_item', command);
|
|
139
100
|
* for await (const commandResultEvent of commandResultStream) {
|
|
140
|
-
* console.log('Received:', commandResultEvent.data);
|
|
101
|
+
* console.log('Received event:', commandResultEvent.data);
|
|
141
102
|
* }
|
|
142
103
|
* ```
|
|
143
104
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandClient.d.ts","sourceRoot":"","sources":["../../src/command/commandClient.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commandClient.d.ts","sourceRoot":"","sources":["../../src/command/commandClient.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAoB,MAAM,8BAA8B,CAAC;AAGjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,aAAa;IACZ,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa;gBAAtB,OAAO,EAAE,aAAa;IAGrD;;;;;;;;OAQG;cACa,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,MAAM,EACZ,kBAAkB,EAAE,cAAc,EAClC,SAAS,GAAE,eAAuC,GACjD,OAAO,CAAC,CAAC,CAAC;IAUb;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,kBAAkB,EAAE,cAAc,GACjC,OAAO,CAAC,aAAa,CAAC;IAIzB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,kBAAkB,EAAE,cAAc,GACjC,OAAO,CAAC,wBAAwB,CAAC;CAWrC"}
|