@genspectrum/dashboard-components 1.1.0 → 1.3.0

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.
Files changed (109) hide show
  1. package/custom-elements.json +22 -3
  2. package/dist/{NumberRangeFilterChangedEvent-B64OQZjX.js → NumberRangeFilterChangedEvent-CQ32Qy8D.js} +2 -2
  3. package/dist/NumberRangeFilterChangedEvent-CQ32Qy8D.js.map +1 -0
  4. package/dist/assets/mutationOverTimeWorker-C7saVShx.js.map +1 -0
  5. package/dist/components.d.ts +33 -27
  6. package/dist/components.js +119 -127
  7. package/dist/components.js.map +1 -1
  8. package/dist/util.d.ts +27 -27
  9. package/dist/util.js +1 -1
  10. package/package.json +7 -3
  11. package/src/lapisApi/lapisApi.ts +31 -2
  12. package/src/lapisApi/lapisTypes.ts +35 -1
  13. package/src/operator/DivisionOperator.ts +4 -2
  14. package/src/operator/FetchDetailsOperator.ts +1 -1
  15. package/src/operator/RenameFieldOperator.ts +3 -3
  16. package/src/preact/aggregatedData/aggregate.tsx +0 -5
  17. package/src/preact/components/annotated-mutation.tsx +0 -1
  18. package/src/preact/components/clearable-select.stories.tsx +1 -1
  19. package/src/preact/components/confidence-interval-selector.tsx +1 -1
  20. package/src/preact/components/error-boundary.tsx +1 -5
  21. package/src/preact/components/error-display.tsx +1 -1
  22. package/src/preact/components/fullscreen.tsx +2 -5
  23. package/src/preact/components/info.stories.tsx +1 -1
  24. package/src/preact/components/min-max-range-slider.tsx +1 -1
  25. package/src/preact/components/proportion-selector.tsx +4 -4
  26. package/src/preact/components/select.tsx +1 -1
  27. package/src/preact/components/table.tsx +1 -1
  28. package/src/preact/components/tabs.tsx +1 -1
  29. package/src/preact/components/tooltip.stories.tsx +1 -1
  30. package/src/preact/components/tooltip.tsx +1 -1
  31. package/src/preact/genomeViewer/CDSPlot.tsx +3 -3
  32. package/src/preact/genomeViewer/loadGff3.ts +5 -8
  33. package/src/preact/lineageFilter/lineage-filter.tsx +1 -1
  34. package/src/preact/locationFilter/location-filter.tsx +4 -4
  35. package/src/preact/mutationComparison/getMutationComparisonTableData.ts +1 -3
  36. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +1 -1
  37. package/src/preact/mutationComparison/mutation-comparison.tsx +0 -5
  38. package/src/preact/mutationFilter/mutation-filter-info.tsx +2 -2
  39. package/src/preact/mutationFilter/mutation-filter.tsx +1 -1
  40. package/src/preact/mutations/getMutationsGridData.ts +2 -6
  41. package/src/preact/mutations/getMutationsTableData.ts +1 -1
  42. package/src/preact/mutations/mutations-grid.tsx +1 -1
  43. package/src/preact/mutations/mutations.tsx +0 -5
  44. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +1 -0
  45. package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +1 -0
  46. package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +1 -0
  47. package/src/preact/mutationsOverTime/__mockData__/noDataWhenNoMutationsAreInFilter.ts +1 -0
  48. package/src/preact/mutationsOverTime/__mockData__/noDataWhenThereAreNoDatesInFilter.ts +1 -0
  49. package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +1 -0
  50. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +2 -0
  51. package/src/preact/mutationsOverTime/mutations-over-time.tsx +11 -11
  52. package/src/preact/numberRangeFilter/number-range-filter.tsx +4 -4
  53. package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +1 -4
  54. package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +0 -5
  55. package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +1 -1
  56. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
  57. package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +1 -1
  58. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +1 -1
  59. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +5 -5
  60. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +1 -4
  61. package/src/preact/sequencesByLocation/loadMapSource.tsx +5 -2
  62. package/src/preact/shared/aspectRatio/AspectRatio.tsx +1 -1
  63. package/src/preact/shared/floating-ui/hooks.ts +2 -2
  64. package/src/preact/shared/sort/sortMutationPositions.ts +2 -2
  65. package/src/preact/shared/tanstackTable/pagination.tsx +2 -2
  66. package/src/preact/shared/tanstackTable/tanstackTable.tsx +1 -1
  67. package/src/preact/statistic/statistics.tsx +0 -5
  68. package/src/preact/textFilter/fetchStringAutocompleteList.ts +1 -10
  69. package/src/preact/textFilter/text-filter.tsx +1 -6
  70. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +1 -1
  71. package/src/preact/webWorkers/useWebWorker.ts +2 -1
  72. package/src/preact/webWorkers/workerFunction.ts +2 -2
  73. package/src/query/computeMapLocationData.ts +1 -1
  74. package/src/query/queryAggregatedDataOverTime.ts +3 -3
  75. package/src/query/queryMutationsOverTime.spec.ts +9 -9
  76. package/src/query/queryMutationsOverTime.ts +121 -37
  77. package/src/query/queryMutationsOverTimeNewEndpoint.spec.ts +935 -0
  78. package/src/query/queryRelativeGrowthAdvantage.ts +5 -9
  79. package/src/query/queryWastewaterMutationsOverTime.ts +1 -1
  80. package/src/types.ts +1 -1
  81. package/src/utils/mutations.ts +10 -10
  82. package/src/utils/type-utils.ts +1 -1
  83. package/src/utils/typeAssertions.spec.ts +1 -1
  84. package/src/web-components/gs-app.spec-d.ts +1 -1
  85. package/src/web-components/gs-app.stories.ts +1 -1
  86. package/src/web-components/input/gs-date-range-filter.tsx +2 -2
  87. package/src/web-components/input/gs-lineage-filter.tsx +2 -2
  88. package/src/web-components/input/gs-location-filter.tsx +3 -3
  89. package/src/web-components/input/gs-mutation-filter.tsx +2 -2
  90. package/src/web-components/input/gs-number-range-filter.spec.ts +1 -1
  91. package/src/web-components/input/gs-text-filter.tsx +2 -2
  92. package/src/web-components/visualization/gs-aggregate.tsx +2 -2
  93. package/src/web-components/visualization/gs-genome-data-viewer.spec-d.ts +1 -1
  94. package/src/web-components/visualization/gs-mutation-comparison.tsx +2 -2
  95. package/src/web-components/visualization/gs-mutations-over-time.spec-d.ts +3 -0
  96. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +3 -0
  97. package/src/web-components/visualization/gs-mutations-over-time.tsx +9 -0
  98. package/src/web-components/visualization/gs-mutations.tsx +2 -2
  99. package/src/web-components/visualization/gs-number-sequences-over-time.tsx +2 -2
  100. package/src/web-components/visualization/gs-prevalence-over-time.tsx +2 -2
  101. package/src/web-components/visualization/gs-relative-growth-advantage.tsx +2 -2
  102. package/src/web-components/visualization/gs-sequences-by-location.tsx +2 -2
  103. package/src/web-components/visualization/gs-statistics.tsx +2 -2
  104. package/standalone-bundle/assets/mutationOverTimeWorker-DRRi3aMG.js.map +1 -0
  105. package/standalone-bundle/dashboard-components.js +4454 -4430
  106. package/standalone-bundle/dashboard-components.js.map +1 -1
  107. package/dist/NumberRangeFilterChangedEvent-B64OQZjX.js.map +0 -1
  108. package/dist/assets/mutationOverTimeWorker-DjH04AQB.js.map +0 -1
  109. package/standalone-bundle/assets/mutationOverTimeWorker-B6bf3R3j.js.map +0 -1
