@@ -16,8 +16,8 @@ import org.genspectrum.lapis.request.NucleotideMutation
16
16
import org.genspectrum.lapis.request.OrderByField
17
17
import org.genspectrum.lapis.request.SequenceFiltersRequestWithFields
18
18
import org.genspectrum.lapis.response.AggregationData
19
+ import org.genspectrum.lapis.response.DetailsData
19
20
import org.genspectrum.lapis.response.MutationData
20
- import org.genspectrum.lapis.silo.DetailsData
21
21
import org.springframework.http.MediaType
22
22
import org.springframework.web.bind.annotation.GetMapping
23
23
import org.springframework.web.bind.annotation.PostMapping
@@ -39,10 +39,16 @@ const val LIMIT_SCHEMA = "Limit"
39
39
const val OFFSET_SCHEMA = " Offset"
40
40
41
41
const val DETAILS_ENDPOINT_DESCRIPTION = " Returns the specified metadata fields of sequences matching the filter."
42
+ const val AGGREGATED_ENDPONT_DESCRIPTION = " Returns the number of sequences matching the specified sequence filters"
42
43
const val AGGREGATED_GROUP_BY_FIELDS_DESCRIPTION =
43
44
" The fields to stratify by. If empty, only the overall count is returned"
45
+ const val AGGREGATED_ORDER_BY_FIELDS_DESCRIPTION =
46
+ " The fields of the response to order by." +
47
+ " Fields specified here must either be \" count\" or also be present in \" fields\" ."
44
48
const val DETAILS_FIELDS_DESCRIPTION =
45
49
" The fields that the response items should contain. If empty, all fields are returned"
50
+ const val DETAILS_ORDER_BY_FIELDS_DESCRIPTION =
51
+ " The fields of the response to order by. Fields specified here must also be present in \" fields\" ."
46
52
const val LIMIT_DESCRIPTION = " The maximum number of entries to return in the response"
47
53
const val OFFSET_DESCRIPTION = " The offset of the first entry to return in the response. " +
48
54
" This is useful for pagination in combination with \" limit\" ."
@@ -53,7 +59,7 @@ class LapisController(
53
59
private val requestContext : RequestContext ,
54
60
private val csvWriter : CsvWriter ,
55
61
) {
56
- @GetMapping(" /aggregated" )
62
+ @GetMapping(" /aggregated" , produces = [ MediaType . APPLICATION_JSON_VALUE ] )
57
63
@LapisAggregatedResponse
58
64
fun aggregated (
59
65
@SequenceFilters
@@ -64,8 +70,7 @@ class LapisController(
64
70
fields : List <String >? ,
65
71
@Parameter(
66
72
schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
67
- description = " The fields to order by." +
68
- " Fields specified here must either be \" count\" or also be present in \" fields\" ." ,
73
+ description = AGGREGATED_ORDER_BY_FIELDS_DESCRIPTION ,
69
74
)
70
75
@RequestParam
71
76
orderBy : List <OrderByField >? ,
@@ -103,19 +108,161 @@ class LapisController(
103
108
104
109
requestContext.filter = request
105
110
106
- return LapisResponse (siloQueryModel.aggregate (request))
111
+ return LapisResponse (siloQueryModel.getAggregated (request))
107
112
}
108
113
109
- @PostMapping (" /aggregated" )
114
+ @GetMapping (" /aggregated" , produces = [ TEXT_CSV_HEADER ] )
110
115
@LapisAggregatedResponse
116
+ @Operation(
117
+ description = AGGREGATED_ENDPONT_DESCRIPTION ,
118
+ operationId = " getAggregatedAsCsv" ,
119
+ responses = [ApiResponse (responseCode = " 200" )],
120
+ )
121
+ fun getAggregatedAsCsv (
122
+ @SequenceFilters
123
+ @RequestParam
124
+ sequenceFilters : Map <String , String >? ,
125
+ @Parameter(description = AGGREGATED_GROUP_BY_FIELDS_DESCRIPTION )
126
+ @RequestParam
127
+ fields : List <String >? ,
128
+ @Parameter(
129
+ schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
130
+ description = AGGREGATED_ORDER_BY_FIELDS_DESCRIPTION ,
131
+ )
132
+ @RequestParam
133
+ orderBy : List <OrderByField >? ,
134
+ @Parameter(
135
+ schema = Schema (ref = " #/components/schemas/$NUCLEOTIDE_MUTATIONS_SCHEMA " ),
136
+ explode = Explode .TRUE ,
137
+ )
138
+ @RequestParam
139
+ nucleotideMutations : List <NucleotideMutation >? ,
140
+ @Parameter(schema = Schema (ref = " #/components/schemas/$AMINO_ACID_MUTATIONS_SCHEMA " ))
141
+ @RequestParam
142
+ aminoAcidMutations : List <AminoAcidMutation >? ,
143
+ @Parameter(
144
+ schema = Schema (ref = " #/components/schemas/$LIMIT_SCHEMA " ),
145
+ description = LIMIT_DESCRIPTION ,
146
+ )
147
+ @RequestParam
148
+ limit : Int? = null,
149
+ @Parameter(
150
+ schema = Schema (ref = " #/components/schemas/$OFFSET_SCHEMA " ),
151
+ description = OFFSET_DESCRIPTION ,
152
+ )
153
+ @RequestParam
154
+ offset : Int? = null,
155
+ ): String {
156
+ val request = SequenceFiltersRequestWithFields (
157
+ sequenceFilters?.filter { ! SPECIAL_REQUEST_PROPERTIES .contains(it.key) } ? : emptyMap(),
158
+ nucleotideMutations ? : emptyList(),
159
+ aminoAcidMutations ? : emptyList(),
160
+ fields ? : emptyList(),
161
+ orderBy ? : emptyList(),
162
+ limit,
163
+ offset,
164
+ )
165
+
166
+ return getResponseAsCsv(request, Delimiter .COMMA , siloQueryModel::getAggregated)
167
+ }
168
+
169
+ @GetMapping(" /aggregated" , produces = [TEXT_TSV_HEADER ])
170
+ @LapisAggregatedResponse
171
+ @Operation(
172
+ description = AGGREGATED_ENDPONT_DESCRIPTION ,
173
+ operationId = " getAggregatedAsTsv" ,
174
+ responses = [ApiResponse (responseCode = " 200" )],
175
+ )
176
+ fun getAggregatedAsTsv (
177
+ @SequenceFilters
178
+ @RequestParam
179
+ sequenceFilters : Map <String , String >? ,
180
+ @Parameter(description = AGGREGATED_GROUP_BY_FIELDS_DESCRIPTION )
181
+ @RequestParam
182
+ fields : List <String >? ,
183
+ @Parameter(
184
+ schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
185
+ description = AGGREGATED_ORDER_BY_FIELDS_DESCRIPTION ,
186
+ )
187
+ @RequestParam
188
+ orderBy : List <OrderByField >? ,
189
+ @Parameter(
190
+ schema = Schema (ref = " #/components/schemas/$NUCLEOTIDE_MUTATIONS_SCHEMA " ),
191
+ explode = Explode .TRUE ,
192
+ )
193
+ @RequestParam
194
+ nucleotideMutations : List <NucleotideMutation >? ,
195
+ @Parameter(schema = Schema (ref = " #/components/schemas/$AMINO_ACID_MUTATIONS_SCHEMA " ))
196
+ @RequestParam
197
+ aminoAcidMutations : List <AminoAcidMutation >? ,
198
+ @Parameter(
199
+ schema = Schema (ref = " #/components/schemas/$LIMIT_SCHEMA " ),
200
+ description = LIMIT_DESCRIPTION ,
201
+ )
202
+ @RequestParam
203
+ limit : Int? = null,
204
+ @Parameter(
205
+ schema = Schema (ref = " #/components/schemas/$OFFSET_SCHEMA " ),
206
+ description = OFFSET_DESCRIPTION ,
207
+ )
208
+ @RequestParam
209
+ offset : Int? = null,
210
+ ): String {
211
+ val request = SequenceFiltersRequestWithFields (
212
+ sequenceFilters?.filter { ! SPECIAL_REQUEST_PROPERTIES .contains(it.key) } ? : emptyMap(),
213
+ nucleotideMutations ? : emptyList(),
214
+ aminoAcidMutations ? : emptyList(),
215
+ fields ? : emptyList(),
216
+ orderBy ? : emptyList(),
217
+ limit,
218
+ offset,
219
+ )
220
+
221
+ return getResponseAsCsv(request, Delimiter .TAB , siloQueryModel::getAggregated)
222
+ }
223
+
224
+ @PostMapping(" /aggregated" , produces = [MediaType .APPLICATION_JSON_VALUE ])
225
+ @LapisAggregatedResponse
226
+ @Operation(
227
+ description = AGGREGATED_ENDPONT_DESCRIPTION ,
228
+ operationId = " postAggregated" ,
229
+ )
111
230
fun postAggregated (
112
231
@Parameter(schema = Schema (ref = " #/components/schemas/$AGGREGATED_REQUEST_SCHEMA " ))
113
232
@RequestBody
114
233
request : SequenceFiltersRequestWithFields ,
115
234
): LapisResponse <List <AggregationData >> {
116
235
requestContext.filter = request
117
236
118
- return LapisResponse (siloQueryModel.aggregate(request))
237
+ return LapisResponse (siloQueryModel.getAggregated(request))
238
+ }
239
+
240
+ @PostMapping(" /aggregated" , produces = [TEXT_CSV_HEADER ])
241
+ @Operation(
242
+ description = AGGREGATED_ENDPONT_DESCRIPTION ,
243
+ operationId = " postAggregatedAsCsv" ,
244
+ responses = [ApiResponse (responseCode = " 200" )],
245
+ )
246
+ fun postAggregatedAsCsv (
247
+ @Parameter(schema = Schema (ref = " #/components/schemas/$DETAILS_REQUEST_SCHEMA " ))
248
+ @RequestBody
249
+ request : SequenceFiltersRequestWithFields ,
250
+ ): String {
251
+ return getResponseAsCsv(request, Delimiter .COMMA , siloQueryModel::getAggregated)
252
+ }
253
+
254
+ @PostMapping(" /aggregated" , produces = [TEXT_TSV_HEADER ])
255
+ @Operation(
256
+ description = AGGREGATED_ENDPONT_DESCRIPTION ,
257
+ operationId = " postAggregatedAsTsv" ,
258
+ responses = [ApiResponse (responseCode = " 200" )],
259
+ )
260
+ fun postAggregatedAsTsv (
261
+ @Parameter(schema = Schema (ref = " #/components/schemas/$DETAILS_REQUEST_SCHEMA " ))
262
+ @RequestBody
263
+ request : SequenceFiltersRequestWithFields ,
264
+ ): String {
265
+ return getResponseAsCsv(request, Delimiter .TAB , siloQueryModel::getAggregated)
119
266
}
120
267
121
268
@GetMapping(" /nucleotideMutations" )
@@ -197,8 +344,7 @@ class LapisController(
197
344
fields : List <String >? ,
198
345
@Parameter(
199
346
schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
200
- description = " The fields of the response to order by." +
201
- " Fields specified here must also be present in \" fields\" ." ,
347
+ description = DETAILS_ORDER_BY_FIELDS_DESCRIPTION ,
202
348
)
203
349
@RequestParam
204
350
orderBy : List <OrderByField >? ,
@@ -251,8 +397,7 @@ class LapisController(
251
397
fields : List <String >? ,
252
398
@Parameter(
253
399
schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
254
- description = " The fields of the response to order by." +
255
- " Fields specified here must also be present in \" fields\" ." ,
400
+ description = DETAILS_ORDER_BY_FIELDS_DESCRIPTION ,
256
401
)
257
402
@RequestParam
258
403
orderBy : List <OrderByField >? ,
@@ -285,7 +430,7 @@ class LapisController(
285
430
offset,
286
431
)
287
432
288
- return getDetailsAsCsv (request, Delimiter .COMMA )
433
+ return getResponseAsCsv (request, Delimiter .COMMA , siloQueryModel::getDetails )
289
434
}
290
435
291
436
@GetMapping(" /details" , produces = [TEXT_TSV_HEADER ])
@@ -303,8 +448,7 @@ class LapisController(
303
448
fields : List <String >? ,
304
449
@Parameter(
305
450
schema = Schema (ref = " #/components/schemas/$ORDER_BY_FIELDS_SCHEMA " ),
306
- description = " The fields of the response to order by." +
307
- " Fields specified here must also be present in \" fields\" ." ,
451
+ description = DETAILS_ORDER_BY_FIELDS_DESCRIPTION ,
308
452
)
309
453
@RequestParam
310
454
orderBy : List <OrderByField >? ,
@@ -337,7 +481,7 @@ class LapisController(
337
481
offset,
338
482
)
339
483
340
- return getDetailsAsCsv (request, Delimiter .TAB )
484
+ return getResponseAsCsv (request, Delimiter .TAB , siloQueryModel::getDetails )
341
485
}
342
486
343
487
@PostMapping(" /details" , produces = [MediaType .APPLICATION_JSON_VALUE ])
@@ -367,7 +511,7 @@ class LapisController(
367
511
@RequestBody
368
512
request : SequenceFiltersRequestWithFields ,
369
513
): String {
370
- return getDetailsAsCsv (request, Delimiter .COMMA )
514
+ return getResponseAsCsv (request, Delimiter .COMMA , siloQueryModel::getDetails )
371
515
}
372
516
373
517
@PostMapping(" /details" , produces = [TEXT_TSV_HEADER ])
@@ -381,20 +525,24 @@ class LapisController(
381
525
@RequestBody
382
526
request : SequenceFiltersRequestWithFields ,
383
527
): String {
384
- return getDetailsAsCsv (request, Delimiter .TAB )
528
+ return getResponseAsCsv (request, Delimiter .TAB , siloQueryModel::getDetails )
385
529
}
386
530
387
- private fun getDetailsAsCsv (request : SequenceFiltersRequestWithFields , delimiter : Delimiter ): String {
531
+ private fun getResponseAsCsv (
532
+ request : SequenceFiltersRequestWithFields ,
533
+ delimiter : Delimiter ,
534
+ getResponse : (request: SequenceFiltersRequestWithFields ) -> List <CsvRecord >,
535
+ ): String {
388
536
requestContext.filter = request
389
537
390
- val data = siloQueryModel.getDetails (request)
538
+ val data = getResponse (request)
391
539
392
540
if (data.isEmpty()) {
393
541
return " "
394
542
}
395
543
396
- val headers = data[0 ].keys.toTypedArray< String > ()
397
- return csvWriter.write(headers, data.map { it.asCsvRecord() } , delimiter)
544
+ val headers = data[0 ].asHeader ()
545
+ return csvWriter.write(headers, data, delimiter)
398
546
}
399
547
}
400
548
0 commit comments