@@ -41,10 +41,10 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
41
41
*
42
42
* GET Django list from this API
43
43
*
44
- * @param {Boolean = } paginated - Treat this API result like a paginated one (i.e., it contains 'next', 'prev', etc.)
44
+ * @param {boolean = } paginated - Treat this API result like a paginated one (i.e., it contains 'next', 'prev', etc.)
45
45
* @param {TypeFilters= } filters - Filters to send with request
46
46
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
47
- * @return {ApiResponse } Api response object
47
+ * @return {ApiResponse<Model[]> } Api response object
48
48
*/
49
49
public async getList (
50
50
paginated : boolean = true ,
@@ -60,16 +60,16 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
60
60
}
61
61
62
62
/**
63
- * getList
63
+ * getListAll
64
64
*
65
65
* GET Django list from this API for ALL pages if paginated
66
66
*
67
67
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
68
- * @returns {Array } List of all objects paginated out
68
+ * @returns {Model[] } List of all objects paginated out
69
69
*/
70
70
public async getListAll ( extraHeaders ?: Record < string , unknown > ) : Promise < Model [ ] > {
71
71
this . loading = true
72
- let res = [ ]
72
+ let res : Model [ ] = [ ]
73
73
const first = await this . getList ( true , undefined , extraHeaders )
74
74
res = first . obj ?? [ ]
75
75
let pages = 1
@@ -78,10 +78,8 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
78
78
const nextPage = await this . getNext ( )
79
79
if ( typeof nextPage !== 'undefined' ) {
80
80
const nextList = nextPage . obj
81
- if ( ! ! nextList && nextList . length > 0 ) {
82
- nextList . map ( function ( i : Model ) {
83
- return res . push ( i )
84
- } )
81
+ if ( nextList && nextList . length > 0 ) {
82
+ nextList . map ( ( i : Model ) => res . push ( i ) )
85
83
}
86
84
}
87
85
}
@@ -95,11 +93,11 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
95
93
*
96
94
* Django GET item and details
97
95
*
98
- * @param {string= } id - ID of object to retrieve
99
- * @param {Boolean = } paginated - Treat this API result like a paginated one (i.e., it contains 'next', 'prev', etc.)
96
+ * @param {string } id - ID of object to retrieve
97
+ * @param {boolean = } paginated - Treat this API result like a paginated one (i.e., it contains 'next', 'prev', etc.)
100
98
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
101
99
* @param {TypeFilters= } filters - Filters to send with request
102
- * @return {ApiResponse } Api response object
100
+ * @return {ApiResponse<Model | Model[]> } Api response object
103
101
*/
104
102
public async getRetrieve (
105
103
id : string ,
@@ -118,18 +116,23 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
118
116
/**
119
117
* handleDjangoGet
120
118
*
121
- * @param ApiResponse
122
- * @param paginated
123
- * @returns ApiResponse
119
+ * Helper function to handle the response from a GET request.
120
+ *
121
+ * @param {ApiResponse<Model | Model[]> } apiResponse - API response object
122
+ * @param {boolean } paginated - Whether the response is paginated
123
+ * @returns {Promise<ApiResponse<Model | Model[]>> } Api response object
124
124
*/
125
- protected async handleDjangoGet ( apiResponse : ApiResponse < Model | Model [ ] > , paginated : boolean ) : Promise < ApiResponse < Model | Model [ ] > > {
126
- // handle duplicate response
125
+ protected async handleDjangoGet (
126
+ apiResponse : ApiResponse < Model | Model [ ] > ,
127
+ paginated : boolean
128
+ ) : Promise < ApiResponse < Model | Model [ ] > > {
129
+ // Handle duplicate response
127
130
if ( apiResponse . duplicate ) {
128
131
return apiResponse
129
132
}
130
133
131
- // helper function to clean up get and retrieve methods
132
134
if ( ! paginated ) {
135
+ // Non-paginated response
133
136
try {
134
137
if ( apiResponse . obj instanceof Array ) {
135
138
this . list = apiResponse . obj
@@ -141,10 +144,11 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
141
144
}
142
145
return apiResponse
143
146
} else {
147
+ // Paginated response
144
148
try {
145
149
this . count = ( apiResponse . response . data as { count : number } ) . count
146
150
this . list = ( apiResponse . obj as Model [ ] ) ?? [ ]
147
- this . calculatePageTotal ( ) // this should only be called during the initial call NOT during any next/prev calls
151
+ this . calculatePageTotal ( ) // This should only be called during the initial call NOT during any next/prev calls
148
152
} catch ( e ) {
149
153
console . warn ( e )
150
154
}
@@ -160,10 +164,13 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
160
164
* this API data
161
165
*
162
166
* @param {ApiResponse<Model[]> } apiResponse - Api response object
163
- * @param {Boolean = } combineLists - Whether to add next page to the current list or replace it
164
- * @return {ApiResponse } Api response object
167
+ * @param {boolean = } combineLists - Whether to add next page to the current list or replace it
168
+ * @return {ApiResponse<Model[]> } Api response object
165
169
*/
166
- protected async handlePaginatedResponse ( apiResponse : ApiResponse < Model [ ] > , combineLists : boolean = false ) : Promise < ApiResponse < Model [ ] > > {
170
+ protected async handlePaginatedResponse (
171
+ apiResponse : ApiResponse < Model [ ] > ,
172
+ combineLists : boolean = false
173
+ ) : Promise < ApiResponse < Model [ ] > > {
167
174
try {
168
175
const responseData = apiResponse . response . data as { count : number , next : string , previous : string }
169
176
if ( responseData ) {
@@ -175,13 +182,13 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
175
182
if ( ! combineLists ) {
176
183
this . list = apiResponse . obj ?? [ ]
177
184
} else {
178
- if ( ! ! this . list && this . list . length > 0 ) {
185
+ if ( this . list && this . list . length > 0 ) {
179
186
this . list = [ ...this . list , ...( apiResponse . obj ?? [ ] ) ]
180
187
} else {
181
188
this . list = apiResponse . obj ?? [ ]
182
189
}
183
190
}
184
- this . calculatePageCurrent ( )
191
+ this . calculatePageCurrent ( ) // Update current page number based on 'next' and 'prev'
185
192
} catch ( e ) {
186
193
console . error ( e )
187
194
}
@@ -191,17 +198,27 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
191
198
/**
192
199
* getNext
193
200
*
194
- * @param {Boolean= } combineLists - Whether to add next page to the current list or replace it
201
+ * Get the next page of results.
202
+ *
203
+ * @param {boolean= } combineLists - Whether to add next page to the current list or replace it
195
204
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
196
- * @return {ApiResponse } Api response object
205
+ * @return {ApiResponse<Model[]> | undefined } Api response object
197
206
*/
198
- public async getNext ( combineLists : boolean = false , extraHeaders ?: Record < string , unknown > ) : Promise < ApiResponse < Model [ ] > | undefined > {
207
+ public async getNext (
208
+ combineLists : boolean = false ,
209
+ extraHeaders ?: Record < string , unknown >
210
+ ) : Promise < ApiResponse < Model [ ] > | undefined > {
199
211
this . loading = true
200
- if ( typeof this . next !== 'undefined' ) {
212
+ if ( typeof this . next !== 'undefined' && this . next !== null ) {
201
213
const apiResponse = await this . httpGet ( this . next , extraHeaders )
214
+ if ( apiResponse . duplicate ) {
215
+ this . loading = false
216
+ return apiResponse as ApiResponse < Model [ ] >
217
+ }
218
+
202
219
if ( apiResponse . obj instanceof Array ) {
203
- // If the response is a list, return it as-is
204
220
const response = await this . handlePaginatedResponse ( apiResponse as ApiResponse < Model [ ] > , combineLists )
221
+ this . pageCurrent += 1 // Increment current page
205
222
this . loading = false
206
223
return response
207
224
} else {
@@ -215,17 +232,27 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
215
232
/**
216
233
* getPrev
217
234
*
218
- * @param {Boolean= } combineLists - Whether to add next page to the current list or replace it
235
+ * Get the previous page of results.
236
+ *
237
+ * @param {boolean= } combineLists - Whether to add previous page to the current list or replace it
219
238
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
220
- * @return {ApiResponse } Api response object
239
+ * @return {ApiResponse<Model[]> | undefined } Api response object
221
240
*/
222
- public async getPrev ( combineLists : boolean = false , extraHeaders ?: Record < string , unknown > ) : Promise < ApiResponse < Model [ ] > | undefined > {
241
+ public async getPrev (
242
+ combineLists : boolean = false ,
243
+ extraHeaders ?: Record < string , unknown >
244
+ ) : Promise < ApiResponse < Model [ ] > | undefined > {
223
245
this . loading = true
224
- if ( typeof this . prev !== 'undefined' ) {
246
+ if ( typeof this . prev !== 'undefined' && this . prev !== null ) {
225
247
const apiResponse = await this . httpGet ( this . prev , extraHeaders )
248
+ if ( apiResponse . duplicate ) {
249
+ this . loading = false
250
+ return apiResponse as ApiResponse < Model [ ] >
251
+ }
252
+
226
253
if ( apiResponse . obj instanceof Array ) {
227
- // If the response is a list, return it as-is
228
254
const response = await this . handlePaginatedResponse ( apiResponse as ApiResponse < Model [ ] > , combineLists )
255
+ this . pageCurrent -= 1 // Decrement current page
229
256
this . loading = false
230
257
return response
231
258
} else {
@@ -239,26 +266,34 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
239
266
/**
240
267
* getPage
241
268
*
242
- * @param {Number } page - Specific page number to retrieve
269
+ * Get a specific page of results.
270
+ *
271
+ * @param {number } page - Specific page number to retrieve
243
272
* @param {Record<string, unknown>= } extraHeaders - Extra headers to add to request
244
- * @return {ApiResponse } Api response object
273
+ * @return {ApiResponse<Model[]> } Api response object
245
274
*/
246
-
247
275
public async getPage ( page : number , extraHeaders ?: Record < string , unknown > ) : Promise < ApiResponse < Model [ ] > > {
248
276
this . loading = true
249
277
const pageUrl = `${ this . urlApi ( ) } ?page=${ page } `
250
278
const apiResponse = await this . httpGet ( pageUrl , extraHeaders )
251
279
252
- if ( apiResponse . obj instanceof Array ) {
253
- // If the response is a list, return it as-is
280
+ if ( apiResponse . duplicate ) {
254
281
this . loading = false
255
282
return apiResponse as ApiResponse < Model [ ] >
283
+ }
284
+
285
+ if ( apiResponse . obj instanceof Array ) {
286
+ const response = await this . handlePaginatedResponse ( apiResponse as ApiResponse < Model [ ] > )
287
+ this . pageCurrent = page // Set the current page here
288
+ this . loading = false
289
+ return response
256
290
} else {
257
291
// If the response is not a list, wrap the result in an array
258
292
const response : ApiResponse < Model [ ] > = {
259
293
...apiResponse ,
260
294
obj : [ apiResponse . obj as Model ]
261
295
}
296
+ this . pageCurrent = page // Set the current page here
262
297
this . loading = false
263
298
return response
264
299
}
@@ -267,25 +302,57 @@ export default class DjangoGet<Model, TypeFilters extends object | null = null>
267
302
/**
268
303
* PAGINATION HELPERS
269
304
*/
305
+
306
+ /**
307
+ * calculatePageCurrent
308
+ *
309
+ * Calculate the current page number based on 'next' and 'prev' URLs.
310
+ */
270
311
protected calculatePageCurrent ( ) : void {
271
- if ( typeof this . next !== 'undefined' && this . next != null ) {
272
- const num = Number ( this . getQueryString ( 'page' , this . next ) ) || 2
273
- this . pageCurrent = num - 1
274
- } else if ( typeof this . prev !== 'undefined' && this . prev != null ) {
275
- const num = Number ( this . getQueryString ( 'page' , this . prev ) ) || 0
276
- this . pageCurrent = num + 1
312
+ if ( this . next ) {
313
+ const num = Number ( this . getQueryStringValue ( 'page' , this . next ) )
314
+ if ( ! isNaN ( num ) ) {
315
+ this . pageCurrent = num - 1
316
+ }
317
+ } else if ( this . prev ) {
318
+ const num = Number ( this . getQueryStringValue ( 'page' , this . prev ) )
319
+ if ( ! isNaN ( num ) ) {
320
+ this . pageCurrent = num + 1
321
+ }
322
+ } else {
323
+ // If both next and prev are null, we're on the first or last page
324
+ if ( this . pageCurrent === undefined || this . pageCurrent === null ) {
325
+ this . pageCurrent = 1 // Default to page 1
326
+ }
277
327
}
278
328
}
279
329
330
+ /**
331
+ * getQueryStringValue
332
+ *
333
+ * Extracts the value of a query parameter from a URL.
334
+ *
335
+ * @param {string } field - The name of the query parameter to extract.
336
+ * @param {string } url - The URL to parse.
337
+ * @return {string | null } The value of the query parameter, or null if not found.
338
+ */
339
+ protected getQueryStringValue ( field : string , url : string ) : number {
340
+ // Parse the URL to extract the query parameter
341
+ const reg = new RegExp ( `[?&]${ field } =([^&#]*)` , 'i' )
342
+ const string = reg . exec ( url )
343
+ return string ? Number ( string [ 1 ] ) : NaN
344
+ }
345
+
346
+ /**
347
+ * calculatePageTotal
348
+ *
349
+ * Calculate the total number of pages.
350
+ */
280
351
protected calculatePageTotal ( ) : void {
281
- if ( typeof this . list !== 'undefined' ) {
282
- if ( this . list ?. length > 0 && typeof this . count !== 'undefined' ) {
283
- let pageTotal = Math . floor ( this . count / this . list ?. length )
284
- const remainder = this . count % this . list ?. length
285
- if ( remainder !== 0 ) {
286
- pageTotal ++
287
- }
288
- this . pageTotal = pageTotal
352
+ if ( this . list && this . count !== undefined ) {
353
+ const itemsPerPage = this . list . length
354
+ if ( itemsPerPage > 0 ) {
355
+ this . pageTotal = Math . ceil ( this . count / itemsPerPage )
289
356
}
290
357
}
291
358
}
0 commit comments