@@ -422,6 +422,7 @@ FieldsInSetCanMerge(set):
422
422
{set} including visiting fragments and inline fragments.
423
423
- Given each pair of members {fieldA} and {fieldB} in {fieldsForName}:
424
424
- {SameResponseShape(fieldA, fieldB)} must be true.
425
+ - {SameStreamDirective(fieldA, fieldB)} must be true.
425
426
- If the parent types of {fieldA} and {fieldB} are equal or if either is not
426
427
an Object Type:
427
428
- {fieldA} and {fieldB} must have identical field names.
@@ -456,6 +457,16 @@ SameResponseShape(fieldA, fieldB):
456
457
- If {SameResponseShape(subfieldA, subfieldB)} is {false}, return {false}.
457
458
- Return {true}.
458
459
460
+ SameStreamDirective(fieldA, fieldB):
461
+
462
+ - If neither {fieldA} nor {fieldB} has a directive named ` stream ` .
463
+ - Return {true}.
464
+ - If both {fieldA} and {fieldB} have a directive named ` stream ` .
465
+ - Let {streamA} be the directive named ` stream ` on {fieldA}.
466
+ - Let {streamB} be the directive named ` stream ` on {fieldB}.
467
+ - If {streamA} and {streamB} have identical sets of arguments, return {true}.
468
+ - Return {false}.
469
+
459
470
Note: In prior versions of the spec the term "composite" was used to signal a
460
471
type that is either an Object, Interface or Union type.
461
472
@@ -1521,6 +1532,174 @@ query ($foo: Boolean = true, $bar: Boolean = false) {
1521
1532
}
1522
1533
```
1523
1534
1535
+ ### Defer And Stream Directives Are Used On Valid Root Field
1536
+
1537
+ ** Formal Specification **
1538
+
1539
+ - For every {directive} in a document.
1540
+ - Let {directiveName} be the name of {directive}.
1541
+ - Let {mutationType} be the root Mutation type in {schema}.
1542
+ - Let {subscriptionType} be the root Subscription type in {schema}.
1543
+ - If {directiveName} is "defer" or "stream":
1544
+ - The parent type of {directive} must not be {mutationType} or
1545
+ {subscriptionType}.
1546
+
1547
+ ** Explanatory Text**
1548
+
1549
+ The defer and stream directives are not allowed to be used on root fields of the
1550
+ mutation or subscription type.
1551
+
1552
+ For example, the following document will not pass validation because ` @defer `
1553
+ has been used on a root mutation field:
1554
+
1555
+ ``` raw graphql counter-example
1556
+ mutation {
1557
+ ... @defer {
1558
+ mutationField
1559
+ }
1560
+ }
1561
+ ```
1562
+
1563
+ ### Defer And Stream Directives Are Used On Valid Operations
1564
+
1565
+ ** Formal Specification **
1566
+
1567
+ - Let {subscriptionFragments} be the empty set.
1568
+ - For each {operation} in a document:
1569
+ - If {operation} is a subscription operation:
1570
+ - Let {fragments} be every fragment referenced by that {operation}
1571
+ transitively.
1572
+ - For each {fragment} in {fragments}:
1573
+ - Let {fragmentName} be the name of {fragment}.
1574
+ - Add {fragmentName} to {subscriptionFragments}.
1575
+ - For every {directive} in a document:
1576
+ - If {directiveName} is not "defer" or "stream":
1577
+ - Continue to the next {directive}.
1578
+ - Let {ancestor} be the ancestor operation or fragment definition of
1579
+ {directive}.
1580
+ - If {ancestor} is a fragment definition:
1581
+ - If the fragment name of {ancestor} is not present in
1582
+ {subscriptionFragments}:
1583
+ - Continue to the next {directive}.
1584
+ - If {ancestor} is not a subscription operation:
1585
+ - Continue to the next {directive}.
1586
+ - Let {if} be the argument named "if" on {directive}.
1587
+ - {if} must be defined.
1588
+ - Let {argumentValue} be the value passed to {if}.
1589
+ - {argumentValue} must be a variable, or the boolean value "false".
1590
+
1591
+ ** Explanatory Text**
1592
+
1593
+ The defer and stream directives can not be used to defer or stream data in
1594
+ subscription operations. If these directives appear in a subscription operation
1595
+ they must be disabled using the "if" argument. This rule will not permit any
1596
+ defer or stream directives on a subscription operation that cannot be disabled
1597
+ using the "if" argument.
1598
+
1599
+ For example, the following document will not pass validation because ` @defer `
1600
+ has been used in a subscription operation with no "if" argument defined:
1601
+
1602
+ ``` raw graphql counter-example
1603
+ subscription sub {
1604
+ newMessage {
1605
+ ... @defer {
1606
+ body
1607
+ }
1608
+ }
1609
+ }
1610
+ ```
1611
+
1612
+ ### Defer And Stream Directive Labels Are Unique
1613
+
1614
+ ** Formal Specification **
1615
+
1616
+ - Let {labelValues} be an empty set.
1617
+ - For every {directive} in the document:
1618
+ - Let {directiveName} be the name of {directive}.
1619
+ - If {directiveName} is "defer" or "stream":
1620
+ - For every {argument} in {directive}:
1621
+ - Let {argumentName} be the name of {argument}.
1622
+ - Let {argumentValue} be the value passed to {argument}.
1623
+ - If {argumentName} is "label":
1624
+ - {argumentValue} must not be a variable.
1625
+ - {argumentValue} must not be present in {labelValues}.
1626
+ - Append {argumentValue} to {labelValues}.
1627
+
1628
+ ** Explanatory Text**
1629
+
1630
+ The ` @defer ` and ` @stream ` directives each accept an argument "label". This
1631
+ label may be used by GraphQL clients to uniquely identify response payloads. If
1632
+ a label is passed, it must not be a variable and it must be unique within all
1633
+ other ` @defer ` and ` @stream ` directives in the document.
1634
+
1635
+ For example the following document is valid:
1636
+
1637
+ ``` graphql example
1638
+ {
1639
+ dog {
1640
+ ... fragmentOne
1641
+ ... fragmentTwo @defer (label : " dogDefer" )
1642
+ }
1643
+ pets @stream (label : " petStream" ) {
1644
+ name
1645
+ }
1646
+ }
1647
+
1648
+ fragment fragmentOne on Dog {
1649
+ name
1650
+ }
1651
+
1652
+ fragment fragmentTwo on Dog {
1653
+ owner {
1654
+ name
1655
+ }
1656
+ }
1657
+ ```
1658
+
1659
+ For example, the following document will not pass validation because the same
1660
+ label is used in different ` @defer ` and ` @stream ` directives.:
1661
+
1662
+ ``` raw graphql counter-example
1663
+ {
1664
+ dog {
1665
+ ...fragmentOne @defer(label: "MyLabel")
1666
+ }
1667
+ pets @stream(label: "MyLabel") {
1668
+ name
1669
+ }
1670
+ }
1671
+
1672
+ fragment fragmentOne on Dog {
1673
+ name
1674
+ }
1675
+ ```
1676
+
1677
+ ### Stream Directives Are Used On List Fields
1678
+
1679
+ ** Formal Specification**
1680
+
1681
+ - For every {directive} in a document.
1682
+ - Let {directiveName} be the name of {directive}.
1683
+ - If {directiveName} is "stream":
1684
+ - Let {adjacent} be the AST node the directive affects.
1685
+ - {adjacent} must be a List type.
1686
+
1687
+ ** Explanatory Text**
1688
+
1689
+ GraphQL directive locations do not provide enough granularity to distinguish the
1690
+ type of fields used in a GraphQL document. Since the stream directive is only
1691
+ valid on list fields, an additional validation rule must be used to ensure it is
1692
+ used correctly.
1693
+
1694
+ For example, the following document will only pass validation if ` field ` is
1695
+ defined as a List type in the associated schema.
1696
+
1697
+ ``` graphql counter-example
1698
+ query {
1699
+ field @stream (initialCount : 0 )
1700
+ }
1701
+ ```
1702
+
1524
1703
## Variables
1525
1704
1526
1705
### Variable Uniqueness
0 commit comments