Skip to content

Commit 12cdd3c

Browse files
shadajtrevor-scheer
authored andcommitted
Fix Scala codegen emitting fields under names that don't match the schema (#1008)
* Fix Scala codegen emitting fields under names that don't match the schema * Improve typing in code generator
1 parent a230ecb commit 12cdd3c

7 files changed

Lines changed: 260 additions & 193 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
- `vscode-apollo@1.5.0`
1616
- Fix inline graphql highlighting in Vue `<script>` tags [#981](https://github.com/apollographql/apollo-tooling/pull/981)
1717
- Fix graphql comments not being highlighted correctly [#907](https://github.com/apollographql/apollo-tooling/pull/907)
18+
- `apollo-codegen-scala`
19+
- Fix types sometimes being emitted with fields that don't match the underlying data [#1008](https://github.com/apollographql/apollo-tooling/pull/1008)
1820

1921
## `apollo@2.4.4`, `apollo-codegen-scala@0.33.0`
2022

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

Lines changed: 168 additions & 118 deletions
Large diffs are not rendered by default.

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,38 @@ describe("Scala code generation", function() {
453453
expect(generator.output).toMatchSnapshot();
454454
});
455455

456+
test(`should handle underscores in a trait declaration for a selection set`, function() {
457+
traitDeclarationForSelectionSet(generator, {
458+
traitName: "TypeWithUnderscore",
459+
parentType: undefined,
460+
fields: [
461+
{
462+
responseName: "_id",
463+
fieldName: "_id",
464+
type: GraphQLString
465+
}
466+
]
467+
});
468+
469+
expect(generator.output).toMatchSnapshot();
470+
});
471+
472+
test(`should handle escaped values in a trait declaration for a selection set`, function() {
473+
traitDeclarationForSelectionSet(generator, {
474+
traitName: "TypeWithUnderscore",
475+
parentType: undefined,
476+
fields: [
477+
{
478+
responseName: "class",
479+
fieldName: "class",
480+
type: GraphQLString
481+
}
482+
]
483+
});
484+
485+
expect(generator.output).toMatchSnapshot();
486+
});
487+
456488
test(`should generate a nested trait declaration for a selection set with subselections`, function() {
457489
traitDeclarationForSelectionSet(generator, {
458490
traitName: "Hero",

packages/apollo-codegen-scala/src/codeGeneration.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,10 @@ function dataContainerDeclaration(
443443
insideCompanion
444444
}: {
445445
name: string;
446-
properties: Property[];
446+
properties: (Property & {
447+
name?: string;
448+
responseName?: string;
449+
})[];
447450
extraSuperClasses?: string[];
448451
description?: string;
449452
insideCompanion?: () => void;
@@ -460,6 +463,7 @@ function dataContainerDeclaration(
460463
() => {
461464
properties.forEach(p => {
462465
propertyDeclaration(generator, {
466+
jsName: p.name || p.responseName,
463467
propertyName: p.propertyName,
464468
typeName: p.typeName
465469
});
@@ -489,7 +493,7 @@ function dataContainerDeclaration(
489493
},
490494
() => {
491495
const propertiesIn = properties
492-
.map(p => `${p.propertyName} = ${p.propertyName}`)
496+
.map(p => `"${p.name || p.responseName}" -> ${p.propertyName}`)
493497
.join(", ");
494498
generator.printOnNewline(
495499
`scala.scalajs.js.Dynamic.literal(${propertiesIn}).asInstanceOf[${name}]`
@@ -536,7 +540,7 @@ function dataContainerDeclaration(
536540
},
537541
() => {
538542
const propertiesIn = properties
539-
.map(p => `${p.propertyName} = ${p.propertyName}`)
543+
.map(p => `"${p.name || p.responseName}" -> ${p.propertyName}`)
540544
.join(", ");
541545
generator.printOnNewline(
542546
`scala.scalajs.js.Dynamic.literal(${propertiesIn}).asInstanceOf[${name}]`

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,12 @@ export function methodDeclaration(
130130
export function propertyDeclaration(
131131
generator: CodeGenerator<LegacyCompilerContext, any>,
132132
{
133+
jsName,
133134
propertyName,
134135
typeName,
135136
description
136137
}: {
138+
jsName?: string;
137139
propertyName: string;
138140
typeName: string;
139141
description?: string;
@@ -145,7 +147,9 @@ export function propertyDeclaration(
145147
}
146148

147149
generator.printOnNewline(
148-
`val ${propertyName}: ${typeName}` + (closure ? ` =` : "")
150+
(jsName ? `@scala.scalajs.js.annotation.JSName("${jsName}") ` : "") +
151+
`val ${propertyName}: ${typeName}` +
152+
(closure ? ` =` : "")
149153
);
150154

151155
if (closure) {

packages/apollo-codegen-scala/src/naming.ts

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -57,47 +57,31 @@ export function propertyFromInputField(
5757
const isOptional = !(type instanceof GraphQLNonNull);
5858
const bareType = getNamedType(type);
5959

60-
if (isCompositeType(bareType)) {
61-
const bareTypeName = join(
62-
[
63-
namespace,
64-
parentTraitName,
65-
escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
66-
],
67-
"."
68-
);
69-
const typeName = typeNameFromGraphQLType(
70-
context,
71-
type,
72-
bareTypeName,
73-
isOptional,
74-
true
75-
);
76-
return {
77-
...field,
78-
propertyName,
79-
typeName,
80-
isOptional,
81-
isList,
82-
description: field.description || undefined
83-
};
84-
} else {
85-
const typeName = typeNameFromGraphQLType(
86-
context,
87-
type,
88-
undefined,
89-
isOptional,
90-
true
91-
);
92-
return {
93-
...field,
94-
propertyName,
95-
typeName,
96-
isOptional,
97-
isList,
98-
description: field.description || undefined
99-
};
100-
}
60+
const bareTypeName = isCompositeType(bareType)
61+
? join(
62+
[
63+
namespace,
64+
parentTraitName,
65+
escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
66+
],
67+
"."
68+
)
69+
: undefined;
70+
const typeName = typeNameFromGraphQLType(
71+
context,
72+
type,
73+
bareTypeName,
74+
isOptional,
75+
true
76+
);
77+
return {
78+
...field,
79+
propertyName,
80+
typeName,
81+
isOptional,
82+
isList,
83+
description: field.description || undefined
84+
};
10185
}
10286

10387
export function propertyFromLegacyField(
@@ -107,39 +91,30 @@ export function propertyFromLegacyField(
10791
parentTraitName?: string
10892
): LegacyField & Property {
10993
const name = field.responseName;
110-
const unescapedPropertyName = isMetaFieldName(name) ? name : camelCase(name);
111-
const propertyName = escapeIdentifierIfNeeded(unescapedPropertyName);
94+
const propertyName = escapeIdentifierIfNeeded(name);
11295

11396
const type = field.type;
11497
const isList = type instanceof GraphQLList || type instanceof GraphQLList;
11598
const isOptional = field.isConditional || !(type instanceof GraphQLNonNull);
11699
const bareType = getNamedType(type);
117100

118-
if (isCompositeType(bareType)) {
119-
const bareTypeName = join(
120-
[
121-
namespace,
122-
parentTraitName,
123-
escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
124-
],
125-
"."
126-
);
127-
const typeName = typeNameFromGraphQLType(
128-
context,
129-
type,
130-
bareTypeName,
131-
isOptional
132-
);
133-
return { ...field, propertyName, typeName, isOptional, isList };
134-
} else {
135-
const typeName = typeNameFromGraphQLType(
136-
context,
137-
type,
138-
undefined,
139-
isOptional
140-
);
141-
return { ...field, propertyName, typeName, isOptional, isList };
142-
}
101+
const bareTypeName = isCompositeType(bareType)
102+
? join(
103+
[
104+
namespace,
105+
parentTraitName,
106+
escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
107+
],
108+
"."
109+
)
110+
: undefined;
111+
const typeName = typeNameFromGraphQLType(
112+
context,
113+
type,
114+
bareTypeName,
115+
isOptional
116+
);
117+
return { ...field, propertyName, typeName, isOptional, isList };
143118
}
144119

145120
function isMetaFieldName(name: string) {

packages/apollo/src/commands/client/__tests__/__snapshots__/generate.test.ts.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,12 @@ object SimpleQueryQuery extends com.apollographql.scalajs.GraphQLQuery {
283283
type Variables = Unit
284284
285285
@scala.scalajs.js.native trait Data extends scala.scalajs.js.Object {
286-
val hello: String
286+
@scala.scalajs.js.annotation.JSName(\\"hello\\") val hello: String
287287
}
288288
289289
object Data {
290290
def apply(hello: String) = {
291-
scala.scalajs.js.Dynamic.literal(hello = hello).asInstanceOf[Data]
291+
scala.scalajs.js.Dynamic.literal(\\"hello\\" -> hello).asInstanceOf[Data]
292292
}
293293
294294
def unapply(value: Data) = {
@@ -297,7 +297,7 @@ object SimpleQueryQuery extends com.apollographql.scalajs.GraphQLQuery {
297297
298298
implicit class CopyExtensions(private val orig: Data) extends AnyVal {
299299
def copy(hello: String = orig.hello) = {
300-
scala.scalajs.js.Dynamic.literal(hello = hello).asInstanceOf[Data]
300+
scala.scalajs.js.Dynamic.literal(\\"hello\\" -> hello).asInstanceOf[Data]
301301
}
302302
}
303303

0 commit comments

Comments
 (0)