Skip to content

Commit

Permalink
Recfactored to add InputValueRenderable
Browse files Browse the repository at this point in the history
Finished implementation of operation variable generation
  • Loading branch information
AnthonyMDev committed Feb 15, 2022
1 parent a4fdcef commit d3dd12e
Show file tree
Hide file tree
Showing 9 changed files with 465 additions and 93 deletions.
20 changes: 18 additions & 2 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@
DE674D9F261CEEE4000E8FC8 /* a.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9B2061192591B3550020D1E0 /* a.txt */; };
DE6B15AF26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6B15AE26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift */; };
DE6B15B126152BE10068D642 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; };
DE6D07F927BC3B6D009F5F33 /* InputValueRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D07F827BC3B6D009F5F33 /* InputValueRenderable.swift */; };
DE6D07FD27BC3D53009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D07FA27BC3BE9009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift */; };
DE736F4626FA6EE6007187F2 /* InflectorKit in Frameworks */ = {isa = PBXBuildFile; productRef = E6E4209126A7DF4200B82624 /* InflectorKit */; };
DE796429276998B000978A03 /* IR+RootFieldBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE796428276998B000978A03 /* IR+RootFieldBuilder.swift */; };
DE79642B276999E700978A03 /* IRNamedFragmentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE79642A276999E700978A03 /* IRNamedFragmentBuilderTests.swift */; };
Expand Down Expand Up @@ -981,6 +983,8 @@
DE6B160B26152D210068D642 /* Project-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Debug.xcconfig"; sourceTree = "<group>"; };
DE6B160C26152D210068D642 /* Workspace-Packaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Packaging.xcconfig"; sourceTree = "<group>"; };
DE6B160D26152D210068D642 /* Workspace-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Shared.xcconfig"; sourceTree = "<group>"; };
DE6D07F827BC3B6D009F5F33 /* InputValueRenderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputValueRenderable.swift; sourceTree = "<group>"; };
DE6D07FA27BC3BE9009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationDefinition_VariableDefinition_Tests.swift; sourceTree = "<group>"; };
DE796428276998B000978A03 /* IR+RootFieldBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IR+RootFieldBuilder.swift"; sourceTree = "<group>"; };
DE79642A276999E700978A03 /* IRNamedFragmentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRNamedFragmentBuilderTests.swift; sourceTree = "<group>"; };
DE79642C27699A6A00978A03 /* IR+NamedFragmentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IR+NamedFragmentBuilder.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2017,6 +2021,7 @@
DE31A437276A78140020DC44 /* Templates */ = {
isa = PBXGroup;
children = (
DE6D07FC27BC3C81009F5F33 /* RenderingHelpers */,
E6C9849227929EBE009481BE /* EnumTemplate.swift */,
DE5FD60A276970FC0033EE23 /* FragmentTemplate.swift */,
E608FBA427B1EFDF00493756 /* HeaderCommentTemplate.swift */,
Expand All @@ -2027,7 +2032,6 @@
DE5FD5FC2769222D0033EE23 /* OperationDefinitionTemplate.swift */,
DE5FD60427694FA70033EE23 /* SchemaTemplate.swift */,
DE2739102769AEBA00B886EF /* SelectionSetTemplate.swift */,
DEE2DAA127BAF00500EC0607 /* GraphQLType+Rendered.swift */,
E6B42D0827A472A700A3BD58 /* SwiftPackageManagerModuleTemplate.swift */,
E64F7EB727A0854E0059C021 /* UnionTemplate.swift */,
);
Expand All @@ -2043,8 +2047,9 @@
E69BEDA62798B89600000D10 /* InputObjectTemplateTests.swift */,
E623FD2B2797A700008B4CED /* InterfaceTemplateTests.swift */,
E64F7EC227A1243A0059C021 /* ObjectTemplateTests.swift */,
DE09F9C5270269F800795949 /* OperationDefinitionTemplate_DocumentType_Tests.swift */,
DE09066E27A4713F00211300 /* OperationDefinitionTemplateTests.swift */,
DE09F9C5270269F800795949 /* OperationDefinitionTemplate_DocumentType_Tests.swift */,
DE6D07FA27BC3BE9009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift */,
DE5FD608276956C70033EE23 /* SchemaTemplateTests.swift */,
E6B42D0C27A4749100A3BD58 /* SwiftPackageManagerModuleTemplateTests.swift */,
E64F7EB927A085D90059C021 /* UnionTemplateTests.swift */,
Expand Down Expand Up @@ -2149,6 +2154,15 @@
path = Configuration/Shared;
sourceTree = SOURCE_ROOT;
};
DE6D07FC27BC3C81009F5F33 /* RenderingHelpers */ = {
isa = PBXGroup;
children = (
DEE2DAA127BAF00500EC0607 /* GraphQLType+Rendered.swift */,
DE6D07F827BC3B6D009F5F33 /* InputValueRenderable.swift */,
);
path = RenderingHelpers;
sourceTree = "<group>";
};
DE9C04AB26EA763E00EC35E7 /* Accumulators */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3171,6 +3185,7 @@
E610D8DB278EB0900023E495 /* InterfaceFileGenerator.swift in Sources */,
9B7B6F69233C2C0C00F32205 /* FileManager+Apollo.swift in Sources */,
E674DB41274C0A9B009BB90E /* Glob.swift in Sources */,
DE6D07F927BC3B6D009F5F33 /* InputValueRenderable.swift in Sources */,
DE5B318F27A48E060051C9D3 /* ImportStatementTemplate.swift in Sources */,
9F1A966C258F34BB00A06EEB /* GraphQLSchema.swift in Sources */,
9BE74D3D23FB4A8E006D354F /* FileFinder.swift in Sources */,
Expand Down Expand Up @@ -3254,6 +3269,7 @@
E6C9849527929FED009481BE /* EnumTemplateTests.swift in Sources */,
DE5FD609276956C70033EE23 /* SchemaTemplateTests.swift in Sources */,
E61EF713275EC99A00191DA7 /* ApolloCodegenTests.swift in Sources */,
DE6D07FD27BC3D53009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift in Sources */,
E6B4E9992798A8CB004EC8C4 /* InterfaceTemplateTests.swift in Sources */,
9F62DF8E2590539A00E6E808 /* SchemaIntrospectionTests.swift in Sources */,
E6D90D0D278FFE35009CAC5D /* SchemaFileGeneratorTests.swift in Sources */,
Expand Down
70 changes: 2 additions & 68 deletions Sources/ApolloCodegenLib/Templates/InputObjectTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct InputObjectTemplate {
private func InitializerParametersTemplate() -> TemplateString {
TemplateString("""
\(graphqlInputObject.fields.map({
"\($1.name): \($1.renderType(includeDefault: true))"
"\($1.name): \($1.renderInputValueType(includeDefault: true))"
}), separator: ",\n")
""")
}
Expand All @@ -44,76 +44,10 @@ struct InputObjectTemplate {

private func FieldPropertyTemplate(_ field: GraphQLInputField) -> String {
"""
var \(field.name): \(field.renderType()) {
var \(field.name): \(field.renderInputValueType()) {
get { dict[\"\(field.name)\"] }
set { dict[\"\(field.name)\"] = newValue }
}
"""
}
}

fileprivate extension GraphQLInputField {
func renderType(includeDefault: Bool = false) -> String {
"\(type.render())\(isSwiftOptional ? "?" : "")\(includeDefault && hasSwiftNilDefault ? " = nil" : "")"
}

var isSwiftOptional: Bool {
!isNullable && hasSchemaDefault
}

var hasSwiftNilDefault: Bool {
isNullable && !hasSchemaDefault
}

var isNullable: Bool {
switch type {
case .nonNull(_): return false
default: return true
}
}

var hasSchemaDefault: Bool {
switch defaultValue {
case .none, .some(nil):
return false
case let .some(value):
guard let value = value as? JSValue else {
fatalError("Cannot determine default value for Input field: \(self)")
}

return !value.isUndefined
}
}
}

fileprivate extension GraphQLType {
enum NullabilityContainer {
case none
case graphqlNullable
case swiftOptional
}

func render(nullability: NullabilityContainer = .graphqlNullable) -> String {
switch self {
case let .entity(type as GraphQLNamedType),
let .enum(type as GraphQLNamedType),
let .scalar(type as GraphQLNamedType),
let .inputObject(type as GraphQLNamedType):

switch nullability {
case .none: return type.swiftName
case .graphqlNullable: return "GraphQLNullable<\(type.swiftName)>"
case .swiftOptional: return "\(type.swiftName)?"
}

case let .nonNull(ofType):
return ofType.render(nullability: .none)

case let .list(ofType):
let inner = "[\(ofType.render(nullability: .swiftOptional))]"

if nullability == .graphqlNullable { return "GraphQLNullable<\(inner)>" }
else { return inner }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ struct OperationDefinitionTemplate {
\(OperationDeclaration(operation.definition))
\(DocumentType.render(operation.definition, fragments: operation.referencedFragments, apq: config.apqs))
\(section: VariableProperties(operation.definition.variables))
\(section: Variables.Properties(operation.definition.variables))
\(Initializer(operation.definition.variables))
\(section: VariablesAccessor(operation.definition.variables))
\(section: Variables.Accessors(operation.definition.variables))
\(SelectionSetTemplate(schema: schema).render(for: operation))
}
Expand Down Expand Up @@ -65,18 +65,6 @@ struct OperationDefinitionTemplate {
}
}

private func VariableProperties(
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
"""
\(variables.map { "public var \(VariableParameter($0))"}, separator: "\n")
"""
}

private func VariableParameter(_ variable: CompilationResult.VariableDefinition) -> String {
"\(variable.name): \(variable.type.rendered)"
}

private func Initializer(
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
Expand All @@ -86,24 +74,38 @@ struct OperationDefinitionTemplate {
}

return """
\(`init`)(\(list: variables.map(VariableParameter))) {
\(`init`)(\(list: variables.map(Variables.Parameter))) {
\(variables.map { "self.\($0.name) = \($0.name)" }, separator: "\n")
}
"""
}

private func VariablesAccessor(
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
guard !variables.isEmpty else {
return ""
enum Variables {
static func Properties(
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
"""
\(variables.map { "public var \($0.name): \($0.renderInputValueType())"}, separator: "\n")
"""
}

return """
static func Parameter(_ variable: CompilationResult.VariableDefinition) -> String {
"\(variable.name): \(variable.renderInputValueType(includeDefault: true))"
}

static func Accessors(
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
guard !variables.isEmpty else {
return ""
}

return """
public var variables: Variables? {
[\(variables.map { "\"\($0.name)\": \($0.name)"}, separator: ",\n ")]
}
"""
}
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// GraphQLInputValue+Rendered.swift
// ApolloCodegenLib
//
// Created by Anthony Miller on 2/15/22.
// Copyright © 2022 Apollo GraphQL. All rights reserved.
//

import Foundation

protocol InputValueRenderable {

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,25 @@ extension GraphQLType {
return containedInNonNull ? inner : "\(inner)?"
}
}

// MARK: Input Value

func renderAsInputValue() -> String {
return renderAsInputValue(inNullable: true)
}

private func renderAsInputValue(inNullable: Bool) -> String {
switch self {
case .entity, .enum, .scalar, .inputObject:
let typeName = self.rendered(containedInNonNull: true)
return inNullable ? "GraphQLNullable<\(typeName)>" : typeName

case let .nonNull(ofType):
return ofType.renderAsInputValue(inNullable: false)

case let .list(ofType):
let typeName = "[\(ofType.rendered)]"
return inNullable ? "GraphQLNullable<\(typeName)>" : typeName
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import JavaScriptCore

protocol InputValueRenderable {
var name: String { get }
var type: GraphQLType { get }
var hasDefaultValue: Bool { get }
}

extension InputValueRenderable {
func renderInputValueType(includeDefault: Bool = false) -> String {
"\(type.renderAsInputValue())\(isSwiftOptional ? "?" : "")\(includeDefault && hasSwiftNilDefault ? " = nil" : "")"
}

private var isSwiftOptional: Bool {
!isNullable && hasDefaultValue
}

private var hasSwiftNilDefault: Bool {
isNullable && !hasDefaultValue
}

var isNullable: Bool {
switch type {
case .nonNull: return false
default: return true
}
}
}

extension GraphQLInputField: InputValueRenderable {
var hasDefaultValue: Bool {
switch defaultValue {
case .none, .some(nil):
return false
case let .some(value):
guard let value = value as? JSValue else {
fatalError("Cannot determine default value for Input field: \(self)")
}

return !value.isUndefined
}
}
}

extension CompilationResult.VariableDefinition: InputValueRenderable {
var hasDefaultValue: Bool {
switch defaultValue {
case .none, .some(nil), .some(.null): return false
default: return true
}
}
}
14 changes: 14 additions & 0 deletions Sources/ApolloCodegenTestSupport/MockCompilationResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,17 @@ public extension CompilationResult.FragmentDefinition {
return mock
}
}

public extension CompilationResult.VariableDefinition {
class func mock(
_ name: String,
type: GraphQLType,
defaultValue: GraphQLValue?
) -> Self {
let mock = Self.emptyMockObject()
mock.name = name
mock.type = type
mock.defaultValue = defaultValue
return mock
}
}
Loading

0 comments on commit d3dd12e

Please sign in to comment.