Skip to content

Commit ff4cb06

Browse files
Merge pull request #1533 from lilyball/swift-self-field-in-init
swift: Fix initializers with field named `self`
2 parents f34ec78 + 849ea70 commit ff4cb06

6 files changed

Lines changed: 394 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
- `apollo-codegen-scala`
1010
- <First `apollo-codegen-scala` related entry goes here>
1111
- `apollo-codegen-swift`
12-
- <First `apollo-codegen-swift` related entry goes here>
12+
- Ensure fields named `self` don't cause compilation errors in the generated code [#1533](https://github.com/apollographql/apollo-tooling/pull/1533)
13+
- Preserve leading/trailing underscores on field names [#1533](https://github.com/apollographql/apollo-tooling/pull/1533)
1314
- `apollo-codegen-typescript`
1415
- <First `apollo-codegen-typescript` related entry goes here>
1516
- `apollo-env`

packages/apollo-codegen-swift/src/__tests__/__snapshots__/codeGeneration.ts.snap

Lines changed: 182 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,139 @@ exports[`Swift code generation #structDeclarationForFragment() should generate a
11851185
}"
11861186
`;
11871187

1188+
exports[`Swift code generation #structDeclarationForSelectionSet() should escape init specially in a struct declaration initializer for a selection set 1`] = `
1189+
"public struct Human: GraphQLSelectionSet {
1190+
public static let possibleTypes = [\\"Human\\"]
1191+
1192+
public static let selections: [GraphQLSelection] = [
1193+
GraphQLField(\\"friends\\", alias: \\"self\\", type: .list(.object(\`Self\`.selections))),
1194+
]
1195+
1196+
public private(set) var resultMap: ResultMap
1197+
1198+
public init(unsafeResultMap: ResultMap) {
1199+
self.resultMap = unsafeResultMap
1200+
}
1201+
1202+
public init(\`self\` _self: [\`Self\`?]? = nil) {
1203+
self.init(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"self\\": _self.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }])
1204+
}
1205+
1206+
/// This human's friends, or an empty list if they have none
1207+
public var \`self\`: [\`Self\`?]? {
1208+
get {
1209+
return (resultMap[\\"self\\"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [\`Self\`?] in value.map { (value: ResultMap?) -> \`Self\`? in value.flatMap { (value: ResultMap) -> \`Self\` in \`Self\`(unsafeResultMap: value) } } }
1210+
}
1211+
set {
1212+
resultMap.updateValue(newValue.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }, forKey: \\"self\\")
1213+
}
1214+
}
1215+
1216+
public struct \`Self\`: GraphQLSelectionSet {
1217+
public static let possibleTypes = [\\"Human\\", \\"Droid\\"]
1218+
1219+
public static let selections: [GraphQLSelection] = [
1220+
GraphQLField(\\"id\\", type: .nonNull(.scalar(GraphQLID.self))),
1221+
]
1222+
1223+
public private(set) var resultMap: ResultMap
1224+
1225+
public init(unsafeResultMap: ResultMap) {
1226+
self.resultMap = unsafeResultMap
1227+
}
1228+
1229+
public static func makeHuman(id: GraphQLID) -> \`Self\` {
1230+
return \`Self\`(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"id\\": id])
1231+
}
1232+
1233+
public static func makeDroid(id: GraphQLID) -> \`Self\` {
1234+
return \`Self\`(unsafeResultMap: [\\"__typename\\": \\"Droid\\", \\"id\\": id])
1235+
}
1236+
1237+
/// The ID of the character
1238+
public var id: GraphQLID {
1239+
get {
1240+
return resultMap[\\"id\\"]! as! GraphQLID
1241+
}
1242+
set {
1243+
resultMap.updateValue(newValue, forKey: \\"id\\")
1244+
}
1245+
}
1246+
}
1247+
}
1248+
1249+
public struct Human: GraphQLSelectionSet {
1250+
public static let possibleTypes = [\\"Human\\"]
1251+
1252+
public static let selections: [GraphQLSelection] = [
1253+
GraphQLField(\\"friends\\", alias: \\"self\\", type: .list(.object(\`Self\`.selections))),
1254+
GraphQLField(\\"name\\", alias: \\"_self\\", type: .nonNull(.scalar(String.self))),
1255+
]
1256+
1257+
public private(set) var resultMap: ResultMap
1258+
1259+
public init(unsafeResultMap: ResultMap) {
1260+
self.resultMap = unsafeResultMap
1261+
}
1262+
1263+
public init(\`self\` _self_: [\`Self\`?]? = nil, _self: String) {
1264+
self.init(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"self\\": _self_.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }, \\"_self\\": _self])
1265+
}
1266+
1267+
/// This human's friends, or an empty list if they have none
1268+
public var \`self\`: [\`Self\`?]? {
1269+
get {
1270+
return (resultMap[\\"self\\"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [\`Self\`?] in value.map { (value: ResultMap?) -> \`Self\`? in value.flatMap { (value: ResultMap) -> \`Self\` in \`Self\`(unsafeResultMap: value) } } }
1271+
}
1272+
set {
1273+
resultMap.updateValue(newValue.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }, forKey: \\"self\\")
1274+
}
1275+
}
1276+
1277+
/// What this human calls themselves
1278+
public var _self: String {
1279+
get {
1280+
return resultMap[\\"_self\\"]! as! String
1281+
}
1282+
set {
1283+
resultMap.updateValue(newValue, forKey: \\"_self\\")
1284+
}
1285+
}
1286+
1287+
public struct \`Self\`: GraphQLSelectionSet {
1288+
public static let possibleTypes = [\\"Human\\", \\"Droid\\"]
1289+
1290+
public static let selections: [GraphQLSelection] = [
1291+
GraphQLField(\\"id\\", type: .nonNull(.scalar(GraphQLID.self))),
1292+
]
1293+
1294+
public private(set) var resultMap: ResultMap
1295+
1296+
public init(unsafeResultMap: ResultMap) {
1297+
self.resultMap = unsafeResultMap
1298+
}
1299+
1300+
public static func makeHuman(id: GraphQLID) -> \`Self\` {
1301+
return \`Self\`(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"id\\": id])
1302+
}
1303+
1304+
public static func makeDroid(id: GraphQLID) -> \`Self\` {
1305+
return \`Self\`(unsafeResultMap: [\\"__typename\\": \\"Droid\\", \\"id\\": id])
1306+
}
1307+
1308+
/// The ID of the character
1309+
public var id: GraphQLID {
1310+
get {
1311+
return resultMap[\\"id\\"]! as! GraphQLID
1312+
}
1313+
set {
1314+
resultMap.updateValue(newValue, forKey: \\"id\\")
1315+
}
1316+
}
1317+
}
1318+
}"
1319+
`;
1320+
11881321
exports[`Swift code generation #structDeclarationForSelectionSet() should escape reserved keywords in a struct declaration for a selection set 1`] = `
11891322
"public struct Hero: GraphQLSelectionSet {
11901323
public static let possibleTypes = [\\"Human\\", \\"Droid\\"]
@@ -1200,12 +1333,12 @@ exports[`Swift code generation #structDeclarationForSelectionSet() should escape
12001333
self.resultMap = unsafeResultMap
12011334
}
12021335

1203-
public static func makeHuman(\`private\`: String, \`self\`: [\`Self\`?]? = nil) -> Hero {
1204-
return Hero(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"private\\": \`private\`, \\"self\\": \`self\`.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }])
1336+
public static func makeHuman(\`private\`: String, \`self\` _self: [\`Self\`?]? = nil) -> Hero {
1337+
return Hero(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"private\\": \`private\`, \\"self\\": _self.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }])
12051338
}
12061339

1207-
public static func makeDroid(\`private\`: String, \`self\`: [\`Self\`?]? = nil) -> Hero {
1208-
return Hero(unsafeResultMap: [\\"__typename\\": \\"Droid\\", \\"private\\": \`private\`, \\"self\\": \`self\`.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }])
1340+
public static func makeDroid(\`private\`: String, \`self\` _self: [\`Self\`?]? = nil) -> Hero {
1341+
return Hero(unsafeResultMap: [\\"__typename\\": \\"Droid\\", \\"private\\": \`private\`, \\"self\\": _self.flatMap { (value: [\`Self\`?]) -> [ResultMap?] in value.map { (value: \`Self\`?) -> ResultMap? in value.flatMap { (value: \`Self\`) -> ResultMap in value.resultMap } } }])
12091342
}
12101343

12111344
/// The name of the character
@@ -1786,6 +1919,51 @@ exports[`Swift code generation #structDeclarationForSelectionSet() should genera
17861919
}"
17871920
`;
17881921

1922+
exports[`Swift code generation #structDeclarationForSelectionSet() should preserve leading and trailing underscores on fields 1`] = `
1923+
"public struct Hero: GraphQLSelectionSet {
1924+
public static let possibleTypes = [\\"Human\\", \\"Droid\\"]
1925+
1926+
public static let selections: [GraphQLSelection] = [
1927+
GraphQLField(\\"name\\", alias: \\"_name\\", type: .nonNull(.scalar(String.self))),
1928+
GraphQLField(\\"id\\", alias: \\"_camel_case_id__\\", type: .nonNull(.scalar(GraphQLID.self))),
1929+
]
1930+
1931+
public private(set) var resultMap: ResultMap
1932+
1933+
public init(unsafeResultMap: ResultMap) {
1934+
self.resultMap = unsafeResultMap
1935+
}
1936+
1937+
public static func makeHuman(_name: String, _camelCaseId__: GraphQLID) -> Hero {
1938+
return Hero(unsafeResultMap: [\\"__typename\\": \\"Human\\", \\"_name\\": _name, \\"_camel_case_id__\\": _camelCaseId__])
1939+
}
1940+
1941+
public static func makeDroid(_name: String, _camelCaseId__: GraphQLID) -> Hero {
1942+
return Hero(unsafeResultMap: [\\"__typename\\": \\"Droid\\", \\"_name\\": _name, \\"_camel_case_id__\\": _camelCaseId__])
1943+
}
1944+
1945+
/// The name of the character
1946+
public var _name: String {
1947+
get {
1948+
return resultMap[\\"_name\\"]! as! String
1949+
}
1950+
set {
1951+
resultMap.updateValue(newValue, forKey: \\"_name\\")
1952+
}
1953+
}
1954+
1955+
/// The ID of the character
1956+
public var _camelCaseId__: GraphQLID {
1957+
get {
1958+
return resultMap[\\"_camel_case_id__\\"]! as! GraphQLID
1959+
}
1960+
set {
1961+
resultMap.updateValue(newValue, forKey: \\"_camel_case_id__\\")
1962+
}
1963+
}
1964+
}"
1965+
`;
1966+
17891967
exports[`Swift code generation #typeDeclarationForGraphQLType() should escape identifiers in cases of enum declaration for a GraphQLEnumType 1`] = `
17901968
"public enum AlbumPrivacies: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable {
17911969
public typealias RawValue = String

