Skip to content

Commit

Permalink
feature: @OneOf input object support (apollographql/apollo-ios-dev#537)
Browse files Browse the repository at this point in the history
  • Loading branch information
BobaFetters authored and gh-action-runner committed Dec 2, 2024
1 parent cfe2748 commit 461d092
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -386,19 +386,15 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
decoder: decoder
)

url = try values.decode(String.self, forKey: .url)
url = try values.decodeIfPresent(String.self, forKey: .url) ?? "https://github.com/apollographql/apollo-ios"

if let version = try? values.decodeIfPresent(SDKVersion.self, forKey: .sdkVersion) {
sdkVersion = version
} else if let versionString = try? values.decodeIfPresent(String.self, forKey: .sdkVersion) {
let version = try SDKVersion(fromString: versionString)
sdkVersion = version
} else {
throw DecodingError.typeMismatch(Self.self, DecodingError.Context.init(
codingPath: values.codingPath,
debugDescription: "No valid 'sdkVersion' provided.",
underlyingError: nil
))
sdkVersion = .default
}
}

Expand Down
10 changes: 7 additions & 3 deletions Sources/ApolloCodegenLib/ConfigurationValidation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ extension ApolloCodegen.ConfigurationContext {
throw ApolloCodegen.Error.schemaNameConflict(name: self.schemaNamespace)
}

