Skip to content

Commit 5bab071

Browse files
committed
swift: Fix codegen with empty input objects / arrays
The codegen was omitting the `[:]` and `[]` tokens entirely. Fixes apollographql/apollo-ios#838
1 parent ce432f1 commit 5bab071

4 files changed

Lines changed: 113 additions & 41 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
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+
- Fix code generation for empty input objects / arrays [#1589](https://github.com/apollographql/apollo-tooling/pull/1589)
1313
- `apollo-codegen-typescript`
1414
- <First `apollo-codegen-typescript` related entry goes here>
1515
- `apollo-env`

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
buildSchema,
23
parse,
34
GraphQLNonNull,
45
GraphQLString,
@@ -754,5 +755,70 @@ describe("Swift code generation", () => {
754755
'["episode": "JEDI", "review": ["stars": 2, "commentary": GraphQLVariable("commentary"), "favorite_color": ["red": GraphQLVariable("red"), "blue": 100, "green": 50]]]'
755756
);
756757
});
758+
759+
it("should handle empty input objects", () => {
760+
// The existing schemas don't contain any input objects with all nullable types.
761+
// Extending the schema in a call to `compile` doesn't seem to work.
762+
// So instead we'll just build our own.
763+
const schema = buildSchema(`
764+
schema {
765+
query: Query
766+
}
767+
type Query {
768+
foo(input: FooInput!): Int
769+
}
770+
input FooInput {
771+
id: ID
772+
}
773+
`);
774+
const document = parse(`
775+
query FieldArgumentsWithEmptyInputObject {
776+
foo(input: {}) {
777+
id
778+
}
779+
}
780+
`);
781+
const context = compileToIR(schema, document);
782+
generator.context = context;
783+
784+
const { operations } = context;
785+
const fieldArguments = (operations["FieldArgumentsWithEmptyInputObject"]
786+
.selectionSet.selections[0] as Field).args as Argument[];
787+
const dictionaryLiteral = generator.helpers.dictionaryLiteralForFieldArguments(
788+
fieldArguments
789+
).source;
790+
791+
expect(dictionaryLiteral).toBe('["input": [:]]');
792+
});
793+
794+
it("should handle empty input arrays", () => {
795+
// As with the previous test, we need to build our own schema.
796+
const schema = buildSchema(`
797+
schema {
798+
query: Query
799+
}
800+
type Query {
801+
foo(input: [Int!]!): Int
802+
}
803+
`);
804+
const document = parse(`
805+
query FieldArgumentsWithEmptyInputArray {
806+
foo(input: []) {
807+
id
808+
}
809+
}
810+
`);
811+
const context = compileToIR(schema, document);
812+
generator.context = context;
813+
814+
const { operations } = context;
815+
const fieldArguments = (operations["FieldArgumentsWithEmptyInputArray"]
816+
.selectionSet.selections[0] as Field).args as Argument[];
817+
const dictionaryLiteral = generator.helpers.dictionaryLiteralForFieldArguments(
818+
fieldArguments
819+
).source;
820+
821+
expect(dictionaryLiteral).toBe('["input": []]');
822+
});
757823
});
758824
});

packages/apollo-codegen-swift/src/helpers.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -260,23 +260,27 @@ export class Helpers {
260260
value.variableName
261261
)})`;
262262
} else if (Array.isArray(value)) {
263-
return SwiftSource.wrap(
264-
swift`[`,
265-
SwiftSource.join(value.map(expressionFromValue), ", "),
266-
swift`]`
263+
return (
264+
SwiftSource.wrap(
265+
swift`[`,
266+
SwiftSource.join(value.map(expressionFromValue), ", "),
267+
swift`]`
268+
) || swift`[]`
267269
);
268270
} else if (typeof value === "object") {
269-
return SwiftSource.wrap(
270-
swift`[`,
271-
SwiftSource.join(
272-
Object.entries(value).map(([key, value]) => {
273-
return swift`${SwiftSource.string(key)}: ${expressionFromValue(
274-
value
275-
)}`;
276-
}),
277-
", "
278-
) || ":",
279-
swift`]`
271+
return (
272+
SwiftSource.wrap(
273+
swift`[`,
274+
SwiftSource.join(
275+
Object.entries(value).map(([key, value]) => {
276+
return swift`${SwiftSource.string(key)}: ${expressionFromValue(
277+
value
278+
)}`;
279+
}),
280+
", "
281+
),
282+
swift`]`
283+
) || swift`[:]`
280284
);
281285
} else if (typeof value === "string") {
282286
return SwiftSource.string(value);
@@ -285,17 +289,19 @@ export class Helpers {
285289
}
286290
}
287291

288-
return SwiftSource.wrap(
289-
swift`[`,
290-
SwiftSource.join(
291-
args.map(arg => {
292-
return swift`${SwiftSource.string(arg.name)}: ${expressionFromValue(
293-
arg.value
294-
)}`;
295-
}),
296-
", "
297-
) || ":",
298-
swift`]`
292+
return (
293+
SwiftSource.wrap(
294+
swift`[`,
295+
SwiftSource.join(
296+
args.map(arg => {
297+
return swift`${SwiftSource.string(arg.name)}: ${expressionFromValue(
298+
arg.value
299+
)}`;
300+
}),
301+
", "
302+
),
303+
swift`]`
304+
) || swift`[:]`
299305
);
300306
}
301307

packages/apollo-codegen-swift/src/language.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -276,30 +276,29 @@ export class SwiftSource {
276276
}
277277

278278
/**
279-
* If maybeSource is not null or empty, then wrap with start and end, otherwise return an empty
280-
* string.
279+
* If maybeSource is not undefined or empty, then wrap with start and end, otherwise return
280+
* undefined.
281281
*
282-
* This is just a wrapper for `wrap()` from apollo-codegen-core/lib/utilities/printing.
282+
* This is largely just a wrapper for `wrap()` from apollo-codegen-core/lib/utilities/printing.
283283
*/
284284
static wrap(
285285
start: SwiftSource,
286286
maybeSource?: SwiftSource,
287287
end?: SwiftSource
288-
): SwiftSource {
289-
return new SwiftSource(
290-
_wrap(
291-
start.source,
292-
maybeSource !== undefined ? maybeSource.source : undefined,
293-
end !== undefined ? end.source : undefined
294-
)
288+
): SwiftSource | undefined {
289+
const result = _wrap(
290+
start.source,
291+
maybeSource !== undefined ? maybeSource.source : undefined,
292+
end !== undefined ? end.source : undefined
295293
);
294+
return result ? new SwiftSource(result) : undefined;
296295
}
297296

298297
/**
299-
* Given maybeArray, return an empty string if it is null or empty, otherwise return all items
298+
* Given maybeArray, return undefined if it is undefined or empty, otherwise return all items
300299
* together separated by separator if provided.
301300
*
302-
* This is just a wrapper for `join()` from apollo-codegen-core/lib/utilities/printing.
301+
* This is largely just a wrapper for `join()` from apollo-codegen-core/lib/utilities/printing.
303302
*
304303
* @param separator The separator to put between elements. This is typed as `string` with the
305304
* expectation that it's generally something like `', '` but if it contains identifiers it should
@@ -308,8 +307,9 @@ export class SwiftSource {
308307
static join(
309308
maybeArray?: (SwiftSource | undefined)[],
310309
separator?: string
311-
): SwiftSource {
312-
return new SwiftSource(_join(maybeArray, separator));
310+
): SwiftSource | undefined {
311+
const result = _join(maybeArray, separator);
312+
return result ? new SwiftSource(result) : undefined;
313313
}
314314
}
315315

0 commit comments

Comments
 (0)