@@ -7,15 +7,21 @@ import type {
7
7
} from "@cosense/types/rest" ;
8
8
import { type BaseOptions , setDefaults } from "../../util.ts" ;
9
9
import { cookie } from "../../rest/auth.ts" ;
10
- import type { ResponseOfEndpoint } from "../../targeted_response.ts" ;
10
+ import type {
11
+ ResponseOfEndpoint ,
12
+ TargetedResponse ,
13
+ } from "../../targeted_response.ts" ;
11
14
import {
12
15
type HTTPError ,
13
16
makeError ,
14
17
makeHTTPError ,
15
18
type TypedError ,
16
19
} from "../../error.ts" ;
20
+ import { pooledMap } from "@std/async/pool" ;
21
+ import { range } from "@core/iterutil/range" ;
22
+ import { flatten } from "@core/iterutil/async/flatten" ;
17
23
18
- /** Options for {@linkcode listPages } */
24
+ /** Options for {@linkcode get } */
19
25
export interface ListPagesOption < R extends Response | undefined >
20
26
extends BaseOptions < R > {
21
27
/** the sort of page list to return
@@ -100,6 +106,16 @@ export const get = <R extends Response | undefined = Response>(
100
106
} , R >
101
107
> ;
102
108
109
+ /** Options for {@linkcode list} */
110
+ export interface ListPagesStreamOption < R extends Response | undefined >
111
+ extends ListPagesOption < R > {
112
+ /** The number of requests to make concurrently
113
+ *
114
+ * @default {3}
115
+ */
116
+ poolLimit ?: number ;
117
+ }
118
+
103
119
/**
104
120
* Lists pages from a given `project` with pagination
105
121
*
@@ -109,31 +125,59 @@ export const get = <R extends Response | undefined = Response>(
109
125
*/
110
126
export async function * list (
111
127
project : string ,
112
- options ?: ListPagesOption < Response > ,
128
+ options ?: ListPagesStreamOption < Response > ,
113
129
) : AsyncGenerator < BasePage , void , unknown > {
114
- const props = { ...( options ?? { } ) , skip : options ?. skip ?? 0 } ;
115
- while ( true ) {
116
- const response = await get ( project , props ) ;
117
- switch ( response . status ) {
118
- case 200 :
119
- break ;
120
- case 401 :
121
- case 403 :
122
- case 404 : {
123
- const error = await response . json ( ) ;
124
- throw makeError ( error . name , error . message ) satisfies TypedError <
125
- "NotLoggedInError" | "NotMemberError" | "NotFoundError"
126
- > ;
127
- }
128
- default :
129
- throw makeHTTPError ( response ) satisfies HTTPError ;
130
+ const props = {
131
+ ...( options ?? { } ) ,
132
+ skip : options ?. skip ?? 0 ,
133
+ limit : options ?. limit ?? 100 ,
134
+ } ;
135
+ const response = await ensureResponse ( await get ( project , props ) ) ;
136
+ const list = await response . json ( ) ;
137
+ yield * list . pages ;
138
+
139
+ const limit = list . limit ;
140
+ const skip = list . skip + limit ;
141
+ const times = Math . ceil ( ( list . count - skip ) / limit ) ;
142
+
143
+ yield * flatten (
144
+ pooledMap (
145
+ options ?. poolLimit ?? 3 ,
146
+ range ( 0 , times - 1 ) ,
147
+ async ( i ) => {
148
+ const response = await ensureResponse (
149
+ await get ( project , { ...props , skip : skip + i * limit , limit } ) ,
150
+ ) ;
151
+ const list = await response . json ( ) ;
152
+ return list . pages ;
153
+ } ,
154
+ ) ,
155
+ ) ;
156
+ }
157
+
158
+ const ensureResponse = async (
159
+ response : ResponseOfEndpoint < {
160
+ 200 : PageList ;
161
+ 404 : NotFoundError ;
162
+ 401 : NotLoggedInError ;
163
+ 403 : NotMemberError ;
164
+ } , Response > ,
165
+ ) : Promise < TargetedResponse < 200 , PageList > > => {
166
+ switch ( response . status ) {
167
+ case 200 :
168
+ return response ;
169
+ case 401 :
170
+ case 403 :
171
+ case 404 : {
172
+ const error = await response . json ( ) ;
173
+ throw makeError ( error . name , error . message ) satisfies TypedError <
174
+ "NotLoggedInError" | "NotMemberError" | "NotFoundError"
175
+ > ;
130
176
}
131
- const list = await response . json ( ) ;
132
- yield * list . pages ;
133
- props . skip += props . limit ?? 100 ;
134
- if ( list . skip + list . limit >= list . count ) break ;
177
+ default :
178
+ throw makeHTTPError ( response ) satisfies HTTPError ;
135
179
}
136
- }
180
+ } ;
137
181
138
182
export * as replace from "./project/replace.ts" ;
139
183
export * as search from "./project/search.ts" ;
0 commit comments