@@ -35,8 +35,9 @@ public struct IncludeAssociationDecorator: ModelBasedGraphQLDocumentDecorator {
35
35
includedAssociations. forEach { association in
36
36
// we don't include the root reference because it refers to the root model
37
37
// fields in the selection set, only the nested/included ones are needed
38
- let associationSelectionSet = association. asSelectionSet ( includeRoot: false )
39
- selectionSet. merge ( with: associationSelectionSet)
38
+ if let associationSelectionSet = association. asSelectionSet ( includeRoot: false ) {
39
+ selectionSet. merge ( with: associationSelectionSet)
40
+ }
40
41
}
41
42
42
43
return document. copy ( selectionSet: selectionSet)
@@ -45,24 +46,48 @@ public struct IncludeAssociationDecorator: ModelBasedGraphQLDocumentDecorator {
45
46
}
46
47
47
48
extension PropertyContainerPath {
48
-
49
- func asSelectionSet( includeRoot: Bool = true ) -> SelectionSet {
50
- let metadata = getMetadata ( )
51
- let modelName = getModelType ( ) . modelName
52
- guard let schema = ModelRegistry . modelSchema ( from: modelName) else {
53
- fatalError ( " Schema for model \( modelName) could not be found. " )
49
+ /// Build GraphQL Selection Set based on Model Associations
50
+ /// `PropertyContainerPath` is a tree path with leaf node pointer that
51
+ /// represents the associations from bottom to the top.
52
+ ///
53
+ /// - Returns: A Optional<SelectionSet> represents GraphQL Selection Set from top to bottom.
54
+ func asSelectionSet( includeRoot: Bool = true ) -> SelectionSet ? {
55
+ func getSelectionSet( node: PropertyContainerPath ) -> SelectionSet {
56
+ let metadata = node. getMetadata ( )
57
+ let modelName = node. getModelType ( ) . modelName
58
+
59
+ guard let schema = ModelRegistry . modelSchema ( from: modelName) else {
60
+ fatalError ( " Schema for model \( modelName) could not be found. " )
61
+ }
62
+ let fieldType : SelectionSetFieldType = metadata. isCollection ? . collection : . model
63
+
64
+ let selectionSet = SelectionSet ( value: . init( name: metadata. name, fieldType: fieldType) )
65
+ selectionSet. withModelFields ( schema. graphQLFields, primaryKeysOnly: true )
66
+ return selectionSet
67
+ }
68
+
69
+ func shouldProcessNode( node: PropertyContainerPath ) -> Bool {
70
+ includeRoot || node. getMetadata ( ) . name != " root "
54
71
}
55
- let fieldType : SelectionSetFieldType = metadata. isCollection ? . collection : . model
56
-
57
- var selectionSet = SelectionSet ( value: . init( name: metadata. name, fieldType: fieldType) )
58
- selectionSet. withModelFields ( schema. graphQLFields, primaryKeysOnly: true )
59
- if let parent = metadata. parent as? PropertyContainerPath ,
60
- parent. getMetadata ( ) . parent != nil || includeRoot {
61
- let parentSelectionSet = parent. asSelectionSet ( includeRoot: includeRoot)
62
- parentSelectionSet. replaceChild ( selectionSet)
63
- selectionSet = parentSelectionSet
72
+
73
+ func nodesInPath( node: PropertyContainerPath ) -> [ PropertyContainerPath ] {
74
+ var parent : PropertyContainerPath ? = node
75
+ var path = [ PropertyContainerPath] ( )
76
+ while let currentNode = parent, shouldProcessNode ( node: currentNode) {
77
+ path. append ( currentNode)
78
+ parent = currentNode. getMetadata ( ) . parent as? PropertyContainerPath
79
+ }
80
+ return path
81
+ }
82
+
83
+ let selectionSets = nodesInPath ( node: self ) . map ( getSelectionSet ( node: ) )
84
+ return selectionSets. dropFirst ( ) . reduce ( selectionSets. first) { partialResult, selectionSet in
85
+ guard let partialResult = partialResult else {
86
+ return selectionSet
87
+ }
88
+ selectionSet. replaceChild ( partialResult)
89
+ return selectionSet
64
90
}
65
- return selectionSet
66
91
}
67
92
68
93
}
0 commit comments