if case .swiftPackage = self.output.testMocks,
self.output.schemaTypes.moduleType != .swiftPackage() {
throw ApolloCodegen.Error.testMocksInvalidSwiftPackageConfiguration
if case .swiftPackage = self.output.testMocks {
switch self.output.schemaTypes.moduleType {
case .swiftPackage(_), .swiftPackageManager:
break
default:
throw ApolloCodegen.Error.testMocksInvalidSwiftPackageConfiguration
}
}

if case .swiftPackage = self.output.schemaTypes.moduleType,
Expand Down
6 changes: 3 additions & 3 deletions Sources/ApolloCodegenLib/FileGenerators/FileGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ enum FileTarget: Equatable {
forConfig config: ApolloCodegen.ConfigurationContext
) -> String {
var moduleSubpath: String = "/"
if config.output.schemaTypes.moduleType == .swiftPackage() {
if case .swiftPackage = config.output.schemaTypes.moduleType {
moduleSubpath += "Sources/"
}
if config.output.operations.isInModule {
Expand All @@ -132,7 +132,7 @@ enum FileTarget: Equatable {
switch config.output.operations {
case .inSchemaModule:
var url = URL(fileURLWithPath: config.output.schemaTypes.path, relativeTo: config.rootURL)
if config.output.schemaTypes.moduleType == .swiftPackage() {
if case .swiftPackage = config.output.schemaTypes.moduleType {
url = url.appendingPathComponent("Sources")
}

Expand Down Expand Up @@ -167,7 +167,7 @@ enum FileTarget: Equatable {
switch config.output.operations {
case .inSchemaModule:
var url = URL(fileURLWithPath: config.output.schemaTypes.path, relativeTo: config.rootURL)
if config.output.schemaTypes.moduleType == .swiftPackage() {
if case .swiftPackage = config.output.schemaTypes.moduleType {
url = url.appendingPathComponent("Sources")
}
if !operation.isLocalCacheMutation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ struct InputObjectFileGenerator: FileGenerator {
let config: ApolloCodegen.ConfigurationContext

var template: any TemplateRenderer {
InputObjectTemplate(graphqlInputObject: graphqlInputObject, config: config)
if graphqlInputObject.isOneOf {
OneOfInputObjectTemplate(graphqlInputObject: graphqlInputObject, config: config)
} else {
InputObjectTemplate(graphqlInputObject: graphqlInputObject, config: config)
}
}
var target: FileTarget { .inputObject }
var fileName: String { graphqlInputObject.render(as: .filename) }
Expand Down
38 changes: 20 additions & 18 deletions Sources/ApolloCodegenLib/Templates/InputObjectTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct InputObjectTemplate: TemplateRenderer {
func renderBodyTemplate(
nonFatalErrorRecorder: ApolloCodegen.NonFatalError.Recorder
) -> TemplateString {
let (validFields, deprecatedFields) = filterFields(graphqlInputObject.fields)
let (validFields, deprecatedFields) = graphqlInputObject.fields.filterFields()
let memberAccessControl = accessControlModifier(for: .member)

return TemplateString(
Expand Down Expand Up @@ -63,23 +63,6 @@ struct InputObjectTemplate: TemplateRenderer {
config.options.warningsOnDeprecatedUsage == .include
}

private func filterFields(
_ fields: GraphQLInputFieldDictionary
) -> (valid: GraphQLInputFieldDictionary, deprecated: GraphQLInputFieldDictionary) {
var valid: GraphQLInputFieldDictionary = [:]
var deprecated: GraphQLInputFieldDictionary = [:]

for (key, value) in fields {
if let _ = value.deprecationReason {
deprecated[key] = value
} else {
valid[key] = value
}
}

return (valid: valid, deprecated: deprecated)
}

private func deprecatedMessage(for fields: GraphQLInputFieldDictionary) -> String {
guard !fields.isEmpty else { return "" }

Expand Down Expand Up @@ -123,3 +106,22 @@ struct InputObjectTemplate: TemplateRenderer {
"""
}
}

extension GraphQLInputFieldDictionary {

func filterFields() -> (valid: GraphQLInputFieldDictionary, deprecated: GraphQLInputFieldDictionary) {
var valid: GraphQLInputFieldDictionary = [:]
var deprecated: GraphQLInputFieldDictionary = [:]

for (key, value) in self {
if let _ = value.deprecationReason {
deprecated[key] = value
} else {
valid[key] = value
}
}

return (valid: valid, deprecated: deprecated)
}

}
52 changes: 52 additions & 0 deletions Sources/ApolloCodegenLib/Templates/OneOfInputObjectTemplate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Foundation
import GraphQLCompiler
import TemplateString

struct OneOfInputObjectTemplate: TemplateRenderer {

let graphqlInputObject: GraphQLInputObjectType

let config: ApolloCodegen.ConfigurationContext

let target: TemplateTarget = .schemaFile(type: .inputObject)

func renderBodyTemplate(
nonFatalErrorRecorder: ApolloCodegen.NonFatalError.Recorder
) -> TemplateString {
let memberAccessControl = accessControlModifier(for: .member)

return TemplateString(
"""
\(documentation: graphqlInputObject.documentation, config: config)
\(graphqlInputObject.name.typeNameDocumentation)
\(accessControlModifier(for: .parent))\
enum \(graphqlInputObject.render(as: .typename)): OneOfInputObject {
\(graphqlInputObject.fields.map({ "\(FieldCaseTemplate($1))" }), separator: "\n")
\(memberAccessControl)var __data: InputDict {
switch self {
\(graphqlInputObject.fields.map({ "\(FieldCaseDataTemplate($1))" }), separator: "\n")
}
}
}
"""
)
}

private func FieldCaseTemplate(_ field: GraphQLInputField) -> TemplateString {
"""
\(documentation: field.documentation, config: config)
\(deprecationReason: field.deprecationReason, config: config)
\(field.name.typeNameDocumentation)
case \(field.render(config: config))(\(field.type.renderAsInputValue(inNullable: false, config: config.config)))
"""
}

private func FieldCaseDataTemplate(_ field: GraphQLInputField) -> TemplateString {
"""
case .\(field.render(config: config))(let value):
return InputDict(["\(field.name.schemaName)": value])
"""
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extension GraphQLType {

// MARK: Input Value

private func renderAsInputValue(
func renderAsInputValue(
inNullable: Bool,
config: ApolloCodegenConfiguration
) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fileprivate extension ApolloCodegenConfiguration.SchemaTypesFileOutput.ModuleTyp
"""
case .local(let path):
return """
.package(path: "\(path)")
.package(name: "apollo-ios", path: "\(path)")
"""
}
}
Expand Down
7 changes: 6 additions & 1 deletion Sources/GraphQLCompiler/GraphQLSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,11 @@ public typealias GraphQLInputFieldDictionary = OrderedDictionary<String, GraphQL

public final class GraphQLInputObjectType: GraphQLNamedType {
public private(set) var fields: GraphQLInputFieldDictionary!

public let isOneOf: Bool

required init(_ jsValue: JSValue, bridge: isolated JavaScriptBridge) {
self.isOneOf = jsValue["isOneOf"]
super.init(jsValue, bridge: bridge)
}

Expand All @@ -167,9 +170,11 @@ public final class GraphQLInputObjectType: GraphQLNamedType {
init(
name: GraphQLName,
documentation: String?,
fields: GraphQLInputFieldDictionary
fields: GraphQLInputFieldDictionary,
isOneOf: Bool = false
) {
self.fields = fields
self.isOneOf = isOneOf
super.init(name: name, documentation: documentation)
}
}
Expand Down

0 comments on commit 461d092

Please sign in to comment.