11import Foundation
22
33// MARK: - Equatable & Hashable
4- public extension SelectionSet {
4+ extension SelectionSet {
55
66 /// Creates a hash using a narrowly scoped algorithm that only combines fields in the underlying data
77 /// that are relevant to the `SelectionSet`. This ensures that hashes for a fragment do not
88 /// consider fields that are not included in the fragment, even if they are present in the data.
9- func hash( into hasher: inout Hasher ) {
9+ public func hash( into hasher: inout Hasher ) {
1010 hasher. combine ( self . fieldsForEquality ( ) )
1111 }
1212
1313 /// Checks for equality using a narrowly scoped algorithm that only compares fields in the underlying data
1414 /// that are relevant to the `SelectionSet`. This ensures that equality checks for a fragment do not
1515 /// consider fields that are not included in the fragment, even if they are present in the data.
16- static func == ( lhs: Self , rhs: Self ) -> Bool {
16+ public static func == ( lhs: Self , rhs: Self ) -> Bool {
1717 return AnySendableHashable . equatableCheck (
1818 lhs. fieldsForEquality ( ) ,
1919 rhs. fieldsForEquality ( )
@@ -22,40 +22,72 @@ public extension SelectionSet {
2222
2323 private func fieldsForEquality( ) -> [ String : DataDict . FieldValue ] {
2424 var fields : [ String : DataDict . FieldValue ] = [ : ]
25- if let asTypeCase = self as? any InlineFragment {
26- self . addFulfilledSelections ( of: type ( of: asTypeCase. asRootEntityType) , to: & fields)
25+ var addedFragments : Set < ObjectIdentifier > = [ ]
2726
28- } else {
29- self . addFulfilledSelections ( of: type ( of: self ) , to: & fields)
30-
27+ for fragment in type ( of: self ) . __fulfilledFragments {
28+ self . addFulfilledSelections ( of: fragment, to: & fields, addedFragments: & addedFragments)
3129 }
3230 return fields
3331 }
3432
3533 private func addFulfilledSelections(
3634 of selectionSetType: any SelectionSet . Type ,
37- to fields: inout [ String : DataDict . FieldValue ]
35+ to fields: inout [ String : DataDict . FieldValue ] ,
36+ addedFragments: inout Set < ObjectIdentifier >
3837 ) {
39- guard self . __data. fragmentIsFulfilled ( selectionSetType) else {
38+ let selectionSetTypeId = ObjectIdentifier ( selectionSetType)
39+ guard !addedFragments. contains ( selectionSetTypeId) ,
40+ self . __data. fragmentIsFulfilled ( selectionSetType) else {
4041 return
4142 }
4243
44+ addedFragments. insert ( selectionSetTypeId)
45+
4346 for selection in selectionSetType. __selections {
4447 switch selection {
45- case let . field( field) :
48+ case . field( let field) :
4649 add ( field: field, to: & fields)
4750
48- case let . inlineFragment( typeCase) :
49- self . addFulfilledSelections ( of: typeCase, to: & fields)
51+ case . inlineFragment( let typeCase) :
52+ self . addFulfilledSelections ( of: typeCase, to: & fields, addedFragments: & addedFragments)
53+
54+ case . conditional( _, let selections) :
55+ self . addConditionalSelections ( selections, to: & fields, addedFragments: & addedFragments)
56+
57+ case . fragment( let fragmentType) :
58+ self . addFulfilledSelections ( of: fragmentType, to: & fields, addedFragments: & addedFragments)
59+
60+ case . deferred( _, let fragmentType, _) :
61+ self . addFulfilledSelections ( of: fragmentType, to: & fields, addedFragments: & addedFragments)
62+ }
63+ }
64+
65+ for fragment in selectionSetType. __fulfilledFragments {
66+ self . addFulfilledSelections ( of: fragment, to: & fields, addedFragments: & addedFragments)
67+ }
68+ }
69+
70+ private func addConditionalSelections(
71+ _ selections: [ Selection ] ,
72+ to fields: inout [ String : DataDict . FieldValue ] ,
73+ addedFragments: inout Set < ObjectIdentifier >
74+ ) {
75+ for selection in selections {
76+ switch selection {
77+ case . inlineFragment( let typeCase) :
78+ self . addFulfilledSelections ( of: typeCase, to: & fields, addedFragments: & addedFragments)
79+
80+ case . fragment( let fragment) :
81+ self . addFulfilledSelections ( of: fragment, to: & fields, addedFragments: & addedFragments)
5082
51- case let . conditional ( _, selections ) :
52- self . addConditionalSelections ( selections , to: & fields)
83+ case . deferred ( _, let fragment , _ ) :
84+ self . addFulfilledSelections ( of : fragment , to: & fields, addedFragments : & addedFragments )
5385
54- case let . fragment ( fragmentType ) :
55- self . addFulfilledSelections ( of : fragmentType , to: & fields)
86+ case . conditional ( _ , let selections ) :
87+ addConditionalSelections ( selections , to: & fields, addedFragments : & addedFragments )
5688
57- case let . deferred ( _ , fragmentType , _ ) :
58- self . addFulfilledSelections ( of : fragmentType , to: & fields)
89+ case . field ( let field ) :
90+ add ( field : field , to: & fields)
5991 }
6092 }
6193 }
@@ -64,10 +96,12 @@ public extension SelectionSet {
6496 field: Selection . Field ,
6597 to fields: inout [ String : DataDict . FieldValue ]
6698 ) {
99+ guard !fields. keys. contains ( field. responseKey) else { return }
100+
67101 let nullableFieldData = self . __data. _data [ field. responseKey] . asNullable
68102 let fieldData : DataDict . FieldValue
69103 switch nullableFieldData {
70- case let . some( value) :
104+ case . some( let value) :
71105 fieldData = value
72106 case . none, . null:
73107 return
@@ -79,13 +113,13 @@ public extension SelectionSet {
79113 case . scalar, . customScalar:
80114 fields [ field. responseKey] = fieldData
81115
82- case let . nonNull( innerType) :
116+ case . nonNull( let innerType) :
83117 addData ( for: innerType, inList: inList)
84118
85- case let . list( innerType) :
119+ case . list( let innerType) :
86120 addData ( for: innerType, inList: true )
87121
88- case let . object( selectionSetType) :
122+ case . object( let selectionSetType) :
89123 switch inList {
90124 case false :
91125 guard let objectData = fieldData as? DataDict else {
@@ -119,28 +153,4 @@ public extension SelectionSet {
119153 preconditionFailure ( " Expected list data to contain objects. " )
120154 }
121155
122- private func addConditionalSelections(
123- _ selections: [ Selection ] ,
124- to fields: inout [ String : DataDict . FieldValue ]
125- ) {
126- for selection in selections {
127- switch selection {
128- case let . inlineFragment( typeCase) :
129- self . addFulfilledSelections ( of: typeCase, to: & fields)
130-
131- case let . fragment( fragment) :
132- self . addFulfilledSelections ( of: fragment, to: & fields)
133-
134- case let . deferred( _, fragment, _) :
135- self . addFulfilledSelections ( of: fragment, to: & fields)
136-
137- case let . conditional( _, selections) :
138- addConditionalSelections ( selections, to: & fields)
139-
140- case let . field( field) :
141- add ( field: field, to: & fields)
142- }
143- }
144- }
145-
146156}
0 commit comments