Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding InputObject casing strategy #137

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase {
warningsOnDeprecatedUsage: .exclude,
conversionStrategies:.init(
enumCases: .none,
fieldAccessors: .camelCase
fieldAccessors: .camelCase,
inputObjects: .none
),
pruneGeneratedFiles: false,
markOperationDefinitionsAsFinal: true
Expand Down Expand Up @@ -94,7 +95,8 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase {
"cocoapodsCompatibleImportStatements" : true,
"conversionStrategies" : {
"enumCases" : "none",
"fieldAccessors" : "camelCase"
"fieldAccessors" : "camelCase",
"inputObjects" : "none"
},
"deprecatedEnumCases" : "exclude",
"markOperationDefinitionsAsFinal" : true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,11 @@ class InputObjectTemplateTests: XCTestCase {

buildSubject(
fields: fields,
config: .mock(.swiftPackageManager, schemaNamespace: "TestSchema")
config: .mock(.swiftPackageManager,
options: .init(
conversionStrategies: .init(inputObjects: .none)
),
schemaNamespace: "TestSchema")
)

let expected = """
Expand Down Expand Up @@ -2176,6 +2180,73 @@ class InputObjectTemplateTests: XCTestCase {

// MARK: Casing Tests

func test__casing__givenSchemaName_generatesWithNoCaseConversion() throws {
// given
let fields: [GraphQLInputField] = [
GraphQLInputField.mock(
"InputField",
type: .inputObject(.mock(
"InnerInputObject",
fields: [
GraphQLInputField.mock("InnerStringField", type: .scalar(.string()), defaultValue: nil)
]
)),
defaultValue: nil
),
GraphQLInputField.mock(
"inputField",
type: .inputObject(.mock(
"InnerInputObject",
fields: [
GraphQLInputField.mock("innerStringField", type: .scalar(.string()), defaultValue: nil)
]
)),
defaultValue: nil
)
]

buildSubject(
fields: fields,
config: .mock(schemaNamespace: "testschema",
output: .mock(
moduleType: .swiftPackageManager,
operations: .relative(subpath: nil)
),
options: .init(
conversionStrategies: .init(inputObjects: .none)
)
)
)

let expected = """
public init(
InputField: GraphQLNullable<Testschema.InnerInputObject> = nil,
inputField: GraphQLNullable<Testschema.InnerInputObject> = nil
) {
__data = InputDict([
"InputField": InputField,
"inputField": inputField
])
}

public var InputField: GraphQLNullable<Testschema.InnerInputObject> {
get { __data["InputField"] }
set { __data["InputField"] = newValue }
}

public var inputField: GraphQLNullable<Testschema.InnerInputObject> {
get { __data["inputField"] }
set { __data["inputField"] = newValue }
}
"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: true))
}

func test__casing__givenSchemaNameLowercased_nonListField_generatesWithFirstUppercasedNamespace() throws {
// given
let fields: [GraphQLInputField] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,16 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
case camelCase
}

/// ``ApolloCodegenConfiguration/ConversionStrategies/InputObjects`` is used to specify
/// the strategy used to convert the casing of input objects in a GraphQL schema into generated Swift code.
public enum InputObjects: String, Codable, Equatable {
/// Generates swift code using the exact name provided in the GraphQL schema
/// performing no conversion
case none
/// Convert to lower camel case from `snake_case`, `UpperCamelCase`, or `UPPERCASE`.
case camelCase
}

/// Determines how the names of enum cases in the GraphQL schema will be converted into
/// cases on the generated Swift enums.
/// Defaults to ``ApolloCodegenConfiguration/ConversionStrategies/CaseConversionStrategy/camelCase``
Expand All @@ -702,26 +712,35 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
/// properties in the generated Swift code.
/// Defaults to ``ApolloCodegenConfiguration/ConversionStrategies/FieldAccessors/idiomatic``
public let fieldAccessors: FieldAccessors

/// Determines how the names of input objects in the GraphQL schema will be converted into
/// the generated Swift code.
/// Defaults to ``ApolloCodegenConfiguration/ConversionStrategies/InputObjects/camelCase``
public let inputObjects: InputObjects

/// Default property values
public struct Default {
public static let enumCases: EnumCases = .camelCase
public static let fieldAccessors: FieldAccessors = .idiomatic
public static let inputObjects: InputObjects = .camelCase
}

public init(
enumCases: EnumCases = Default.enumCases,
fieldAccessors: FieldAccessors = Default.fieldAccessors
fieldAccessors: FieldAccessors = Default.fieldAccessors,
inputObjects: InputObjects = Default.inputObjects
) {
self.enumCases = enumCases
self.fieldAccessors = fieldAccessors
self.inputObjects = inputObjects
}

// MARK: Codable

public enum CodingKeys: CodingKey {
case enumCases
case fieldAccessors
case inputObjects
}

@available(*, deprecated) // Deprecation attribute added to supress warning.
Expand Down Expand Up @@ -756,6 +775,11 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
FieldAccessors.self,
forKey: .fieldAccessors
) ?? Default.fieldAccessors

inputObjects = try values.decodeIfPresent(
InputObjects.self,
forKey: .inputObjects
) ?? Default.inputObjects
}
}

Expand Down Expand Up @@ -1444,6 +1468,7 @@ extension ApolloCodegenConfiguration.ConversionStrategies {
self.enumCases = .camelCase
}
self.fieldAccessors = Default.fieldAccessors
self.inputObjects = Default.inputObjects
}

/// ``CaseConversionStrategy`` is used to specify the strategy used to convert the casing of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ struct InputObjectTemplate: TemplateRenderer {
) -> TemplateString {
TemplateString("""
\(fields.map({
"\($1.name.renderAsFieldPropertyName(config: config.config)): \($1.renderInputValueType(includeDefault: true, config: config.config))"
"\($1.name.renderAsInputObjectName(config: config.config)): \($1.renderInputValueType(includeDefault: true, config: config.config))"
}), separator: ",\n")
""")
}
Expand All @@ -103,7 +103,7 @@ struct InputObjectTemplate: TemplateRenderer {
_ fields: GraphQLInputFieldDictionary
) -> TemplateString {
TemplateString("""
\(fields.map({ "\"\($1.name)\": \($1.name.renderAsFieldPropertyName(config: config.config))" }), separator: ",\n")
\(fields.map({ "\"\($1.name)\": \($1.name.renderAsInputObjectName(config: config.config))" }), separator: ",\n")
""")
}

Expand All @@ -112,7 +112,7 @@ struct InputObjectTemplate: TemplateRenderer {
\(documentation: field.documentation, config: config)
\(deprecationReason: field.deprecationReason, config: config)
\(accessControlModifier(for: .member))\
var \(field.name.renderAsFieldPropertyName(config: config.config)): \(field.renderInputValueType(config: config.config)) {
var \(field.name.renderAsInputObjectName(config: config.config)): \(field.renderInputValueType(config: config.config)) {
get { __data["\(field.name)"] }
set { __data["\(field.name)"] = newValue }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ extension String {
return propertyName.escapeIf(in: SwiftKeywords.FieldAccessorNamesToEscape)
}

func renderAsInputObjectName(
config: ApolloCodegenConfiguration
) -> String {
var propertyName = self

switch config.options.conversionStrategies.inputObjects {
case .none:
break
case .camelCase:
propertyName = propertyName.convertToCamelCase()
break
}

return propertyName.escapeIf(in: SwiftKeywords.FieldAccessorNamesToEscape)
}

/// Convert to `camelCase` from a number of different `snake_case` variants.
///
/// All inner `_` characters will be removed, each 'word' will be capitalized, returning a final
Expand Down
Loading