@genspectrum/dashboard-components 1.2.0 → 1.3.1

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 (33) hide show
  1. package/README.md +9 -0
  2. package/custom-elements.json +20 -1
  3. package/dist/assets/mutationOverTimeWorker-CQxrFo53.js.map +1 -0
  4. package/dist/components.d.ts +34 -28
  5. package/dist/components.js +48 -16
  6. package/dist/components.js.map +1 -1
  7. package/dist/util.d.ts +28 -28
  8. package/package.json +1 -1
  9. package/src/lapisApi/lapisApi.ts +29 -0
  10. package/src/lapisApi/lapisTypes.ts +35 -1
  11. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +1 -0
  12. package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +1 -0
  13. package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +1 -0
  14. package/src/preact/mutationsOverTime/__mockData__/noDataWhenNoMutationsAreInFilter.ts +1 -0
  15. package/src/preact/mutationsOverTime/__mockData__/noDataWhenThereAreNoDatesInFilter.ts +1 -0
  16. package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +1 -0
  17. package/src/preact/mutationsOverTime/__mockData__/withDisplayMutations.ts +352 -0
  18. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +0 -24
  19. package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +0 -8
  20. package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +2 -0
  21. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +2 -0
  22. package/src/preact/mutationsOverTime/mutations-over-time.tsx +11 -6
  23. package/src/query/queryMutationsOverTime.spec.ts +98 -0
  24. package/src/query/queryMutationsOverTime.ts +172 -28
  25. package/src/query/queryMutationsOverTimeNewEndpoint.spec.ts +1057 -0
  26. package/src/web-components/visualization/gs-mutations-over-time.spec-d.ts +3 -0
  27. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +3 -0
  28. package/src/web-components/visualization/gs-mutations-over-time.tsx +9 -0
  29. package/standalone-bundle/assets/mutationOverTimeWorker-CDACUs6w.js.map +1 -0
  30. package/standalone-bundle/dashboard-components.js +3628 -3594
  31. package/standalone-bundle/dashboard-components.js.map +1 -1
  32. package/dist/assets/mutationOverTimeWorker-DpW4YOGl.js.map +0 -1
  33. package/standalone-bundle/assets/mutationOverTimeWorker-CZVvQBze.js.map +0 -1
@@ -0,0 +1,1057 @@
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
+ it('should respect the includeMutations parameter', async () => {
913
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
914
+ const dateField = 'dateField';
915
+
916
+ lapisRequestMocks.multipleAggregated([
917
+ {
918
+ body: { ...lapisFilter, fields: [dateField] },
919
+ response: {
920
+ data: [
921
+ { count: 1, [dateField]: '2023-01-05' },
922
+ { count: 2, [dateField]: '2023-02-15' },
923
+ ],
924
+ },
925
+ },
926
+ {
927
+ body: {
928
+ ...lapisFilter,
929
+ dateFieldFrom: '2023-01-01',
930
+ dateFieldTo: '2023-01-31',
931
+ fields: [],
932
+ },
933
+ response: { data: [{ count: 11 }] },
934
+ },
935
+ {
936
+ body: {
937
+ ...lapisFilter,
938
+ dateFieldFrom: '2023-02-01',
939
+ dateFieldTo: '2023-02-28',
940
+ fields: [],
941
+ },
942
+ response: { data: [{ count: 12 }] },
943
+ },
944
+ ]);
945
+
946
+ lapisRequestMocks.multipleMutations(
947
+ [
948
+ {
949
+ body: {
950
+ ...lapisFilter,
951
+ dateFieldFrom: '2023-01-01',
952
+ dateFieldTo: '2023-02-28',
953
+ minProportion: 0.001,
954
+ },
955
+ response: {
956
+ data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
957
+ },
958
+ },
959
+ ],
960
+ 'nucleotide',
961
+ );
962
+
963
+ const dateRanges = [
964
+ {
965
+ dateFrom: '2023-01-01',
966
+ dateTo: '2023-01-31',
967
+ },
968
+ {
969
+ dateFrom: '2023-02-01',
970
+ dateTo: '2023-02-28',
971
+ },
972
+ ];
973
+
974
+ lapisRequestMocks.mutationsOverTime(
975
+ [
976
+ {
977
+ body: {
978
+ filters: lapisFilter,
979
+ dateRanges,
980
+ includeMutations: ['A122T', 'otherSequenceName:G234C'],
981
+ dateField,
982
+ },
983
+ response: {
984
+ data: {
985
+ data: [
986
+ [
987
+ { count: 0, coverage: 0 },
988
+ { count: 0, coverage: 0 },
989
+ ],
990
+ [
991
+ { count: 2, coverage: 10 },
992
+ { count: 3, coverage: 10 },
993
+ ],
994
+ ],
995
+ dateRanges,
996
+ mutations: ['A122T', 'otherSequenceName:G234C'],
997
+ },
998
+ },
999
+ },
1000
+ ],
1001
+ 'nucleotide',
1002
+ );
1003
+
1004
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
1005
+ lapisFilter,
1006
+ sequenceType: 'nucleotide',
1007
+ lapis: DUMMY_LAPIS_URL,
1008
+ lapisDateField: dateField,
1009
+ granularity: 'month',
1010
+ useNewEndpoint: true,
1011
+ displayMutations: ['otherSequenceName:G234C', 'A122T'],
1012
+ });
1013
+
1014
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
1015
+ [
1016
+ { type: 'value', proportion: NaN, count: 0, totalCount: 11 },
1017
+ { type: 'value', proportion: NaN, count: 0, totalCount: 12 },
1018
+ ],
1019
+ [
1020
+ { type: 'value', proportion: 0.2, count: 2, totalCount: 11 },
1021
+ { type: 'value', proportion: 0.3, count: 3, totalCount: 12 },
1022
+ ],
1023
+ ]);
1024
+
1025
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
1026
+ expect(sequences[0].code).toBe('A122T');
1027
+ expect(sequences[1].code).toBe('otherSequenceName:G234C');
1028
+
1029
+ const dates = mutationOverTimeData.getSecondAxisKeys();
1030
+ expect(dates[0].dateString).toBe('2023-01');
1031
+ expect(dates[1].dateString).toBe('2023-02');
1032
+ });
1033
+
1034
+ function getSomeTestMutation(proportion: number, count: number) {
1035
+ return {
1036
+ mutation: 'sequenceName:A123T',
1037
+ proportion,
1038
+ count,
1039
+ sequenceName: 'sequenceName',
1040
+ mutationFrom: 'A',
1041
+ mutationTo: 'T',
1042
+ position: 123,
1043
+ };
1044
+ }
1045
+
1046
+ function getSomeOtherTestMutation(proportion: number, count: number) {
1047
+ return {
1048
+ mutation: 'otherSequenceName:G234C',
1049
+ proportion,
1050
+ count,
1051
+ sequenceName: 'otherSequenceName',
1052
+ mutationFrom: 'G',
1053
+ mutationTo: 'C',
1054
+ position: 234,
1055
+ };
1056
+ }
1057
+ });