@@ -22,6 +22,7 @@ public class ApolloCodegen {
2222 case invalidSchemaName( _ name: String , message: String )
2323 case targetNameConflict( name: String )
2424 case typeNameConflict( name: String , conflictingName: String , containingObject: String )
25+ case failedToComputeOperationIdentifier( type: String , name: String , error: Swift . Error )
2526
2627 public var errorDescription : String ? {
2728 switch self {
@@ -64,6 +65,8 @@ public class ApolloCodegen {
6465 Recommend using a field alias for one of these fields to resolve this conflict. \
6566 For more info see: https://www.apollographql.com/docs/ios/troubleshooting/codegen-troubleshooting#typenameconflict
6667 """
68+ case let . failedToComputeOperationIdentifier( type, name, error) :
69+ return " Received failure while computing operation identifier for \( type) named ' \( name) ', Error: \( error. localizedDescription) "
6770 }
6871 }
6972 }
@@ -91,6 +94,9 @@ public class ApolloCodegen {
9194
9295 }
9396
97+ /// A `nil` result is treated as a cancellation, and the default operationIdentifier is used
98+ public typealias ComputeOperationIdentifier = ( any IROperation , @escaping ( Result < String , Swift . Error > ? ) -> Void ) -> Void
99+
94100 /// Executes the code generation engine with a specified configuration.
95101 ///
96102 /// - Parameters:
@@ -103,16 +109,18 @@ public class ApolloCodegen {
103109 public static func build(
104110 with configuration: ApolloCodegenConfiguration ,
105111 withRootURL rootURL: URL ? = nil ,
106- itemsToGenerate: ItemsToGenerate = [ . code]
112+ itemsToGenerate: ItemsToGenerate = [ . code] ,
113+ computeOperationIdentifier: ComputeOperationIdentifier ? = nil
107114 ) throws {
108- try build ( with: configuration, rootURL: rootURL, itemsToGenerate: itemsToGenerate)
115+ try build ( with: configuration, rootURL: rootURL, itemsToGenerate: itemsToGenerate, computeOperationIdentifier : computeOperationIdentifier )
109116 }
110117
111118 internal static func build(
112119 with configuration: ApolloCodegenConfiguration ,
113120 rootURL: URL ? = nil ,
114121 fileManager: ApolloFileManager = . default,
115- itemsToGenerate: ItemsToGenerate
122+ itemsToGenerate: ItemsToGenerate ,
123+ computeOperationIdentifier: ComputeOperationIdentifier ? = nil
116124 ) throws {
117125
118126 let configContext = ConfigurationContext (
@@ -131,29 +139,34 @@ public class ApolloCodegen {
131139
132140 let ir = IR ( compilationResult: compilationResult)
133141
134- var existingGeneratedFilePaths : Set < String > ?
135-
136- if itemsToGenerate . contains ( . code ) && configuration . options . pruneGeneratedFiles {
137- existingGeneratedFilePaths = try findExistingGeneratedFilePaths (
142+ let generate : ( ) throws -> Void = {
143+ try generateFiles (
144+ compilationResult : compilationResult ,
145+ ir : ir ,
138146 config: configContext,
139- fileManager: fileManager
147+ fileManager: fileManager,
148+ itemsToGenerate: itemsToGenerate,
149+ computeOperationIdentifier: computeOperationIdentifier
140150 )
141151 }
142152
143- try generateFiles (
144- compilationResult: compilationResult,
145- ir: ir,
146- config: configContext,
147- fileManager: fileManager,
148- itemsToGenerate: itemsToGenerate
149- )
150-
151- if var existingGeneratedFilePaths {
153+ let generateWithPruning : ( ) throws -> Void = {
154+ var existingGeneratedFilePaths = try findExistingGeneratedFilePaths (
155+ config: configContext,
156+ fileManager: fileManager
157+ )
158+ try generate ( )
152159 try deleteExtraneousGeneratedFiles (
153160 from: & existingGeneratedFilePaths,
154161 afterCodeGenerationUsing: fileManager
155162 )
156163 }
164+
165+ if itemsToGenerate. contains ( . code) && configuration. options. pruneGeneratedFiles {
166+ try generateWithPruning ( )
167+ } else {
168+ try generate ( )
169+ }
157170 }
158171
159172 // MARK: Internal
@@ -412,7 +425,8 @@ public class ApolloCodegen {
412425 ir: IR ,
413426 config: ConfigurationContext ,
414427 fileManager: ApolloFileManager = . default,
415- itemsToGenerate: ItemsToGenerate
428+ itemsToGenerate: ItemsToGenerate ,
429+ computeOperationIdentifier: ComputeOperationIdentifier ? = nil
416430 ) throws {
417431
418432 if itemsToGenerate. contains ( . code) {
@@ -431,9 +445,40 @@ public class ApolloCodegen {
431445 operationIDsFileGenerator = OperationManifestFileGenerator ( config: config)
432446 }
433447
434- for operation in compilationResult. operations {
448+ let irOperations = compilationResult. operations. map { ir. build ( operation: $0) }
449+ var results = [ Result < String , Swift . Error > ? ] ( repeating: nil , count: irOperations. count)
450+
451+ if let computeOperationIdentifier {
452+ let dispatchGroup = DispatchGroup ( )
453+ DispatchQueue . concurrentPerform ( iterations: irOperations. count) { index in
454+ let irOperation = irOperations [ index]
455+ var sources : [ String ] = [ irOperation. definition. source. convertedToSingleLine ( ) ]
456+ for fragment in irOperation. referencedFragments {
457+ sources. append ( fragment. definition. source. convertedToSingleLine ( ) )
458+ }
459+ dispatchGroup. enter ( )
460+ computeOperationIdentifier ( irOperation) { result in
461+ results [ index] = result
462+ dispatchGroup. leave ( )
463+ }
464+ }
465+ dispatchGroup. wait ( )
466+ }
467+
468+ for (index, irOperation) in irOperations. enumerated ( ) {
435469 try autoreleasepool {
436- let irOperation = ir. build ( operation: operation)
470+ if let result = results [ index] {
471+ switch result {
472+ case . success( let operationIdentifier) :
473+ irOperation. operationIdentifier = operationIdentifier
474+ case . failure( let error) :
475+ throw Error . failedToComputeOperationIdentifier (
476+ type: irOperation. definition. operationType. rawValue,
477+ name: irOperation. definition. name,
478+ error: error
479+ )
480+ }
481+ }
437482
438483 if itemsToGenerate. contains ( . code) {
439484 try validateTypeConflicts ( for: irOperation. rootField. selectionSet, with: config, in: irOperation. definition. name)
@@ -611,4 +656,31 @@ public class ApolloCodegen {
611656
612657}
613658
659+ public protocol IRNamedFragment : AnyObject , Hashable {
660+ associatedtype ReferencedFragment : IRNamedFragment
661+ var definition : CompilationResult . FragmentDefinition { get }
662+ /// All of the fragments that are referenced by this operation's selection set.
663+ var referencedFragments : OrderedSet < ReferencedFragment > { get }
664+ }
665+
666+ public protocol IROperation : AnyObject {
667+ associatedtype ReferencedFragment : IRNamedFragment
668+ var definition : CompilationResult . OperationDefinition { get }
669+ /// All of the fragments that are referenced by this operation's selection set.
670+ var referencedFragments : OrderedSet < ReferencedFragment > { get }
671+ }
672+
673+ extension IROperation {
674+ public var document : String {
675+ var sources : [ String ] = [ definition. source. convertedToSingleLine ( ) ]
676+ for fragment in referencedFragments {
677+ sources. append ( fragment. definition. source. convertedToSingleLine ( ) )
678+ }
679+ return sources. joined ( separator: " \n " )
680+ }
681+ }
682+
683+ extension IR . NamedFragment : IRNamedFragment { }
684+ extension IR . Operation : IROperation { }
685+
614686#endif
0 commit comments