@apollo/gateway 0.42.2 → 0.44.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.
@@ -1,9 +1,13 @@
1
1
  import { GraphQLSchema } from 'graphql';
2
2
  import gql from 'graphql-tag';
3
3
  import { buildOperationContext } from '../operationContext';
4
- import { astSerializer, queryPlanSerializer } from 'apollo-federation-integration-testsuite';
4
+ import {
5
+ astSerializer,
6
+ queryPlanSerializer,
7
+ fixturesWithUpdate,
8
+ } from 'apollo-federation-integration-testsuite';
5
9
  import { getFederatedTestingSchema } from './execution-utils';
6
- import { QueryPlanner } from '@apollo/query-planner';
10
+ import { QueryPlanner, FetchNode } from '@apollo/query-planner';
7
11
 
8
12
  expect.addSnapshotSerializer(astSerializer);
9
13
  expect.addSnapshotSerializer(queryPlanSerializer);
@@ -85,7 +89,7 @@ describe('buildQueryPlan', () => {
85
89
  buildOperationContext({
86
90
  schema,
87
91
  operationDocument,
88
- })
92
+ }),
89
93
  );
90
94
 
91
95
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -119,7 +123,7 @@ describe('buildQueryPlan', () => {
119
123
  buildOperationContext({
120
124
  schema,
121
125
  operationDocument,
122
- })
126
+ }),
123
127
  );
124
128
 
125
129
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -206,7 +210,7 @@ describe('buildQueryPlan', () => {
206
210
  buildOperationContext({
207
211
  schema,
208
212
  operationDocument,
209
- })
213
+ }),
210
214
  );
211
215
 
212
216
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -337,7 +341,7 @@ describe('buildQueryPlan', () => {
337
341
  buildOperationContext({
338
342
  schema,
339
343
  operationDocument,
340
- })
344
+ }),
341
345
  );
342
346
 
343
347
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -379,7 +383,7 @@ describe('buildQueryPlan', () => {
379
383
  buildOperationContext({
380
384
  schema,
381
385
  operationDocument,
382
- })
386
+ }),
383
387
  );
384
388
 
385
389
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -420,7 +424,7 @@ describe('buildQueryPlan', () => {
420
424
  buildOperationContext({
421
425
  schema,
422
426
  operationDocument,
423
- })
427
+ }),
424
428
  );
425
429
 
426
430
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -475,7 +479,7 @@ describe('buildQueryPlan', () => {
475
479
  buildOperationContext({
476
480
  schema,
477
481
  operationDocument,
478
- })
482
+ }),
479
483
  );
480
484
 
481
485
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -531,7 +535,7 @@ describe('buildQueryPlan', () => {
531
535
  buildOperationContext({
532
536
  schema,
533
537
  operationDocument,
534
- })
538
+ }),
535
539
  );
536
540
 
537
541
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -571,7 +575,7 @@ describe('buildQueryPlan', () => {
571
575
 
572
576
  describe(`when requesting a composite field with subfields from another service`, () => {
573
577
  it(`should add key fields to the parent selection set and use a dependent fetch`, () => {
574
- const operationString = `#graphql
578
+ const operationString = `#graphql
575
579
  query {
576
580
  topReviews {
577
581
  body
@@ -588,7 +592,7 @@ describe('buildQueryPlan', () => {
588
592
  buildOperationContext({
589
593
  schema,
590
594
  operationDocument,
591
- })
595
+ }),
592
596
  );
593
597
 
594
598
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -641,7 +645,7 @@ describe('buildQueryPlan', () => {
641
645
  buildOperationContext({
642
646
  schema,
643
647
  operationDocument,
644
- })
648
+ }),
645
649
  );
646
650
 
647
651
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -696,7 +700,7 @@ describe('buildQueryPlan', () => {
696
700
  buildOperationContext({
697
701
  schema,
698
702
  operationDocument,
699
- })
703
+ }),
700
704
  );
701
705
 
702
706
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -751,7 +755,7 @@ describe('buildQueryPlan', () => {
751
755
  buildOperationContext({
752
756
  schema,
753
757
  operationDocument,
754
- })
758
+ }),
755
759
  );
756
760
 
757
761
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -807,7 +811,7 @@ describe('buildQueryPlan', () => {
807
811
  buildOperationContext({
808
812
  schema,
809
813
  operationDocument,
810
- })
814
+ }),
811
815
  );
812
816
 
813
817
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -854,7 +858,7 @@ describe('buildQueryPlan', () => {
854
858
  buildOperationContext({
855
859
  schema,
856
860
  operationDocument,
857
- })
861
+ }),
858
862
  );
859
863
 
860
864
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -901,7 +905,7 @@ describe('buildQueryPlan', () => {
901
905
  buildOperationContext({
902
906
  schema,
903
907
  operationDocument,
904
- })
908
+ }),
905
909
  );
906
910
 
907
911
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -942,7 +946,7 @@ describe('buildQueryPlan', () => {
942
946
  buildOperationContext({
943
947
  schema,
944
948
  operationDocument,
945
- })
949
+ }),
946
950
  );
