@@ -7,15 +7,21 @@ import type {
77} from "@cosense/types/rest" ;
88import { type BaseOptions , setDefaults } from "../../util.ts" ;
99import { 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" ;
1114import {
1215 type HTTPError ,
1316 makeError ,
1417 makeHTTPError ,
1518 type TypedError ,
1619} 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" ;
1723
18- /** Options for {@linkcode listPages } */
24+ /** Options for {@linkcode get } */
1925export interface ListPagesOption < R extends Response | undefined >
2026 extends BaseOptions < R > {
2127 /** the sort of page list to return
@@ -100,6 +106,16 @@ export const get = <R extends Response | undefined = Response>(
100106 } , R >
101107 > ;
102108
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+
103119/**
104120 * Lists pages from a given `project` with pagination
105121 *
@@ -109,31 +125,59 @@ export const get = <R extends Response | undefined = Response>(
109125 */
110126export async function * list (
111127 project : string ,
112- options ?: ListPagesOption < Response > ,
128+ options ?: ListPagesStreamOption < Response > ,
113129) : 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+ > ;
130176 }
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 ;
135179 }
136- }
180+ } ;
137181
138182export * as replace from "./project/replace.ts" ;
139183export * as search from "./project/search.ts" ;
0 commit comments