packages/apollo-codegen-swift/src/__tests__/codeGeneration.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,30 @@ describe("Swift code generation", () => {
455455
expect(generator.output).toMatchSnapshot();
456456
});
457457

458+
it(`should preserve leading and trailing underscores on fields`, () => {
459+
const { operations } = compile(`
460+
query Hero {
461+
hero {
462+
_name: name
463+
_camel_case_id__: id
464+
}
465+
}
466+
`);
467+
468+
const selectionSet = (operations["Hero"].selectionSet
469+
.selections[0] as Field).selectionSet as SelectionSet;
470+
471+
generator.structDeclarationForSelectionSet(
472+
{
473+
structName: "Hero",
474+
selectionSet
475+
},
476+
false
477+
);
478+
479+
expect(generator.output).toMatchSnapshot();
480+
});
481+
458482
it(`should escape reserved keywords in a struct declaration for a selection set`, () => {
459483
const { operations } = compile(`
460484
query Hero {
@@ -481,6 +505,46 @@ describe("Swift code generation", () => {
481505
expect(generator.output).toMatchSnapshot();
482506
});
483507

508+
it(`should escape init specially in a struct declaration initializer for a selection set`, () => {
509+
const { operations } = compile(`
510+
query Humans {
511+
human(id: 0) {
512+
self: friends {
513+
id
514+
}
515+
}
516+
human(id: 1) {
517+
self: friends {
518+
id
519+
}
520+
_self: name
521+
}
522+
}
523+
`);
524+
525+
const human0 = (operations["Humans"].selectionSet.selections[0] as Field)
526+
.selectionSet as SelectionSet;
527+
const human1 = (operations["Humans"].selectionSet.selections[1] as Field)
528+
.selectionSet as SelectionSet;
529+
530+
generator.structDeclarationForSelectionSet(
531+
{
532+
structName: "Human",
533+
selectionSet: human0
534+
},
535+
false
536+
);
537+
generator.structDeclarationForSelectionSet(
538+
{
539+
structName: "Human",
540+
selectionSet: human1
541+
},
542+
false
543+
);
544+
545+
expect(generator.output).toMatchSnapshot();
546+
});
547+
484548
it(`should generate a nested struct declaration for a selection set with subselections`, () => {
485549
const { operations } = compile(`
486550
query Hero {

0 commit comments

Comments
 (0)