@@ -0,0 +1,935 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { queryMutationsOverTimeData } from './queryMutationsOverTime';
4
+ import { DUMMY_LAPIS_URL, lapisRequestMocks } from '../../vitest.setup';
5
+
6
+ describe('queryMutationsOverTimeNewEndpoint', () => {
7
+ it('should fetch for a filter without date and sort by mutation and date', async () => {
8
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
9
+ const dateField = 'dateField';
10
+
11
+ lapisRequestMocks.multipleAggregated([
12
+ // this request is expected to get 'all dates in dataset' - since the user hasn't provided a date range
13
+ {
14
+ body: { ...lapisFilter, fields: [dateField] },
15
+ response: {
16
+ data: [
17
+ { count: 1, [dateField]: '2023-01-01' },
18
+ { count: 2, [dateField]: '2023-01-03' },
19
+ ],
20
+ },
21
+ },
22
+ {
23
+ body: {
24
+ ...lapisFilter,
25
+ dateFieldFrom: '2023-01-01',
26
+ dateFieldTo: '2023-01-01',
27
+ fields: [],
28
+ },
29
+ response: { data: [{ count: 11 }] },
30
+ },
31
+ {
32
+ body: {
33
+ ...lapisFilter,
34
+ dateFieldFrom: '2023-01-02',
35
+ dateFieldTo: '2023-01-02',
36
+ fields: [],
37
+ },
38
+ response: { data: [{ count: 12 }] },
39
+ },
40
+ {
41
+ body: {
42
+ ...lapisFilter,
43
+ dateFieldFrom: '2023-01-03',
44
+ dateFieldTo: '2023-01-03',
45
+ fields: [],
46
+ },
47
+ response: { data: [{ count: 13 }] },
48
+ },
49
+ ]);
50
+ lapisRequestMocks.multipleMutations(
51
+ [
52
+ {
53
+ body: {
54
+ ...lapisFilter,
55
+ dateFieldFrom: '2023-01-01',
56
+ dateFieldTo: '2023-01-03',
57
+ minProportion: 0.001,
58
+ },
59
+ response: {
60
+ data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
61
+ },
62
+ },
63
+ ],
64
+ 'nucleotide',
65
+ );
66
+ const dateRanges = [
67
+ {
68
+ dateFrom: '2023-01-01',
69
+ dateTo: '2023-01-01',
70
+ },
71
+ {
72
+ dateFrom: '2023-01-02',
73
+ dateTo: '2023-01-02',
74
+ },
75
+ {
76
+ dateFrom: '2023-01-03',
77
+ dateTo: '2023-01-03',
78
+ },
79
+ ];
80
+ lapisRequestMocks.mutationsOverTime(
81
+ [
82
+ {
83
+ body: {
84
+ filters: lapisFilter,
85
+ dateRanges,
86
+ includeMutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
87
+ dateField,
88
+ },
89
+ response: {
90
+ data: {
91
+ data: [
92
+ [
93
+ { count: 4, coverage: 10 },
94
+ { count: 0, coverage: 10 },
95
+ { count: 0, coverage: 10 },
96
+ ],
97
+ [
98
+ { count: 1, coverage: 10 },
99
+ { count: 2, coverage: 10 },
100
+ { count: 3, coverage: 10 },
101
+ ],
102
+ ],
103
+ dateRanges,
104
+ mutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
105
+ },
106
+ },
107
+ },
108
+ ],
109
+ 'nucleotide',
110
+ );
111
+
112
+ const { mutationOverTimeData, overallMutationData } = await queryMutationsOverTimeData({
113
+ lapisFilter,
114
+ sequenceType: 'nucleotide',
115
+ lapis: DUMMY_LAPIS_URL,
116
+ lapisDateField: dateField,
117
+ granularity: 'day',
118
+ useNewEndpoint: true,
119
+ });
120
+
121
+ const expectedData = [
122
+ [
123
+ { type: 'value', proportion: 0.4, count: 4, totalCount: 11 },
124
+ { type: 'value', proportion: 0, count: 0, totalCount: 12 },
125
+ { type: 'value', proportion: 0, count: 0, totalCount: 13 },
126
+ ],
127
+ [
128
+ { type: 'value', proportion: 0.1, count: 1, totalCount: 11 },
129
+ { type: 'value', proportion: 0.2, count: 2, totalCount: 12 },
130
+ { type: 'value', proportion: 0.3, count: 3, totalCount: 13 },
131
+ ],
132
+ ];
133
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal(expectedData);
134
+
135
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
136
+ expect(sequences[0].code).toBe('otherSequenceName:G234C');
137
+ expect(sequences[1].code).toBe('sequenceName:A123T');
138
+
139
+ const dates = mutationOverTimeData.getSecondAxisKeys();
140
+ expect(dates[0].dateString).toBe('2023-01-01');
141
+ expect(dates[1].dateString).toBe('2023-01-02');
142
+ expect(dates[2].dateString).toBe('2023-01-03');
143
+
144
+ expect(overallMutationData).to.deep.equal([
145
+ {
146
+ type: 'substitution',
147
+ mutation: {
148
+ valueAtReference: 'G',
149
+ substitutionValue: 'C',
150
+ position: 234,
151
+ segment: 'otherSequenceName',
152
+ code: 'otherSequenceName:G234C',
153
+ type: 'substitution',
154
+ },
155
+ count: 4,
156
+ proportion: 0.22,
157
+ },
158
+ {
159
+ type: 'substitution',
160
+ mutation: {
161
+ valueAtReference: 'A',
162
+ substitutionValue: 'T',
163
+ position: 123,
164
+ segment: 'sequenceName',
165
+ code: 'sequenceName:A123T',
166
+ type: 'substitution',
167
+ },
168
+ count: 6,
169
+ proportion: 0.21,
170
+ },
171
+ ]);
172
+ });
173
+
174
+ it('should fetch for dates with no mutations', async () => {
175
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
176
+ const dateField = 'dateField';
177
+
178
+ lapisRequestMocks.multipleAggregated([
179
+ {
180
+ body: { ...lapisFilter, fields: [dateField] },
181
+ response: {
182
+ data: [
183
+ { count: 1, [dateField]: '2023-01-01' },
184
+ { count: 2, [dateField]: '2023-01-03' },
185
+ ],
186
+ },
187
+ },
188
+ {
189
+ body: {
190
+ ...lapisFilter,
191
+ dateFieldFrom: '2023-01-01',
192
+ dateFieldTo: '2023-01-01',
193
+ fields: [],
194
+ },
195
+ response: { data: [{ count: 11 }] },
196
+ },
197
+ {
198
+ body: {
199
+ ...lapisFilter,
200
+ dateFieldFrom: '2023-01-02',
201
+ dateFieldTo: '2023-01-02',
202
+ fields: [],
203
+ },
204
+ response: { data: [{ count: 0 }] },
205
+ },
206
+ {
207
+ body: {
208
+ ...lapisFilter,
209
+ dateFieldFrom: '2023-01-03',
210
+ dateFieldTo: '2023-01-03',
211
+ fields: [],
212
+ },
213
+ response: { data: [{ count: 13 }] },
214
+ },
215
+ ]);
216
+
217
+ lapisRequestMocks.multipleMutations(
218
+ [
219
+ {
220
+ body: {
221
+ ...lapisFilter,
222
+ dateFieldFrom: '2023-01-01',
223
+ dateFieldTo: '2023-01-03',
224
+ minProportion: 0.001,
225
+ },
226
+ response: {
227
+ data: [getSomeTestMutation(0.2, 4), getSomeOtherTestMutation(0.4, 4)],
228
+ },
229
+ },
230
+ ],
231
+ 'nucleotide',
232
+ );
233
+
234
+ const dateRanges = [
235
+ {
236
+ dateFrom: '2023-01-01',
237
+ dateTo: '2023-01-01',
238
+ },
239
+ {
240
+ dateFrom: '2023-01-02',
241
+ dateTo: '2023-01-02',
242
+ },
243
+ {
244
+ dateFrom: '2023-01-03',
245
+ dateTo: '2023-01-03',
246
+ },
247
+ ];
248
+
249
+ lapisRequestMocks.mutationsOverTime(
250
+ [
251
+ {
252
+ body: {
253
+ filters: lapisFilter,
254
+ dateRanges,
255
+ includeMutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
256
+ dateField,
257
+ },
258
+ response: {
259
+ data: {
260
+ data: [
261
+ [
262
+ { count: 4, coverage: 10 },
263
+ { count: 0, coverage: 10 },
264
+ { count: 0, coverage: 10 },
265
+ ],
266
+ [
267
+ { count: 1, coverage: 10 },
268
+ { count: 0, coverage: 10 },
269
+ { count: 3, coverage: 10 },
270
+ ],
271
+ ],
272
+ dateRanges,
273
+ mutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
274
+ },
275
+ },
276
+ },
277
+ ],
278
+ 'nucleotide',
279
+ );
280
+
281
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
282
+ lapisFilter,
283
+ sequenceType: 'nucleotide',
284
+ lapis: DUMMY_LAPIS_URL,
285
+ lapisDateField: dateField,
286
+ granularity: 'day',
287
+ useNewEndpoint: true,
288
+ });
289
+
290
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
291
+ [
292
+ { type: 'value', proportion: 0.4, count: 4, totalCount: 11 },
293
+ { type: 'value', proportion: 0, count: 0, totalCount: 0 },
294
+ { type: 'value', proportion: 0, count: 0, totalCount: 13 },
295
+ ],
296
+ [
297
+ { type: 'value', proportion: 0.1, count: 1, totalCount: 11 },
298
+ { type: 'value', proportion: 0, count: 0, totalCount: 0 },
299
+ { type: 'value', proportion: 0.3, count: 3, totalCount: 13 },
300
+ ],
301
+ ]);
302
+
303
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
304
+ expect(sequences[0].code).toBe('otherSequenceName:G234C');
305
+ expect(sequences[1].code).toBe('sequenceName:A123T');
306
+
307
+ const dates = mutationOverTimeData.getSecondAxisKeys();
308
+ expect(dates[0].dateString).toBe('2023-01-01');
309
+ expect(dates[1].dateString).toBe('2023-01-02');
310
+ expect(dates[2].dateString).toBe('2023-01-03');
311
+ });
312
+
313
+ it('should return empty map when no mutations are found', async () => {
314
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
315
+ const dateField = 'dateField';
316
+
317
+ lapisRequestMocks.multipleAggregated([
318
+ {
319
+ body: { ...lapisFilter, fields: [dateField] },
320
+ response: {
321
+ data: [
322
+ { count: 1, [dateField]: '2023-01-01' },
323
+ { count: 2, [dateField]: '2023-01-03' },
324
+ ],
325
+ },
326
+ },
327
+ {
328
+ body: {
329
+ ...lapisFilter,
330
+ dateFieldFrom: '2023-01-01',
331
+ dateFieldTo: '2023-01-01',
332
+ fields: [],
333
+ },
334
+ response: { data: [{ count: 11 }] },
335
+ },
336
+ {
337
+ body: {
338
+ ...lapisFilter,
339
+ dateFieldFrom: '2023-01-02',
340
+ dateFieldTo: '2023-01-02',
341
+ fields: [],
342
+ },
343
+ response: { data: [{ count: 12 }] },
344
+ },
345
+ {
346
+ body: {
347
+ ...lapisFilter,
348
+ dateFieldFrom: '2023-01-03',
349
+ dateFieldTo: '2023-01-03',
350
+ fields: [],
351
+ },
352
+ response: { data: [{ count: 13 }] },
353
+ },
354
+ ]);
355
+
356
+ lapisRequestMocks.multipleMutations(
357
+ [
358
+ {
359
+ body: {
360
+ ...lapisFilter,
361
+ dateFieldFrom: '2023-01-01',
362
+ dateFieldTo: '2023-01-03',
363
+ minProportion: 0.001,
364
+ },
365
+ response: {
366
+ data: [],
367
+ },
368
+ },
369
+ ],
370
+ 'nucleotide',
371
+ );
372
+
373
+ const dateRanges = [
374
+ {
375
+ dateFrom: '2023-01-01',
376
+ dateTo: '2023-01-01',
377
+ },
378
+ {
379
+ dateFrom: '2023-01-02',
380
+ dateTo: '2023-01-02',
381
+ },
382
+ {
383
+ dateFrom: '2023-01-03',
384
+ dateTo: '2023-01-03',
385
+ },
386
+ ];
387
+
388
+ lapisRequestMocks.mutationsOverTime(
389
+ [
390
+ {
391
+ body: {
392
+ filters: lapisFilter,
393
+ dateRanges,
394
+ includeMutations: [],
395
+ dateField,
396
+ },
397
+ response: {
398
+ data: {
399
+ data: [],
400
+ dateRanges,
401
+ mutations: [],
402
+ },
403
+ },
404
+ },
405
+ ],
406
+ 'nucleotide',
407
+ );
408
+
409
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
410
+ lapisFilter,
411
+ sequenceType: 'nucleotide',
412
+ lapis: DUMMY_LAPIS_URL,
413
+ lapisDateField: dateField,
414
+ granularity: 'day',
415
+ useNewEndpoint: true,
416
+ });
417
+
418
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([]);
419
+ expect(mutationOverTimeData.getFirstAxisKeys()).to.deep.equal([]);
420
+ const dates = mutationOverTimeData.getSecondAxisKeys();
421
+ expect(dates.length).toBe(3);
422
+ expect(dates[0].dateString).toBe('2023-01-01');
423
+ expect(dates[1].dateString).toBe('2023-01-02');
424
+ expect(dates[2].dateString).toBe('2023-01-03');
425
+ });
426
+
427
+ it('should use dateFrom from filter', async () => {
428
+ const dateField = 'dateField';
429
+ const lapisFilter = { field1: 'value1', field2: 'value2', [`${dateField}From`]: '2023-01-02' };
430
+
431
+ lapisRequestMocks.multipleAggregated([
432
+ {
433
+ body: { ...lapisFilter, fields: [dateField] },
434
+ response: {
435
+ data: [
436
+ { count: 1, [dateField]: '2023-01-01' },
437
+ { count: 2, [dateField]: '2023-01-03' },
438
+ ],
439
+ },
440
+ },
441
+ {
442
+ body: {
443
+ ...lapisFilter,
444
+ dateFieldFrom: '2023-01-02',
445
+ dateFieldTo: '2023-01-02',
446
+ fields: [],
447
+ },
448
+ response: { data: [{ count: 11 }] },
449
+ },
450
+ {
451
+ body: {
452
+ ...lapisFilter,
453
+ dateFieldFrom: '2023-01-03',
454
+ dateFieldTo: '2023-01-03',
455
+ fields: [],
456
+ },
457
+ response: { data: [{ count: 12 }] },
458
+ },
459
+ ]);
460
+
461
+ lapisRequestMocks.multipleMutations(
462
+ [
463
+ {
464
+ body: {
465
+ ...lapisFilter,
466
+ dateFieldFrom: '2023-01-02',
467
+ dateFieldTo: '2023-01-03',
468
+ minProportion: 0.001,
469
+ },
470
+ response: {
471
+ data: [getSomeTestMutation(0.25, 5)],
472
+ },
473
+ },
474
+ ],
475
+ 'nucleotide',
476
+ );
477
+
478
+ const dateRanges = [
479
+ {
480
+ dateFrom: '2023-01-02',
481
+ dateTo: '2023-01-02',
482
+ },
483
+ {
484
+ dateFrom: '2023-01-03',
485
+ dateTo: '2023-01-03',
486
+ },
487
+ ];
488
+
489
+ lapisRequestMocks.mutationsOverTime(
490
+ [
491
+ {
492
+ body: {
493
+ filters: lapisFilter,
494
+ dateRanges,
495
+ includeMutations: ['sequenceName:A123T'],
496
+ dateField,
497
+ },
498
+ response: {
499
+ data: {
500
+ data: [
501
+ [
502
+ { count: 2, coverage: 10 },
503
+ { count: 3, coverage: 10 },
504
+ ],
505
+ ],
506
+ dateRanges,
507
+ mutations: ['sequenceName:A123T'],
508
+ },
509
+ },
510
+ },
511
+ ],
512
+ 'nucleotide',
513
+ );
514
+
515
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
516
+ lapisFilter,
517
+ sequenceType: 'nucleotide',
518
+ lapis: DUMMY_LAPIS_URL,
519
+ lapisDateField: dateField,
520
+ granularity: 'day',
521
+ useNewEndpoint: true,
522
+ });
523
+
524
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
525
+ [
526
+ { type: 'value', proportion: 0.2, count: 2, totalCount: 11 },
527
+ { type: 'value', proportion: 0.3, count: 3, totalCount: 12 },
528
+ ],
529
+ ]);
530
+
531
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
532
+ expect(sequences[0].code).toBe('sequenceName:A123T');
533
+
534
+ const dates = mutationOverTimeData.getSecondAxisKeys();
535
+ expect(dates[0].dateString).toBe('2023-01-02');
536
+ expect(dates[1].dateString).toBe('2023-01-03');
537
+ });
538
+
539
+ it('should use dateTo from filter', async () => {
540
+ const dateField = 'dateField';
541
+ const lapisFilter = { field1: 'value1', field2: 'value2', [`${dateField}To`]: '2023-01-02' };
542
+
543
+ lapisRequestMocks.multipleAggregated([
544
+ {
545
+ body: { ...lapisFilter, fields: [dateField] },
546
+ response: {
547
+ data: [
548
+ { count: 1, [dateField]: '2023-01-01' },
549
+ { count: 2, [dateField]: '2023-01-03' },
550
+ ],
551
+ },
552
+ },
553
+ {
554
+ body: {
555
+ ...lapisFilter,
556
+ dateFieldFrom: '2023-01-01',
557
+ dateFieldTo: '2023-01-01',
558
+ fields: [],
559
+ },
560
+ response: { data: [{ count: 11 }] },
561
+ },
562
+ {
563
+ body: {
564
+ ...lapisFilter,
565
+ dateFieldFrom: '2023-01-02',
566
+ dateFieldTo: '2023-01-02',
567
+ fields: [],
568
+ },
569
+ response: { data: [{ count: 12 }] },
570
+ },
571
+ ]);
572
+
573
+ lapisRequestMocks.multipleMutations(
574
+ [
575
+ {
576
+ body: {
577
+ ...lapisFilter,
578
+ dateFieldFrom: '2023-01-01',
579
+ dateFieldTo: '2023-01-02',
580
+ minProportion: 0.001,
581
+ },
582
+ response: {
583
+ data: [getSomeTestMutation(0.15, 3)],
584
+ },
585
+ },
586
+ ],
587
+ 'nucleotide',
588
+ );
589
+
590
+ const dateRanges = [
591
+ {
592
+ dateFrom: '2023-01-01',
593
+ dateTo: '2023-01-01',
594
+ },
595
+ {
596
+ dateFrom: '2023-01-02',
597
+ dateTo: '2023-01-02',
598
+ },
599
+ ];
600
+
601
+ lapisRequestMocks.mutationsOverTime(
602
+ [
603
+ {
604
+ body: {
605
+ filters: lapisFilter,
606
+ dateRanges,
607
+ includeMutations: ['sequenceName:A123T'],
608
+ dateField,
609
+ },
610
+ response: {
611
+ data: {
612
+ data: [
613
+ [
614
+ { count: 1, coverage: 10 },
615
+ { count: 2, coverage: 10 },
616
+ ],
617
+ ],
618
+ dateRanges,
619
+ mutations: ['sequenceName:A123T'],
620
+ },
621
+ },
622
+ },
623
+ ],
624
+ 'nucleotide',
625
+ );
626
+
627
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
628
+ lapisFilter,
629
+ sequenceType: 'nucleotide',
630
+ lapis: DUMMY_LAPIS_URL,
631
+ lapisDateField: dateField,
632
+ granularity: 'day',
633
+ useNewEndpoint: true,
634
+ });
635
+
636
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
637
+ [
638
+ { type: 'value', proportion: 0.1, count: 1, totalCount: 11 },
639
+ { type: 'value', proportion: 0.2, count: 2, totalCount: 12 },
640
+ ],
641
+ ]);
642
+
643
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
644
+ expect(sequences[0].code).toBe('sequenceName:A123T');
645
+
646
+ const dates = mutationOverTimeData.getSecondAxisKeys();
647
+ expect(dates[0].dateString).toBe('2023-01-01');
648
+ expect(dates[1].dateString).toBe('2023-01-02');
649
+ });
650
+
651
+ it('should use date from filter', async () => {
652
+ const dateField = 'dateField';
653
+ const lapisFilter = { field1: 'value1', field2: 'value2', [dateField]: '2023-01-02' };
654
+
655
+ lapisRequestMocks.multipleAggregated([
656
+ {
657
+ body: { ...lapisFilter, fields: [dateField] },
658
+ response: {
659
+ data: [
660
+ { count: 1, [dateField]: '2023-01-01' },
661
+ { count: 2, [dateField]: '2023-01-03' },
662
+ ],
663
+ },
664
+ },
665
+ {
666
+ body: {
667
+ ...lapisFilter,
668
+ dateFieldFrom: '2023-01-02',
669
+ dateFieldTo: '2023-01-02',
670
+ fields: [],
671
+ },
672
+ response: { data: [{ count: 11 }] },
673
+ },
674
+ ]);
675
+
676
+ lapisRequestMocks.multipleMutations(
677
+ [
678
+ {
679
+ body: {
680
+ ...lapisFilter,
681
+ dateFieldFrom: '2023-01-02',
682
+ dateFieldTo: '2023-01-02',
683
+ minProportion: 0.001,
684
+ },
685
+ response: { data: [getSomeTestMutation(0.2, 2)] },
686
+ },
687
+ ],
688
+ 'nucleotide',
689
+ );
690
+
691
+ const dateRanges = [
692
+ {
693
+ dateFrom: '2023-01-02',
694
+ dateTo: '2023-01-02',
695
+ },
696
+ ];
697
+
698
+ lapisRequestMocks.mutationsOverTime(
699
+ [
700
+ {
701
+ body: {
702
+ filters: lapisFilter,
703
+ dateRanges,
704
+ includeMutations: ['sequenceName:A123T'],
705
+ dateField,
706
+ },
707
+ response: {
708
+ data: {
709
+ data: [[{ count: 2, coverage: 10 }]],
710
+ dateRanges,
711
+ mutations: ['sequenceName:A123T'],
712
+ },
713
+ },
714
+ },
715
+ ],
716
+ 'nucleotide',
717
+ );
718
+
719
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
720
+ lapisFilter,
721
+ sequenceType: 'nucleotide',
722
+ lapis: DUMMY_LAPIS_URL,
723
+ lapisDateField: dateField,
724
+ granularity: 'day',
725
+ useNewEndpoint: true,
726
+ });
727
+
728
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
729
+ [{ type: 'value', proportion: 0.2, count: 2, totalCount: 11 }],
730
+ ]);
731
+
732
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
733
+ expect(sequences[0].code).toBe('sequenceName:A123T');
734
+
735
+ const dates = mutationOverTimeData.getSecondAxisKeys();
736
+ expect(dates[0].dateString).toBe('2023-01-02');
737
+ });
738
+
739
+ it('should fetch data including the first and last day of the granularity', async () => {
740
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
741
+ const dateField = 'dateField';
742
+
743
+ lapisRequestMocks.multipleAggregated([
744
+ {
745
+ body: { ...lapisFilter, fields: [dateField] },
746
+ response: {
747
+ data: [
748
+ { count: 1, [dateField]: '2023-01-05' },
749
+ { count: 2, [dateField]: '2023-02-15' },
750
+ ],
751
+ },
752
+ },
753
+ {
754
+ body: {
755
+ ...lapisFilter,
756
+ dateFieldFrom: '2023-01-01',
757
+ dateFieldTo: '2023-01-31',
758
+ fields: [],
759
+ },
760
+ response: { data: [{ count: 11 }] },
761
+ },
762
+ {
763
+ body: {
764
+ ...lapisFilter,
765
+ dateFieldFrom: '2023-02-01',
766
+ dateFieldTo: '2023-02-28',
767
+ fields: [],
768
+ },
769
+ response: { data: [{ count: 12 }] },
770
+ },
771
+ ]);
772
+
773
+ lapisRequestMocks.multipleMutations(
774
+ [
775
+ {
776
+ body: {
777
+ ...lapisFilter,
778
+ dateFieldFrom: '2023-01-01',
779
+ dateFieldTo: '2023-02-28',
780
+ minProportion: 0.001,
781
+ },
782
+ response: {
783
+ data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
784
+ },
785
+ },
786
+ ],
787
+ 'nucleotide',
788
+ );
789
+
790
+ const dateRanges = [
791
+ {
792
+ dateFrom: '2023-01-01',
793
+ dateTo: '2023-01-31',
794
+ },
795
+ {
796
+ dateFrom: '2023-02-01',
797
+ dateTo: '2023-02-28',
798
+ },
799
+ ];
800
+
801
+ lapisRequestMocks.mutationsOverTime(
802
+ [
803
+ {
804
+ body: {
805
+ filters: lapisFilter,
806
+ dateRanges,
807
+ includeMutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
808
+ dateField,
809
+ },
810
+ response: {
811
+ data: {
812
+ data: [
813
+ [
814
+ { count: 2, coverage: 10 },
815
+ { count: 3, coverage: 10 },
816
+ ],
817
+ [
818
+ { count: 4, coverage: 10 },
819
+ { count: 5, coverage: 10 },
820
+ ],
821
+ ],
822
+ dateRanges,
823
+ mutations: ['otherSequenceName:G234C', 'sequenceName:A123T'],
824
+ },
825
+ },
826
+ },
827
+ ],
828
+ 'nucleotide',
829
+ );
830
+
831
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
832
+ lapisFilter,
833
+ sequenceType: 'nucleotide',
834
+ lapis: DUMMY_LAPIS_URL,
835
+ lapisDateField: dateField,
836
+ granularity: 'month',
837
+ useNewEndpoint: true,
838
+ });
839
+
840
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
841
+ [
842
+ { type: 'value', proportion: 0.2, count: 2, totalCount: 11 },
843
+ { type: 'value', proportion: 0.3, count: 3, totalCount: 12 },
844
+ ],
845
+ [
846
+ { type: 'value', proportion: 0.4, count: 4, totalCount: 11 },
847
+ { type: 'value', proportion: 0.5, count: 5, totalCount: 12 },
848
+ ],
849
+ ]);
850
+
851
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
852
+ expect(sequences[0].code).toBe('otherSequenceName:G234C');
853
+ expect(sequences[1].code).toBe('sequenceName:A123T');
854
+
855
+ const dates = mutationOverTimeData.getSecondAxisKeys();
856
+ expect(dates[0].dateString).toBe('2023-01');
857
+ expect(dates[1].dateString).toBe('2023-02');
858
+ });
859
+
860
+ it('should return empty data when there are no dates in filter', async () => {
861
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
862
+ const dateField = 'dateField';
863
+
864
+ lapisRequestMocks.multipleAggregated([
865
+ {
866
+ body: { ...lapisFilter, fields: [dateField] },
867
+ response: {
868
+ data: [],
869
+ },
870
+ },
871
+ ]);
872
+
873
+ lapisRequestMocks.mutationsOverTime(
874
+ [
875
+ {
876
+ body: {
877
+ filters: lapisFilter,
878
+ dateRanges: [],
879
+ includeMutations: [],
880
+ dateField,
881
+ },
882
+ response: {
883
+ data: {
884
+ data: [],
885
+ dateRanges: [],
886
+ mutations: [],
887
+ },
888
+ },
889
+ },
890
+ ],
891
+ 'nucleotide',
892
+ );
893
+
894
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
895
+ lapisFilter,
896
+ sequenceType: 'nucleotide',
897
+ lapis: DUMMY_LAPIS_URL,
898
+ lapisDateField: dateField,
899
+ granularity: 'month',
900
+ useNewEndpoint: true,
901
+ });
902
+
903
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([]);
904
+
905
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
906
+ expect(sequences.length).toBe(0);
907
+
908
+ const dates = mutationOverTimeData.getSecondAxisKeys();
909
+ expect(dates.length).toBe(0);
910
+ });
911
+
912
+ function getSomeTestMutation(proportion: number, count: number) {
913
+ return {
914
+ mutation: 'sequenceName:A123T',
915
+ proportion,
916
+ count,
917
+ sequenceName: 'sequenceName',
918
+ mutationFrom: 'A',
919
+ mutationTo: 'T',
920
+ position: 123,
921
+ };
922
+ }
923
+
924
+ function getSomeOtherTestMutation(proportion: number, count: number) {
925
+ return {
926
+ mutation: 'otherSequenceName:G234C',
927
+ proportion,
928
+ count,
929
+ sequenceName: 'otherSequenceName',
930
+ mutationFrom: 'G',
931
+ mutationTo: 'C',
932
+ position: 234,
933
+ };
934
+ }
935
+ });