947
951
 
948
952
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -982,7 +986,7 @@ describe('buildQueryPlan', () => {
982
986
  buildOperationContext({
983
987
  schema,
984
988
  operationDocument,
985
- })
989
+ }),
986
990
  );
987
991
 
988
992
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1025,7 +1029,7 @@ describe('buildQueryPlan', () => {
1025
1029
  buildOperationContext({
1026
1030
  schema,
1027
1031
  operationDocument,
1028
- })
1032
+ }),
1029
1033
  );
1030
1034
 
1031
1035
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1099,7 +1103,7 @@ describe('buildQueryPlan', () => {
1099
1103
  buildOperationContext({
1100
1104
  schema,
1101
1105
  operationDocument,
1102
- })
1106
+ }),
1103
1107
  );
1104
1108
 
1105
1109
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1154,7 +1158,7 @@ describe('buildQueryPlan', () => {
1154
1158
  buildOperationContext({
1155
1159
  schema,
1156
1160
  operationDocument,
1157
- })
1161
+ }),
1158
1162
  );
1159
1163
 
1160
1164
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1550,7 +1554,7 @@ describe('buildQueryPlan', () => {
1550
1554
  buildOperationContext({
1551
1555
  schema,
1552
1556
  operationDocument,
1553
- })
1557
+ }),
1554
1558
  );
1555
1559
 
1556
1560
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1612,7 +1616,7 @@ describe('buildQueryPlan', () => {
1612
1616
  buildOperationContext({
1613
1617
  schema,
1614
1618
  operationDocument,
1615
- })
1619
+ }),
1616
1620
  );
1617
1621
 
1618
1622
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1662,7 +1666,7 @@ describe('buildQueryPlan', () => {
1662
1666
  buildOperationContext({
1663
1667
  schema,
1664
1668
  operationDocument,
1665
- })
1669
+ }),
1666
1670
  );
1667
1671
 
1668
1672
  expect(queryPlan).toMatchInlineSnapshot(`
@@ -1684,4 +1688,251 @@ describe('buildQueryPlan', () => {
1684
1688
  `);
1685
1689
  });
1686
1690
  });
