@malloydata/malloy-query-builder 0.0.237-dev250225144145

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.
@@ -0,0 +1,1777 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import * as Malloy from '@malloydata/malloy-interfaces';
9
+ import {flights_model} from './flights_model';
10
+ import './expects';
11
+ import {ASTQuery} from './query-ast';
12
+
13
+ function dedent(strs: TemplateStringsArray) {
14
+ const str = strs.join('');
15
+ let lines = str.split('\n');
16
+ const firstNonEmptyLine = lines.findIndex(l => l.trim().length > 0);
17
+ let lastNonEmptyLine = 0;
18
+ for (let i = lines.length - 1; i >= 0; i--) {
19
+ if (lines[i].trim().length > 0) {
20
+ lastNonEmptyLine = i;
21
+ break;
22
+ }
23
+ }
24
+ lines = lines.slice(firstNonEmptyLine, lastNonEmptyLine + 1);
25
+ let minIndent: number | undefined = undefined;
26
+ for (const line of lines) {
27
+ if (line.trim().length === 0) continue;
28
+ const indent = line.length - line.trimStart().length;
29
+ if (minIndent === undefined || indent < minIndent) minIndent = indent;
30
+ }
31
+ if (!minIndent) return str;
32
+ return lines.map(l => l.slice(minIndent)).join('\n');
33
+ }
34
+
35
+ describe('query builder', () => {
36
+ test('add an order by', () => {
37
+ const from: Malloy.Query = {
38
+ definition: {
39
+ kind: 'arrow',
40
+ source_reference: {name: 'flights'},
41
+ view: {
42
+ kind: 'segment',
43
+ operations: [
44
+ {
45
+ kind: 'group_by',
46
+ field: {
47
+ expression: {
48
+ kind: 'field_reference',
49
+ name: 'carrier',
50
+ },
51
+ },
52
+ },
53
+ ],
54
+ },
55
+ },
56
+ };
57
+ expect((q: ASTQuery) => {
58
+ q.getOrAddDefaultSegment().addOrderBy('carrier', 'asc');
59
+ }).toModifyQuery({
60
+ model: flights_model,
61
+ from,
62
+ to: {
63
+ definition: {
64
+ kind: 'arrow',
65
+ source_reference: {name: 'flights'},
66
+ view: {
67
+ kind: 'segment',
68
+ operations: [
69
+ {
70
+ kind: 'group_by',
71
+ field: {
72
+ expression: {
73
+ kind: 'field_reference',
74
+ name: 'carrier',
75
+ },
76
+ },
77
+ },
78
+ {
79
+ kind: 'order_by',
80
+ field_reference: {
81
+ name: 'carrier',
82
+ },
83
+ direction: 'asc',
84
+ },
85
+ ],
86
+ },
87
+ },
88
+ },
89
+ malloy: `run: flights -> {
90
+ group_by: carrier
91
+ order_by: carrier asc
92
+ }`,
93
+ });
94
+ });
95
+ test('add a group by', () => {
96
+ const from: Malloy.Query = {
97
+ definition: {
98
+ kind: 'arrow',
99
+ source_reference: {name: 'flights'},
100
+ view: {
101
+ kind: 'segment',
102
+ operations: [],
103
+ },
104
+ },
105
+ };
106
+ expect((q: ASTQuery) => {
107
+ q.getOrAddDefaultSegment().addGroupBy('carrier');
108
+ }).toModifyQuery({
109
+ model: flights_model,
110
+ from,
111
+ to: {
112
+ definition: {
113
+ kind: 'arrow',
114
+ source_reference: {name: 'flights'},
115
+ view: {
116
+ kind: 'segment',
117
+ operations: [
118
+ {
119
+ kind: 'group_by',
120
+ field: {
121
+ expression: {
122
+ kind: 'field_reference',
123
+ name: 'carrier',
124
+ },
125
+ },
126
+ },
127
+ ],
128
+ },
129
+ },
130
+ },
131
+ malloy: 'run: flights -> { group_by: carrier }',
132
+ });
133
+ });
134
+ test('add a group by with a new name', () => {
135
+ const from: Malloy.Query = {
136
+ definition: {
137
+ kind: 'arrow',
138
+ source_reference: {name: 'flights'},
139
+ view: {
140
+ kind: 'segment',
141
+ operations: [],
142
+ },
143
+ },
144
+ };
145
+ expect((q: ASTQuery) => {
146
+ q.getOrAddDefaultSegment().addGroupBy('carrier');
147
+ q.getOrAddDefaultSegment().addGroupBy('carrier', [], 'carrier_2');
148
+ }).toModifyQuery({
149
+ model: flights_model,
150
+ from,
151
+ to: {
152
+ definition: {
153
+ kind: 'arrow',
154
+ source_reference: {name: 'flights'},
155
+ view: {
156
+ kind: 'segment',
157
+ operations: [
158
+ {
159
+ kind: 'group_by',
160
+ field: {
161
+ expression: {
162
+ kind: 'field_reference',
163
+ name: 'carrier',
164
+ },
165
+ },
166
+ },
167
+ {
168
+ kind: 'group_by',
169
+ name: 'carrier_2',
170
+ field: {
171
+ expression: {
172
+ kind: 'field_reference',
173
+ name: 'carrier',
174
+ },
175
+ },
176
+ },
177
+ ],
178
+ },
179
+ },
180
+ },
181
+ malloy: dedent`
182
+ run: flights -> {
183
+ group_by:
184
+ carrier
185
+ carrier_2 is carrier
186
+ }
187
+ `,
188
+ });
189
+ });
190
+ test('add a group by in a join', () => {
191
+ const from: Malloy.Query = {
192
+ definition: {
193
+ kind: 'arrow',
194
+ source_reference: {name: 'flights'},
195
+ view: {
196
+ kind: 'segment',
197
+ operations: [],
198
+ },
199
+ },
200
+ };
201
+ expect((q: ASTQuery) => {
202
+ const segment = q.getOrAddDefaultSegment();
203
+ segment.addGroupBy('code', ['origin']);
204
+ segment.addOrderBy('code', 'asc');
205
+ }).toModifyQuery({
206
+ model: flights_model,
207
+ from,
208
+ to: {
209
+ definition: {
210
+ kind: 'arrow',
211
+ source_reference: {name: 'flights'},
212
+ view: {
213
+ kind: 'segment',
214
+ operations: [
215
+ {
216
+ kind: 'group_by',
217
+ field: {
218
+ expression: {
219
+ kind: 'field_reference',
220
+ name: 'code',
221
+ path: ['origin'],
222
+ },
223
+ },
224
+ },
225
+ {
226
+ kind: 'order_by',
227
+ field_reference: {name: 'code'},
228
+ direction: 'asc',
229
+ },
230
+ ],
231
+ },
232
+ },
233
+ },
234
+ malloy: dedent`
235
+ run: flights -> {
236
+ group_by: origin.code
237
+ order_by: code asc
238
+ }
239
+ `,
240
+ });
241
+ });
242
+ test('add an aggregate with a where', () => {
243
+ const from: Malloy.Query = {
244
+ definition: {
245
+ kind: 'arrow',
246
+ source_reference: {name: 'flights'},
247
+ view: {
248
+ kind: 'segment',
249
+ operations: [],
250
+ },
251
+ },
252
+ };
253
+ expect((q: ASTQuery) => {
254
+ q.getOrAddDefaultSegment()
255
+ .addAggregate('flight_count')
256
+ .addWhere('carrier', 'WN, AA');
257
+ }).toModifyQuery({
258
+ model: flights_model,
259
+ from,
260
+ to: {
261
+ definition: {
262
+ kind: 'arrow',
263
+ source_reference: {name: 'flights'},
264
+ view: {
265
+ kind: 'segment',
266
+ operations: [
267
+ {
268
+ kind: 'aggregate',
269
+ field: {
270
+ expression: {
271
+ kind: 'filtered_field',
272
+ field_reference: {name: 'flight_count'},
273
+ where: [
274
+ {
275
+ filter: {
276
+ kind: 'filter_string',
277
+ field_reference: {name: 'carrier'},
278
+ filter: 'WN, AA',
279
+ },
280
+ },
281
+ ],
282
+ },
283
+ },
284
+ },
285
+ ],
286
+ },
287
+ },
288
+ },
289
+ malloy:
290
+ 'run: flights -> { aggregate: flight_count { where: carrier ~ f`WN, AA` } }',
291
+ });
292
+ });
293
+ test('add a where', () => {
294
+ const from: Malloy.Query = {
295
+ definition: {
296
+ kind: 'arrow',
297
+ source_reference: {name: 'flights'},
298
+ view: {
299
+ kind: 'segment',
300
+ operations: [],
301
+ },
302
+ },
303
+ };
304
+ expect((q: ASTQuery) => {
305
+ q.getOrAddDefaultSegment().addWhere('carrier', 'WN, AA');
306
+ }).toModifyQuery({
307
+ model: flights_model,
308
+ from,
309
+ to: {
310
+ definition: {
311
+ kind: 'arrow',
312
+ source_reference: {name: 'flights'},
313
+ view: {
314
+ kind: 'segment',
315
+ operations: [
316
+ {
317
+ kind: 'where',
318
+ filter: {
319
+ kind: 'filter_string',
320
+ field_reference: {name: 'carrier'},
321
+ filter: 'WN, AA',
322
+ },
323
+ },
324
+ ],
325
+ },
326
+ },
327
+ },
328
+ malloy: 'run: flights -> { where: carrier ~ f`WN, AA` }',
329
+ });
330
+ });
331
+ test('add a parsed where', () => {
332
+ const from: Malloy.Query = {
333
+ definition: {
334
+ kind: 'arrow',
335
+ source_reference: {name: 'flights'},
336
+ view: {
337
+ kind: 'segment',
338
+ operations: [],
339
+ },
340
+ },
341
+ };
342
+ expect((q: ASTQuery) => {
343
+ q.getOrAddDefaultSegment().addWhere('carrier', {
344
+ kind: 'string',
345
+ clauses: [{operator: '=', values: ['WN', 'AA']}],
346
+ });
347
+ }).toModifyQuery({
348
+ model: flights_model,
349
+ from,
350
+ to: {
351
+ definition: {
352
+ kind: 'arrow',
353
+ source_reference: {name: 'flights'},
354
+ view: {
355
+ kind: 'segment',
356
+ operations: [
357
+ {
358
+ kind: 'where',
359
+ filter: {
360
+ kind: 'filter_string',
361
+ field_reference: {name: 'carrier'},
362
+ filter: 'WN, AA',
363
+ },
364
+ },
365
+ ],
366
+ },
367
+ },
368
+ },
369
+ malloy: 'run: flights -> { where: carrier ~ f`WN, AA` }',
370
+ });
371
+ });
372
+ test('add some parsed wheres with different quote requirements', () => {
373
+ const from: Malloy.Query = {
374
+ definition: {
375
+ kind: 'arrow',
376
+ source_reference: {name: 'flights'},
377
+ view: {
378
+ kind: 'segment',
379
+ operations: [],
380
+ },
381
+ },
382
+ };
383
+ expect((q: ASTQuery) => {
384
+ const segment = q.getOrAddDefaultSegment();
385
+ function add(str: string) {
386
+ segment.addWhere('carrier', {
387
+ kind: 'string',
388
+ clauses: [{operator: '=', values: [str]}],
389
+ });
390
+ }
391
+ add("'");
392
+ add('\'"');
393
+ add('`');
394
+ add("`'");
395
+ add('`\'"');
396
+ add("`'\"\"\"'''");
397
+ }).toModifyQuery({
398
+ model: flights_model,
399
+ from,
400
+ to: {
401
+ definition: {
402
+ kind: 'arrow',
403
+ source_reference: {name: 'flights'},
404
+ view: {
405
+ kind: 'segment',
406
+ operations: [
407
+ {
408
+ kind: 'where',
409
+ filter: {
410
+ kind: 'filter_string',
411
+ field_reference: {name: 'carrier'},
412
+ filter: "'",
413
+ },
414
+ },
415
+ {
416
+ kind: 'where',
417
+ filter: {
418
+ kind: 'filter_string',
419
+ field_reference: {name: 'carrier'},
420
+ filter: '\'"',
421
+ },
422
+ },
423
+ {
424
+ kind: 'where',
425
+ filter: {
426
+ kind: 'filter_string',
427
+ field_reference: {name: 'carrier'},
428
+ filter: '`',
429
+ },
430
+ },
431
+ {
432
+ kind: 'where',
433
+ filter: {
434
+ kind: 'filter_string',
435
+ field_reference: {name: 'carrier'},
436
+ filter: "`'",
437
+ },
438
+ },
439
+ {
440
+ kind: 'where',
441
+ filter: {
442
+ kind: 'filter_string',
443
+ field_reference: {name: 'carrier'},
444
+ filter: '`\'"',
445
+ },
446
+ },
447
+ {
448
+ kind: 'where',
449
+ filter: {
450
+ kind: 'filter_string',
451
+ field_reference: {name: 'carrier'},
452
+ filter: "`'\"\"\"'''",
453
+ },
454
+ },
455
+ ],
456
+ },
457
+ },
458
+ },
459
+ malloy: dedent`
460
+ run: flights -> {
461
+ where:
462
+ carrier ~ f\`'\`
463
+ carrier ~ f\`'"\`
464
+ carrier ~ f'\`'
465
+ carrier ~ f"\`'"
466
+ carrier ~ f\`\\\`"\`
467
+ carrier ~ f\`\\\`"""'''\`
468
+ }`,
469
+ });
470
+ });
471
+ test('add a date group by', () => {
472
+ const from: Malloy.Query = {
473
+ definition: {
474
+ kind: 'arrow',
475
+ source_reference: {name: 'flights'},
476
+ view: {
477
+ kind: 'segment',
478
+ operations: [],
479
+ },
480
+ },
481
+ };
482
+ expect((q: ASTQuery) => {
483
+ q.getOrAddDefaultSegment().addTimestampGroupBy('dep_time', 'month');
484
+ }).toModifyQuery({
485
+ model: flights_model,
486
+ from,
487
+ to: {
488
+ definition: {
489
+ kind: 'arrow',
490
+ source_reference: {name: 'flights'},
491
+ view: {
492
+ kind: 'segment',
493
+ operations: [
494
+ {
495
+ kind: 'group_by',
496
+ field: {
497
+ expression: {
498
+ kind: 'time_truncation',
499
+ field_reference: {name: 'dep_time'},
500
+ truncation: 'month',
501
+ },
502
+ },
503
+ },
504
+ ],
505
+ },
506
+ },
507
+ },
508
+ malloy: 'run: flights -> { group_by: dep_time.month }',
509
+ });
510
+ });
511
+ test('add two group bys', () => {
512
+ const from: Malloy.Query = {
513
+ definition: {
514
+ kind: 'arrow',
515
+ source_reference: {name: 'flights'},
516
+ view: {
517
+ kind: 'segment',
518
+ operations: [],
519
+ },
520
+ },
521
+ };
522
+ expect((q: ASTQuery) => {
523
+ const seg = q.getOrAddDefaultSegment();
524
+ seg.addGroupBy('carrier');
525
+ seg.addGroupBy('origin_code');
526
+ }).toModifyQuery({
527
+ model: flights_model,
528
+ from,
529
+ to: {
530
+ definition: {
531
+ kind: 'arrow',
532
+ source_reference: {name: 'flights'},
533
+ view: {
534
+ kind: 'segment',
535
+ operations: [
536
+ {
537
+ kind: 'group_by',
538
+ field: {
539
+ expression: {
540
+ kind: 'field_reference',
541
+ name: 'carrier',
542
+ },
543
+ },
544
+ },
545
+ {
546
+ kind: 'group_by',
547
+ field: {
548
+ expression: {
549
+ kind: 'field_reference',
550
+ name: 'origin_code',
551
+ },
552
+ },
553
+ },
554
+ ],
555
+ },
556
+ },
557
+ },
558
+ malloy: dedent`
559
+ run: flights -> {
560
+ group_by:
561
+ carrier
562
+ origin_code
563
+ }`,
564
+ });
565
+ });
566
+ test('reorder fields', () => {
567
+ const from: Malloy.Query = {
568
+ definition: {
569
+ kind: 'arrow',
570
+ source_reference: {name: 'flights'},
571
+ view: {
572
+ kind: 'segment',
573
+ operations: [
574
+ {
575
+ kind: 'group_by',
576
+ field: {
577
+ expression: {
578
+ kind: 'field_reference',
579
+ name: 'carrier',
580
+ },
581
+ },
582
+ },
583
+ {
584
+ kind: 'group_by',
585
+ field: {
586
+ expression: {
587
+ kind: 'field_reference',
588
+ name: 'origin_code',
589
+ },
590
+ },
591
+ },
592
+ ],
593
+ },
594
+ },
595
+ };
596
+ expect((q: ASTQuery) => {
597
+ const seg = q.getOrAddDefaultSegment();
598
+ seg.reorderFields(['origin_code', 'carrier']);
599
+ }).toModifyQuery({
600
+ model: flights_model,
601
+ from,
602
+ to: {
603
+ definition: {
604
+ kind: 'arrow',
605
+ source_reference: {name: 'flights'},
606
+ view: {
607
+ kind: 'segment',
608
+ operations: [
609
+ {
610
+ kind: 'group_by',
611
+ field: {
612
+ expression: {
613
+ kind: 'field_reference',
614
+ name: 'origin_code',
615
+ },
616
+ },
617
+ },
618
+ {
619
+ kind: 'group_by',
620
+ field: {
621
+ expression: {
622
+ kind: 'field_reference',
623
+ name: 'carrier',
624
+ },
625
+ },
626
+ },
627
+ ],
628
+ },
629
+ },
630
+ },
631
+ malloy: dedent`
632
+ run: flights -> {
633
+ group_by:
634
+ origin_code
635
+ carrier
636
+ }`,
637
+ });
638
+ });
639
+ test('add a nest', () => {
640
+ const from: Malloy.Query = {
641
+ definition: {
642
+ kind: 'arrow',
643
+ source_reference: {name: 'flights'},
644
+ view: {
645
+ kind: 'segment',
646
+ operations: [],
647
+ },
648
+ },
649
+ };
650
+ expect((q: ASTQuery) => {
651
+ const seg = q.getOrAddDefaultSegment();
652
+ const nest = seg.addEmptyNest('by_carrier');
653
+ const seg2 = nest.view.getOrAddDefaultSegment();
654
+ seg2.addGroupBy('carrier');
655
+ }).toModifyQuery({
656
+ model: flights_model,
657
+ from,
658
+ to: {
659
+ definition: {
660
+ kind: 'arrow',
661
+ source_reference: {name: 'flights'},
662
+ view: {
663
+ kind: 'segment',
664
+ operations: [
665
+ {
666
+ kind: 'nest',
667
+ name: 'by_carrier',
668
+ view: {
669
+ definition: {
670
+ kind: 'segment',
671
+ operations: [
672
+ {
673
+ kind: 'group_by',
674
+ field: {
675
+ expression: {
676
+ kind: 'field_reference',
677
+ name: 'carrier',
678
+ },
679
+ },
680
+ },
681
+ ],
682
+ },
683
+ },
684
+ },
685
+ ],
686
+ },
687
+ },
688
+ },
689
+ malloy: 'run: flights -> { nest: by_carrier is { group_by: carrier } }',
690
+ });
691
+ });
692
+ test('nest via field reference', () => {
693
+ const from: Malloy.Query = {
694
+ definition: {
695
+ kind: 'arrow',
696
+ source_reference: {name: 'flights'},
697
+ view: {
698
+ kind: 'segment',
699
+ operations: [],
700
+ },
701
+ },
702
+ };
703
+ expect((q: ASTQuery) => {
704
+ const seg = q.getOrAddDefaultSegment();
705
+ seg.addNest('by_month');
706
+ }).toModifyQuery({
707
+ model: flights_model,
708
+ from,
709
+ to: {
710
+ definition: {
711
+ kind: 'arrow',
712
+ source_reference: {name: 'flights'},
713
+ view: {
714
+ kind: 'segment',
715
+ operations: [
716
+ {
717
+ kind: 'nest',
718
+ view: {
719
+ definition: {
720
+ kind: 'view_reference',
721
+ name: 'by_month',
722
+ },
723
+ },
724
+ },
725
+ ],
726
+ },
727
+ },
728
+ },
729
+ malloy: 'run: flights -> { nest: by_month }',
730
+ });
731
+ });
732
+ test('set view reference', () => {
733
+ const from: Malloy.Query = {
734
+ definition: {
735
+ kind: 'arrow',
736
+ source_reference: {name: 'flights'},
737
+ view: {
738
+ kind: 'segment',
739
+ operations: [],
740
+ },
741
+ },
742
+ };
743
+ expect((q: ASTQuery) => {
744
+ q.setView('by_month');
745
+ }).toModifyQuery({
746
+ model: flights_model,
747
+ from,
748
+ to: {
749
+ definition: {
750
+ kind: 'arrow',
751
+ source_reference: {name: 'flights'},
752
+ view: {
753
+ kind: 'view_reference',
754
+ name: 'by_month',
755
+ },
756
+ },
757
+ },
758
+ malloy: 'run: flights -> by_month',
759
+ });
760
+ });
761
+ test('reorder fields in a view reference', () => {
762
+ const from: Malloy.Query = {
763
+ definition: {
764
+ kind: 'arrow',
765
+ source_reference: {name: 'flights'},
766
+ view: {
767
+ kind: 'segment',
768
+ operations: [],
769
+ },
770
+ },
771
+ };
772
+ expect((q: ASTQuery) => {
773
+ q.setView('by_month');
774
+ q.reorderFields(['flight_count', 'dep_month']);
775
+ }).toModifyQuery({
776
+ model: flights_model,
777
+ from,
778
+ to: {
779
+ definition: {
780
+ kind: 'arrow',
781
+ source_reference: {name: 'flights'},
782
+ view: {
783
+ kind: 'view_reference',
784
+ name: 'by_month',
785
+ },
786
+ },
787
+ },
788
+ malloy: dedent`
789
+ # field_order = [flight_count, dep_month]
790
+ run: flights -> by_month
791
+ `,
792
+ });
793
+ });
794
+ test('set view with segment refinement', () => {
795
+ const from: Malloy.Query = {
796
+ definition: {
797
+ kind: 'arrow',
798
+ source_reference: {name: 'flights'},
799
+ view: {
800
+ kind: 'segment',
801
+ operations: [],
802
+ },
803
+ },
804
+ };
805
+ expect((q: ASTQuery) => {
806
+ const view = q.setView('by_month');
807
+ const segment = view.addEmptyRefinement();
808
+ segment.setLimit(10);
809
+ }).toModifyQuery({
810
+ model: flights_model,
811
+ from,
812
+ to: {
813
+ definition: {
814
+ kind: 'arrow',
815
+ source_reference: {name: 'flights'},
816
+ view: {
817
+ kind: 'refinement',
818
+ base: {
819
+ kind: 'view_reference',
820
+ name: 'by_month',
821
+ },
822
+ refinement: {
823
+ kind: 'segment',
824
+ operations: [
825
+ {
826
+ kind: 'limit',
827
+ limit: 10,
828
+ },
829
+ ],
830
+ },
831
+ },
832
+ },
833
+ },
834
+ malloy: 'run: flights -> by_month + { limit: 10 }',
835
+ });
836
+ });
837
+ test('add an order by in a refinement', () => {
838
+ const from: Malloy.Query = {
839
+ definition: {
840
+ kind: 'arrow',
841
+ source_reference: {name: 'flights'},
842
+ view: {
843
+ kind: 'view_reference',
844
+ name: 'by_month',
845
+ },
846
+ },
847
+ };
848
+ expect((q: ASTQuery) => {
849
+ q.getOrAddDefaultSegment().addOrderBy('dep_month', 'asc');
850
+ }).toModifyQuery({
851
+ model: flights_model,
852
+ from,
853
+ to: {
854
+ definition: {
855
+ kind: 'arrow',
856
+ source_reference: {name: 'flights'},
857
+ view: {
858
+ kind: 'refinement',
859
+ base: {
860
+ kind: 'view_reference',
861
+ name: 'by_month',
862
+ },
863
+ refinement: {
864
+ kind: 'segment',
865
+ operations: [
866
+ {
867
+ kind: 'order_by',
868
+ field_reference: {name: 'dep_month'},
869
+ direction: 'asc',
870
+ },
871
+ ],
872
+ },
873
+ },
874
+ },
875
+ },
876
+ malloy: 'run: flights -> by_month + { order_by: dep_month asc }',
877
+ });
878
+ });
879
+ test('do nothing', () => {
880
+ expect((_q: ASTQuery) => {}).toModifyQuery({
881
+ model: flights_model,
882
+ from: {
883
+ definition: {
884
+ kind: 'arrow',
885
+ source_reference: {name: 'flights'},
886
+ view: {
887
+ kind: 'segment',
888
+ operations: [],
889
+ },
890
+ },
891
+ },
892
+ to: {
893
+ definition: {
894
+ kind: 'arrow',
895
+ source_reference: {name: 'flights'},
896
+ view: {
897
+ kind: 'segment',
898
+ operations: [],
899
+ },
900
+ },
901
+ },
902
+ malloy: 'run: flights -> { }',
903
+ });
904
+ });
905
+ test('set view reference with named refinement', () => {
906
+ const from: Malloy.Query = {
907
+ definition: {
908
+ kind: 'arrow',
909
+ source_reference: {name: 'flights'},
910
+ view: {
911
+ kind: 'view_reference',
912
+ name: 'by_carrier',
913
+ },
914
+ },
915
+ };
916
+ expect((q: ASTQuery) => {
917
+ q.definition
918
+ .asArrowQueryDefinition()
919
+ .view.addViewRefinement('cool_state_measures');
920
+ }).toModifyQuery({
921
+ source: {
922
+ name: 'flights',
923
+ schema: {
924
+ fields: [
925
+ {
926
+ kind: 'dimension',
927
+ name: 'carrier',
928
+ type: {kind: 'string_type'},
929
+ },
930
+ {
931
+ kind: 'measure',
932
+ name: 'flight_count',
933
+ type: {kind: 'number_type'},
934
+ },
935
+ {
936
+ kind: 'view',
937
+ name: 'by_carrier',
938
+ schema: {
939
+ fields: [
940
+ {
941
+ kind: 'dimension',
942
+ name: 'carrier',
943
+ type: {kind: 'string_type'},
944
+ },
945
+ {
946
+ kind: 'measure',
947
+ name: 'flight_count',
948
+ type: {kind: 'number_type'},
949
+ },
950
+ ],
951
+ },
952
+ },
953
+ {
954
+ kind: 'view',
955
+ name: 'cool_state_measures',
956
+ schema: {
957
+ fields: [
958
+ {
959
+ kind: 'measure',
960
+ name: 'il_flight_count',
961
+ type: {kind: 'number_type'},
962
+ },
963
+ {
964
+ kind: 'measure',
965
+ name: 'ca_flight_count',
966
+ type: {kind: 'number_type'},
967
+ },
968
+ ],
969
+ },
970
+ },
971
+ ],
972
+ },
973
+ },
974
+ from,
975
+ to: {
976
+ definition: {
977
+ kind: 'arrow',
978
+ source_reference: {name: 'flights'},
979
+ view: {
980
+ kind: 'refinement',
981
+ base: {
982
+ kind: 'view_reference',
983
+ name: 'by_carrier',
984
+ },
985
+ refinement: {
986
+ kind: 'view_reference',
987
+ name: 'cool_state_measures',
988
+ },
989
+ },
990
+ },
991
+ },
992
+ malloy: 'run: flights -> by_carrier + cool_state_measures',
993
+ });
994
+ });
995
+ test('add limit', () => {
996
+ const from: Malloy.Query = {
997
+ definition: {
998
+ kind: 'arrow',
999
+ source_reference: {name: 'flights'},
1000
+ view: {
1001
+ kind: 'segment',
1002
+ operations: [],
1003
+ },
1004
+ },
1005
+ };
1006
+ expect((q: ASTQuery) => {
1007
+ const seg = q.getOrAddDefaultSegment();
1008
+ seg.setLimit(10);
1009
+ }).toModifyQuery({
1010
+ model: flights_model,
1011
+ from,
1012
+ to: {
1013
+ definition: {
1014
+ kind: 'arrow',
1015
+ source_reference: {name: 'flights'},
1016
+ view: {
1017
+ kind: 'segment',
1018
+ operations: [
1019
+ {
1020
+ kind: 'limit',
1021
+ limit: 10,
1022
+ },
1023
+ ],
1024
+ },
1025
+ },
1026
+ },
1027
+ malloy: 'run: flights -> { limit: 10 }',
1028
+ });
1029
+ });
1030
+ test('change limit', () => {
1031
+ const from: Malloy.Query = {
1032
+ definition: {
1033
+ kind: 'arrow',
1034
+ source_reference: {name: 'flights'},
1035
+ view: {
1036
+ kind: 'segment',
1037
+ operations: [
1038
+ {
1039
+ kind: 'limit',
1040
+ limit: 10,
1041
+ },
1042
+ ],
1043
+ },
1044
+ },
1045
+ };
1046
+ expect((q: ASTQuery) => {
1047
+ const seg = q.getOrAddDefaultSegment();
1048
+ seg.setLimit(20);
1049
+ }).toModifyQuery({
1050
+ model: flights_model,
1051
+ from,
1052
+ to: {
1053
+ definition: {
1054
+ kind: 'arrow',
1055
+ source_reference: {name: 'flights'},
1056
+ view: {
1057
+ kind: 'segment',
1058
+ operations: [
1059
+ {
1060
+ kind: 'limit',
1061
+ limit: 20,
1062
+ },
1063
+ ],
1064
+ },
1065
+ },
1066
+ },
1067
+ malloy: 'run: flights -> { limit: 20 }',
1068
+ });
1069
+ });
1070
+ describe('tags', () => {
1071
+ test('add a tag property to a group by', () => {
1072
+ const from: Malloy.Query = {
1073
+ definition: {
1074
+ kind: 'arrow',
1075
+ source_reference: {name: 'flights'},
1076
+ view: {
1077
+ kind: 'segment',
1078
+ operations: [],
1079
+ },
1080
+ },
1081
+ };
1082
+ expect((q: ASTQuery) => {
1083
+ const gb = q.getOrAddDefaultSegment().addGroupBy('carrier');
1084
+ gb.setTagProperty(['a', 'b', 'c'], 10);
1085
+ }).toModifyQuery({
1086
+ model: flights_model,
1087
+ from,
1088
+ to: {
1089
+ definition: {
1090
+ kind: 'arrow',
1091
+ source_reference: {name: 'flights'},
1092
+ view: {
1093
+ kind: 'segment',
1094
+ operations: [
1095
+ {
1096
+ kind: 'group_by',
1097
+ field: {
1098
+ annotations: [{value: '# a.b.c = 10'}],
1099
+ expression: {
1100
+ kind: 'field_reference',
1101
+ name: 'carrier',
1102
+ },
1103
+ },
1104
+ },
1105
+ ],
1106
+ },
1107
+ },
1108
+ },
1109
+ malloy: dedent`
1110
+ run: flights -> {
1111
+ # a.b.c = 10
1112
+ group_by: carrier
1113
+ }`,
1114
+ });
1115
+ });
1116
+ test('add tag to query', () => {
1117
+ const from: Malloy.Query = {
1118
+ definition: {
1119
+ kind: 'arrow',
1120
+ source_reference: {name: 'flights'},
1121
+ view: {
1122
+ kind: 'segment',
1123
+ operations: [],
1124
+ },
1125
+ },
1126
+ };
1127
+ expect((q: ASTQuery) => {
1128
+ q.setTagProperty(['a'], 'foo');
1129
+ }).toModifyQuery({
1130
+ model: flights_model,
1131
+ from,
1132
+ to: {
1133
+ definition: {
1134
+ kind: 'arrow',
1135
+ source_reference: {name: 'flights'},
1136
+ view: {
1137
+ kind: 'segment',
1138
+ operations: [],
1139
+ },
1140
+ },
1141
+ annotations: [{value: '# a = foo'}],
1142
+ },
1143
+ malloy: dedent`
1144
+ # a = foo
1145
+ run: flights -> { }
1146
+ `,
1147
+ });
1148
+ });
1149
+ test('clear an inherited tag', () => {
1150
+ const from: Malloy.Query = {
1151
+ definition: {
1152
+ kind: 'arrow',
1153
+ source_reference: {name: 'flights'},
1154
+ view: {
1155
+ kind: 'segment',
1156
+ operations: [],
1157
+ },
1158
+ },
1159
+ };
1160
+ expect((q: ASTQuery) => {
1161
+ q.getOrAddDefaultSegment()
1162
+ .addGroupBy('carrier')
1163
+ .removeTagProperty(['a']);
1164
+ }).toModifyQuery({
1165
+ source: {
1166
+ name: 'flights',
1167
+ schema: {
1168
+ fields: [
1169
+ {
1170
+ kind: 'dimension',
1171
+ name: 'carrier',
1172
+ type: {kind: 'string_type'},
1173
+ annotations: [{value: '# a'}],
1174
+ },
1175
+ ],
1176
+ },
1177
+ },
1178
+ from,
1179
+ to: {
1180
+ definition: {
1181
+ kind: 'arrow',
1182
+ source_reference: {name: 'flights'},
1183
+ view: {
1184
+ kind: 'segment',
1185
+ operations: [
1186
+ {
1187
+ kind: 'group_by',
1188
+ field: {
1189
+ annotations: [{value: '# -a'}],
1190
+ expression: {
1191
+ kind: 'field_reference',
1192
+ name: 'carrier',
1193
+ },
1194
+ },
1195
+ },
1196
+ ],
1197
+ },
1198
+ },
1199
+ },
1200
+ malloy: dedent`
1201
+ run: flights -> {
1202
+ # -a
1203
+ group_by: carrier
1204
+ }`,
1205
+ });
1206
+ });
1207
+ });
1208
+ test('rename a group by', () => {
1209
+ const from: Malloy.Query = {
1210
+ definition: {
1211
+ kind: 'arrow',
1212
+ source_reference: {name: 'flights'},
1213
+ view: {
1214
+ kind: 'segment',
1215
+ operations: [
1216
+ {
1217
+ kind: 'group_by',
1218
+ field: {
1219
+ expression: {
1220
+ kind: 'field_reference',
1221
+ name: 'carrier',
1222
+ },
1223
+ },
1224
+ },
1225
+ {
1226
+ kind: 'order_by',
1227
+ field_reference: {name: 'carrier'},
1228
+ },
1229
+ ],
1230
+ },
1231
+ },
1232
+ };
1233
+ expect((q: ASTQuery) => {
1234
+ q.getOrAddDefaultSegment().getGroupBy('carrier')!.rename('carrier_2');
1235
+ }).toModifyQuery({
1236
+ model: flights_model,
1237
+ from,
1238
+ to: {
1239
+ definition: {
1240
+ kind: 'arrow',
1241
+ source_reference: {name: 'flights'},
1242
+ view: {
1243
+ kind: 'segment',
1244
+ operations: [
1245
+ {
1246
+ kind: 'group_by',
1247
+ name: 'carrier_2',
1248
+ field: {
1249
+ expression: {
1250
+ kind: 'field_reference',
1251
+ name: 'carrier',
1252
+ },
1253
+ },
1254
+ },
1255
+ {
1256
+ kind: 'order_by',
1257
+ field_reference: {
1258
+ name: 'carrier_2',
1259
+ },
1260
+ },
1261
+ ],
1262
+ },
1263
+ },
1264
+ },
1265
+ malloy: `run: flights -> {
1266
+ group_by: carrier_2 is carrier
1267
+ order_by: carrier_2
1268
+ }`,
1269
+ });
1270
+ });
1271
+ test('rename a group by should change order by in refinement', () => {
1272
+ const from: Malloy.Query = {
1273
+ definition: {
1274
+ kind: 'arrow',
1275
+ source_reference: {name: 'flights'},
1276
+ view: {
1277
+ kind: 'refinement',
1278
+ base: {
1279
+ kind: 'segment',
1280
+ operations: [
1281
+ {
1282
+ kind: 'group_by',
1283
+ field: {
1284
+ expression: {
1285
+ kind: 'field_reference',
1286
+ name: 'carrier',
1287
+ },
1288
+ },
1289
+ },
1290
+ ],
1291
+ },
1292
+ refinement: {
1293
+ kind: 'segment',
1294
+ operations: [
1295
+ {
1296
+ kind: 'order_by',
1297
+ field_reference: {name: 'carrier'},
1298
+ },
1299
+ ],
1300
+ },
1301
+ },
1302
+ },
1303
+ };
1304
+ expect((q: ASTQuery) => {
1305
+ const segment = q.definition
1306
+ .asArrowQueryDefinition()
1307
+ .view.asRefinementViewDefinition()
1308
+ .base.asSegmentViewDefinition();
1309
+ segment.getGroupBy('carrier')!.rename('carrier_2');
1310
+ }).toModifyQuery({
1311
+ model: flights_model,
1312
+ from,
1313
+ to: {
1314
+ definition: {
1315
+ kind: 'arrow',
1316
+ source_reference: {name: 'flights'},
1317
+ view: {
1318
+ kind: 'refinement',
1319
+ base: {
1320
+ kind: 'segment',
1321
+ operations: [
1322
+ {
1323
+ kind: 'group_by',
1324
+ name: 'carrier_2',
1325
+ field: {
1326
+ expression: {
1327
+ kind: 'field_reference',
1328
+ name: 'carrier',
1329
+ },
1330
+ },
1331
+ },
1332
+ ],
1333
+ },
1334
+ refinement: {
1335
+ kind: 'segment',
1336
+ operations: [
1337
+ {
1338
+ kind: 'order_by',
1339
+ field_reference: {name: 'carrier_2'},
1340
+ },
1341
+ ],
1342
+ },
1343
+ },
1344
+ },
1345
+ },
1346
+ malloy:
1347
+ 'run: flights -> { group_by: carrier_2 is carrier } + { order_by: carrier_2 }',
1348
+ });
1349
+ });
1350
+ test('deleting a group by should delete order by in refinement', () => {
1351
+ const from: Malloy.Query = {
1352
+ definition: {
1353
+ kind: 'arrow',
1354
+ source_reference: {name: 'flights'},
1355
+ view: {
1356
+ kind: 'refinement',
1357
+ base: {
1358
+ kind: 'segment',
1359
+ operations: [
1360
+ {
1361
+ kind: 'group_by',
1362
+ field: {
1363
+ expression: {
1364
+ kind: 'field_reference',
1365
+ name: 'carrier',
1366
+ },
1367
+ },
1368
+ },
1369
+ ],
1370
+ },
1371
+ refinement: {
1372
+ kind: 'segment',
1373
+ operations: [
1374
+ {
1375
+ kind: 'order_by',
1376
+ field_reference: {name: 'carrier'},
1377
+ },
1378
+ ],
1379
+ },
1380
+ },
1381
+ },
1382
+ };
1383
+ expect((q: ASTQuery) => {
1384
+ const segment = q.definition
1385
+ .asArrowQueryDefinition()
1386
+ .view.asRefinementViewDefinition()
1387
+ .base.asSegmentViewDefinition();
1388
+ segment.getGroupBy('carrier')!.delete();
1389
+ }).toModifyQuery({
1390
+ model: flights_model,
1391
+ from,
1392
+ to: {
1393
+ definition: {
1394
+ kind: 'arrow',
1395
+ source_reference: {name: 'flights'},
1396
+ view: {
1397
+ kind: 'refinement',
1398
+ base: {
1399
+ kind: 'segment',
1400
+ operations: [],
1401
+ },
1402
+ refinement: {
1403
+ kind: 'segment',
1404
+ operations: [],
1405
+ },
1406
+ },
1407
+ },
1408
+ },
1409
+ malloy: 'run: flights -> { } + { }',
1410
+ });
1411
+ });
1412
+ test.skip('deleting a group by should remove a group by in subsequent stage', () => {
1413
+ const from: Malloy.Query = {
1414
+ definition: {
1415
+ kind: 'arrow',
1416
+ source_reference: {name: 'flights'},
1417
+ view: {
1418
+ kind: 'arrow',
1419
+ source: {
1420
+ kind: 'segment',
1421
+ operations: [
1422
+ {
1423
+ kind: 'group_by',
1424
+ field: {
1425
+ expression: {
1426
+ kind: 'field_reference',
1427
+ name: 'carrier',
1428
+ },
1429
+ },
1430
+ },
1431
+ ],
1432
+ },
1433
+ view: {
1434
+ kind: 'segment',
1435
+ operations: [
1436
+ {
1437
+ kind: 'group_by',
1438
+ field: {
1439
+ expression: {
1440
+ kind: 'field_reference',
1441
+ name: 'carrier',
1442
+ },
1443
+ },
1444
+ },
1445
+ ],
1446
+ },
1447
+ },
1448
+ },
1449
+ };
1450
+ expect((q: ASTQuery) => {
1451
+ const segment = q.definition
1452
+ .asArrowQueryDefinition()
1453
+ .view.asArrowViewDefinition()
1454
+ .source.asSegmentViewDefinition();
1455
+ segment.getGroupBy('carrier')!.delete();
1456
+ }).toModifyQuery({
1457
+ model: flights_model,
1458
+ from,
1459
+ to: {
1460
+ definition: {
1461
+ kind: 'arrow',
1462
+ source_reference: {name: 'flights'},
1463
+ view: {
1464
+ kind: 'arrow',
1465
+ source: {
1466
+ kind: 'segment',
1467
+ operations: [],
1468
+ },
1469
+ view: {
1470
+ kind: 'segment',
1471
+ operations: [],
1472
+ },
1473
+ },
1474
+ },
1475
+ },
1476
+ malloy: 'run: flights -> { } -> { }',
1477
+ });
1478
+ });
1479
+ describe('getOrAddDefaultSegment', () => {
1480
+ test('on an arrow query with a segment', () => {
1481
+ expect((q: ASTQuery) => {
1482
+ q.getOrAddDefaultSegment();
1483
+ }).toModifyQuery({
1484
+ model: flights_model,
1485
+ from: {
1486
+ definition: {
1487
+ kind: 'arrow',
1488
+ source_reference: {name: 'flights'},
1489
+ view: {
1490
+ kind: 'segment',
1491
+ operations: [],
1492
+ },
1493
+ },
1494
+ },
1495
+ to: {
1496
+ definition: {
1497
+ kind: 'arrow',
1498
+ source_reference: {name: 'flights'},
1499
+ view: {
1500
+ kind: 'segment',
1501
+ operations: [],
1502
+ },
1503
+ },
1504
+ },
1505
+ malloy: 'run: flights -> { }',
1506
+ });
1507
+ });
1508
+ test('on an arrow query with a view reference', () => {
1509
+ expect((q: ASTQuery) => {
1510
+ q.getOrAddDefaultSegment();
1511
+ }).toModifyQuery({
1512
+ model: flights_model,
1513
+ from: {
1514
+ definition: {
1515
+ kind: 'arrow',
1516
+ source_reference: {name: 'flights'},
1517
+ view: {
1518
+ kind: 'view_reference',
1519
+ name: 'by_month',
1520
+ },
1521
+ },
1522
+ },
1523
+ to: {
1524
+ definition: {
1525
+ kind: 'arrow',
1526
+ source_reference: {name: 'flights'},
1527
+ view: {
1528
+ kind: 'refinement',
1529
+ base: {
1530
+ kind: 'view_reference',
1531
+ name: 'by_month',
1532
+ },
1533
+ refinement: {
1534
+ kind: 'segment',
1535
+ operations: [],
1536
+ },
1537
+ },
1538
+ },
1539
+ },
1540
+ malloy: 'run: flights -> by_month + { }',
1541
+ });
1542
+ });
1543
+ test('on an arrow query with a view reference that already has a segment refinement', () => {
1544
+ expect((q: ASTQuery) => {
1545
+ q.getOrAddDefaultSegment();
1546
+ }).toModifyQuery({
1547
+ model: flights_model,
1548
+ from: {
1549
+ definition: {
1550
+ kind: 'arrow',
1551
+ source_reference: {name: 'flights'},
1552
+ view: {
1553
+ kind: 'refinement',
1554
+ base: {
1555
+ kind: 'view_reference',
1556
+ name: 'by_month',
1557
+ },
1558
+ refinement: {
1559
+ kind: 'segment',
1560
+ operations: [],
1561
+ },
1562
+ },
1563
+ },
1564
+ },
1565
+ to: {
1566
+ definition: {
1567
+ kind: 'arrow',
1568
+ source_reference: {name: 'flights'},
1569
+ view: {
1570
+ kind: 'refinement',
1571
+ base: {
1572
+ kind: 'view_reference',
1573
+ name: 'by_month',
1574
+ },
1575
+ refinement: {
1576
+ kind: 'segment',
1577
+ operations: [],
1578
+ },
1579
+ },
1580
+ },
1581
+ },
1582
+ malloy: 'run: flights -> by_month + { }',
1583
+ });
1584
+ });
1585
+ test('on a query reference', () => {
1586
+ expect((q: ASTQuery) => {
1587
+ q.getOrAddDefaultSegment();
1588
+ }).toModifyQuery({
1589
+ model: flights_model,
1590
+ from: {
1591
+ definition: {
1592
+ kind: 'query_reference',
1593
+ name: 'flights_by_carrier',
1594
+ },
1595
+ },
1596
+ to: {
1597
+ definition: {
1598
+ kind: 'refinement',
1599
+ query_reference: {name: 'flights_by_carrier'},
1600
+ refinement: {
1601
+ kind: 'segment',
1602
+ operations: [],
1603
+ },
1604
+ },
1605
+ },
1606
+ malloy: 'run: flights_by_carrier + { }',
1607
+ });
1608
+ });
1609
+ });
1610
+ test('on an arrow query with a view reference that already has a reference refinement', () => {
1611
+ expect((q: ASTQuery) => {
1612
+ q.getOrAddDefaultSegment();
1613
+ }).toModifyQuery({
1614
+ model: flights_model,
1615
+ from: {
1616
+ definition: {
1617
+ kind: 'arrow',
1618
+ source_reference: {name: 'flights'},
1619
+ view: {
1620
+ kind: 'refinement',
1621
+ base: {
1622
+ kind: 'view_reference',
1623
+ name: 'by_month',
1624
+ },
1625
+ refinement: {
1626
+ kind: 'view_reference',
1627
+ name: 'top10',
1628
+ },
1629
+ },
1630
+ },
1631
+ },
1632
+ to: {
1633
+ definition: {
1634
+ kind: 'arrow',
1635
+ source_reference: {name: 'flights'},
1636
+ view: {
1637
+ kind: 'refinement',
1638
+ base: {
1639
+ kind: 'view_reference',
1640
+ name: 'by_month',
1641
+ },
1642
+ refinement: {
1643
+ kind: 'refinement',
1644
+ base: {
1645
+ kind: 'view_reference',
1646
+ name: 'top10',
1647
+ },
1648
+ refinement: {
1649
+ kind: 'segment',
1650
+ operations: [],
1651
+ },
1652
+ },
1653
+ },
1654
+ },
1655
+ },
1656
+ malloy: 'run: flights -> by_month + top10 + { }',
1657
+ });
1658
+ });
1659
+ describe('parameters', () => {
1660
+ test('add parameters of different types', () => {
1661
+ const from: Malloy.Query = {
1662
+ definition: {
1663
+ kind: 'arrow',
1664
+ source_reference: {name: 'foo'},
1665
+ view: {
1666
+ kind: 'segment',
1667
+ operations: [],
1668
+ },
1669
+ },
1670
+ };
1671
+ expect((q: ASTQuery) => {
1672
+ const source = q.definition.asArrowQueryDefinition().sourceReference;
1673
+ source.setParameter('string_param', 'COOL');
1674
+ source.setParameter('number_param', 7);
1675
+ source.setParameter('boolean_param', true);
1676
+ source.setParameter('date_param', {
1677
+ // TODO what am I supposed to do about timezones?
1678
+ date: new Date('2020-01-01 10:00:00+00:00'),
1679
+ granularity: 'month',
1680
+ });
1681
+ source.setParameter('timestamp_param', {
1682
+ date: new Date('2020-01-01 10:00:00+00:00'),
1683
+ granularity: 'minute',
1684
+ });
1685
+ source.setParameter('null_param', null);
1686
+ }).toModifyQuery({
1687
+ source: {
1688
+ name: 'foo',
1689
+ schema: {fields: []},
1690
+ parameters: [
1691
+ {
1692
+ name: 'string_param',
1693
+ type: {kind: 'string_type'},
1694
+ },
1695
+ {
1696
+ name: 'number_param',
1697
+ type: {kind: 'number_type'},
1698
+ },
1699
+ {
1700
+ name: 'boolean_param',
1701
+ type: {kind: 'boolean_type'},
1702
+ },
1703
+ {
1704
+ name: 'date_param',
1705
+ type: {kind: 'date_type'},
1706
+ },
1707
+ {
1708
+ name: 'timestamp_param',
1709
+ type: {kind: 'timestamp_type'},
1710
+ },
1711
+ {
1712
+ name: 'null_param',
1713
+ type: {kind: 'string_type'},
1714
+ },
1715
+ ],
1716
+ },
1717
+ from,
1718
+ to: {
1719
+ definition: {
1720
+ kind: 'arrow',
1721
+ source_reference: {
1722
+ name: 'foo',
1723
+ parameters: [
1724
+ {
1725
+ name: 'string_param',
1726
+ value: {kind: 'string_literal', string_value: 'COOL'},
1727
+ },
1728
+ {
1729
+ name: 'number_param',
1730
+ value: {kind: 'number_literal', number_value: 7},
1731
+ },
1732
+ {
1733
+ name: 'boolean_param',
1734
+ value: {kind: 'boolean_literal', boolean_value: true},
1735
+ },
1736
+ {
1737
+ name: 'date_param',
1738
+ value: {
1739
+ kind: 'date_literal',
1740
+ date_value: '2020-01-01 10:00:00',
1741
+ granularity: 'month',
1742
+ },
1743
+ },
1744
+ {
1745
+ name: 'timestamp_param',
1746
+ value: {
1747
+ kind: 'timestamp_literal',
1748
+ timestamp_value: '2020-01-01 10:00:00',
1749
+ granularity: 'minute',
1750
+ },
1751
+ },
1752
+ {
1753
+ name: 'null_param',
1754
+ value: {kind: 'null_literal'},
1755
+ },
1756
+ ],
1757
+ },
1758
+ view: {
1759
+ kind: 'segment',
1760
+ operations: [],
1761
+ },
1762
+ },
1763
+ },
1764
+ malloy: dedent`
1765
+ run: foo(
1766
+ string_param is "COOL",
1767
+ number_param is 7,
1768
+ boolean_param is true,
1769
+ date_param is @2020-01,
1770
+ timestamp_param is @2020-01-01 18:00,
1771
+ null_param is null
1772
+ ) -> { }
1773
+ `,
1774
+ });
1775
+ });
1776
+ });
1777
+ });