@@ -35,8 +35,9 @@ public struct IncludeAssociationDecorator: ModelBasedGraphQLDocumentDecorator {
3535 includedAssociations. forEach { association in
3636 // we don't include the root reference because it refers to the root model
3737 // 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+ }
4041 }
4142
4243 return document. copy ( selectionSet: selectionSet)
@@ -45,24 +46,48 @@ public struct IncludeAssociationDecorator: ModelBasedGraphQLDocumentDecorator {
4546}
4647
4748extension 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 "
5471 }
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
6490 }
65- return selectionSet
6691 }
6792
6893}
0 commit comments