1691
+
1692
+ describe('top-level @skip/@include behavior', () => {
1693
+ beforeEach(() => {
1694
+ ({ schema, queryPlanner } =
1695
+ getFederatedTestingSchema(fixturesWithUpdate));
1696
+ });
1697
+
1698
+ function getQueryPlan(operation: string) {
1699
+ const operationDocument = gql(operation);
1700
+
1701
+ return queryPlanner.buildQueryPlan(
1702
+ buildOperationContext({
1703
+ schema,
1704
+ operationDocument,
1705
+ }),
1706
+ );
1707
+ }
1708
+
1709
+ it('simple skip', () => {
1710
+ const operation = `#graphql
1711
+ query {
1712
+ topReviews @skip(if: true) {
1713
+ body
1714
+ }
1715
+ }
1716
+ `;
1717
+
1718
+ expect(
1719
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1720
+ ).toEqual([{ skip: true, include: null }]);
1721
+ });
1722
+
1723
+ it('simple include', () => {
1724
+ const operation = `#graphql
1725
+ query {
1726
+ topReviews @include(if: false) {
1727
+ body
1728
+ }
1729
+ }
1730
+ `;
1731
+
1732
+ expect(
1733
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1734
+ ).toEqual([{ include: false, skip: null }]);
1735
+ });
1736
+
1737
+ it('simple include with variables', () => {
1738
+ const operation = `#graphql
1739
+ query {
1740
+ topReviews @include(if: $shouldInclude) {
1741
+ body
1742
+ }
1743
+ }
1744
+ `;
1745
+
1746
+ expect(
1747
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1748
+ ).toEqual([{ include: 'shouldInclude', skip: null }]);
1749
+ });
1750
+
1751
+ it('simple skip with variables', () => {
1752
+ const operation = `#graphql
1753
+ query {
1754
+ topReviews @skip(if: $shouldSkip) {
1755
+ body
1756
+ }
1757
+ }
1758
+ `;
1759
+
1760
+ expect(
1761
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1762
+ ).toEqual([{ skip: 'shouldSkip', include: null }]);
1763
+ });
1764
+
1765
+ it('not all top-levels have conditionals', () => {
1766
+ const operation = `#graphql
1767
+ query {
1768
+ topReviews @skip(if: $shouldSkip) {
1769
+ body
1770
+ }
1771
+ review(id: "1") {
1772
+ body
1773
+ }
1774
+ }
1775
+ `;
1776
+
1777
+ expect(
1778
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1779
+ ).toBeUndefined();
1780
+ });
1781
+
1782
+ it('all top-levels have conditionals', () => {
1783
+ const operation = `#graphql
1784
+ query {
1785
+ topReviews @skip(if: $shouldSkip) {
1786
+ body
1787
+ }
1788
+ review(id: "1") @skip(if: true) {
1789
+ body
1790
+ }
1791
+ }
1792
+ `;
1793
+
1794
+ expect(
1795
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1796
+ ).toEqual([
1797
+ { skip: 'shouldSkip', include: null },
1798
+ { skip: true, include: null },
1799
+ ]);
1800
+ });
1801
+
1802
+ it('all top-levels use literals (include case)', () => {
1803
+ const operation = `#graphql
1804
+ query {
1805
+ topReviews @skip(if: false) {
1806
+ body
1807
+ }
1808
+ review(id: "1") @include(if: true) {
1809
+ body
1810
+ }
1811
+ }
1812
+ `;
1813
+
1814
+ expect(
1815
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1816
+ ).toBeUndefined();
1817
+ });
1818
+
1819
+ it('all top-levels use literals (skip case)', () => {
1820
+ const operation = `#graphql
1821
+ query {
1822
+ topReviews @skip(if: true) {
1823
+ body
1824
+ }
1825
+ review(id: "1") @include(if: false) {
1826
+ body
1827
+ }
1828
+ }
1829
+ `;
1830
+
1831
+ expect(
1832
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1833
+ ).toEqual([
1834
+ { skip: true, include: null },
1835
+ { include: false, skip: null },
1836
+ ]);
1837
+ });
1838
+
1839
+ it('skip: false, include: false', () => {
1840
+ const operation = `#graphql
1841
+ query {
1842
+ topReviews @skip(if: false) @include(if: false) {
1843
+ body
1844
+ }
1845
+ }
1846
+ `;
1847
+
1848
+ expect(
1849
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1850
+ ).toEqual([{ skip: false, include: false }]);
1851
+ });
1852
+
1853
+ it('skip: false, include: true', () => {
1854
+ const operation = `#graphql
1855
+ query {
1856
+ topReviews @skip(if: false) @include(if: true) {
1857
+ body
1858
+ }
1859
+ }
1860
+ `;
1861
+
1862
+ expect(
1863
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1864
+ ).toBeUndefined();
1865
+ });
1866
+
1867
+ it('skip: true, include: false', () => {
1868
+ const operation = `#graphql
1869
+ query {
1870
+ topReviews @skip(if: true) @include(if: false) {
1871
+ body
1872
+ }
1873
+ }
1874
+ `;
1875
+
1876
+ expect(
1877
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1878
+ ).toEqual([{ skip: true, include: false }]);
1879
+ });
1880
+
1881
+ it('skip: true, include: true', () => {
1882
+ const operation = `#graphql
1883
+ query {
1884
+ topReviews @skip(if: true) @include(if: true) {
1885
+ body
1886
+ }
1887
+ }
1888
+ `;
1889
+
1890
+ expect(
1891
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1892
+ ).toEqual([{ skip: true, include: true }]);
1893
+ });
1894
+
1895
+ describe.skip('known limitations', () => {
1896
+ it('conditionals on top-level fragment spreads are captured', () => {
1897
+ const operation = `#graphql
1898
+ query {
1899
+ ...TopReviews @skip(if: $shouldSkip)
1900
+ }
1901
+
1902
+ fragment TopReviews on Query {
1903
+ topReviews {
1904
+ body
1905
+ }
1906
+ }
1907
+ `;
1908
+
1909
+ expect(
1910
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1911
+ ).toEqual([{ skip: 'shouldSkip', include: null }]);
1912
+ });
1913
+
1914
+ it('conditionals on top-level inline fragments are captured', () => {
1915
+ const operation = `#graphql
1916
+ query {
1917
+ ... on Query @skip(if: $shouldSkip) {
1918
+ topReviews {
1919
+ body
1920
+ }
1921
+ }
1922
+ }
1923
+ `;
1924
+
1925
+ expect(
1926
+ (getQueryPlan(operation).node as FetchNode).inclusionConditions,
1927
+ ).toEqual([{ skip: 'shouldSkip', include: null }]);
1928
+ });
1929
+
1930
+ it.todo(
1931
+ 'deeply-nested conditionals within fragment spreads are captured',
1932
+ );
1933
+ it.todo(
1934
+ 'deeply-nested conditionals within inline fragments are captured',
1935
+ );
1936
+ });
1937
+ });
1687
1938
  });