Skip to content

Commit 4cffd32

Browse files
authored
[Feat][Typescript Angular] Implement deepObject query params (OAS3.0) (#21108)
* feature: implement deepObject query params as per documentation. Closes #19342. * chore: regenerate samples. * chore: symplify code (via @joscha) * chore: regenerate samples * test: add integration test for typescript-angular deepObject query params * fix: typo in the integration tests path * chore: use node v18 for integration tests * chore: make ES6 compliant * chore: make test name semantically accurate * chore: regenerate samples * test: add angular v16 deep-object test * chore: delete previous bespoke test for deep objects (uses test introduced in 71629f8 instead) * chore: restore missing OAS for deep object API tests * test: move angular deepObject tests to v19 and delete v16 ones * test: atomic deepObject test on service rather than integration with app component * chore: clean up superfluous import
1 parent f281371 commit 4cffd32

File tree

49 files changed

+1225
-82
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1225
-82
lines changed

CI/circle_parallel.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ elif [ "$NODE_INDEX" = "3" ]; then
7474
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
7575
#nvm install stable
7676
# install v16 instead of the latest stable version
77-
nvm install 16
78-
nvm alias default 16
77+
nvm install 18
78+
nvm alias default 18
7979
node --version
8080

8181
# Each step uses the same `$BASH_ENV`, so need to modify it
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
generatorName: typescript-angular
2+
outputDir: samples/client/petstore/typescript-angular-v19/builds/deep-object
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/deep-object-query.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
5+
additionalProperties:
6+
ngVersion: 19.0.0
7+
npmName: sample-angular-19-0-0-deep-object
8+
supportsES6: true

modules/openapi-generator/src/main/resources/typescript-angular/api.base.service.mustache

+9-4
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,27 @@ export class BaseService {
2929
return consumes.indexOf('multipart/form-data') !== -1;
3030
}
3131

32-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
32+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
3333
// If the value is an object (but not a Date), recursively add its keys.
3434
if (typeof value === 'object' && !(value instanceof Date)) {
35-
return this.addToHttpParamsRecursive(httpParams, value);
35+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
3636
}
3737
return this.addToHttpParamsRecursive(httpParams, value, key);
3838
}
3939

40-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
40+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4141
if (value === null || value === undefined) {
4242
return httpParams;
4343
}
4444
if (typeof value === 'object') {
4545
// If JSON format is preferred, key must be provided.
4646
if (key != null) {
47-
return httpParams.append(key, JSON.stringify(value));
47+
return isDeep
48+
? Object.keys(value as Record<string, any>).reduce(
49+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
50+
httpParams,
51+
)
52+
: httpParams.append(key, JSON.stringify(value));
4853
}
4954
// Otherwise, if it's an array, add each element.
5055
if (Array.isArray(value)) {

modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export class {{classname}} extends BaseService {
130130
{{/isArray}}
131131
{{^isArray}}
132132
localVarQueryParameters = this.addToHttpParams(localVarQueryParameters,
133-
<any>{{paramName}}, '{{baseName}}');
133+
<any>{{paramName}}, '{{baseName}}'{{#isDeepObject}}, true{{/isDeepObject}});
134134
{{/isArray}}
135135
{{/queryParams}}
136136

modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/typescriptangular/TypeScriptAngularClientCodegenTest.java

+25
Original file line numberDiff line numberDiff line change
@@ -464,4 +464,29 @@ public void testEnumAsConst() throws IOException {
464464
assertThat(fileContents).containsOnlyOnce("} as const;");
465465
assertThat(fileContents).doesNotContain(" as Type");
466466
}
467+
468+
@Test
469+
public void testDeepObject() throws IOException {
470+
// GIVEN
471+
final String specPath = "src/test/resources/3_0/deepobject.yaml";
472+
473+
File output = Files.createTempDirectory("test").toFile();
474+
output.deleteOnExit();
475+
476+
// WHEN
477+
final CodegenConfigurator configurator = new CodegenConfigurator()
478+
.setGeneratorName("typescript-angular")
479+
.setInputSpec(specPath)
480+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
481+
482+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
483+
484+
Generator generator = new DefaultGenerator();
485+
generator.opts(clientOptInput).generate();
486+
487+
// THEN
488+
final String fileContents = Files.readString(Paths.get(output + "/api/default.service.ts"));
489+
assertThat(fileContents).containsOnlyOnce("<any>options, 'options', true);");
490+
assertThat(fileContents).containsOnlyOnce("<any>inputOptions, 'inputOptions', true);");
491+
}
467492
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
openapi: 3.0.0
2+
info:
3+
title: deepobject-query
4+
version: 1.0.0
5+
paths:
6+
/car:
7+
get:
8+
operationId: getCars
9+
parameters:
10+
- name: filter
11+
in: query
12+
required: false
13+
style: deepObject
14+
schema:
15+
$ref: '#/components/schemas/CarFilter'
16+
explode: true
17+
responses:
18+
'200':
19+
description: OK
20+
content:
21+
text/plain:
22+
schema:
23+
type: array
24+
items:
25+
$ref: '#/components/schemas/Car'
26+
components:
27+
schemas:
28+
Car:
29+
type: object
30+
properties:
31+
id:
32+
type: integer
33+
format: int64
34+
example: 1
35+
make:
36+
type: string
37+
example: Toyota
38+
model:
39+
type: string
40+
example: Camry
41+
CarFilter:
42+
type: object
43+
properties:
44+
make:
45+
type: string
46+
example: Toyota
47+
model:
48+
type: string
49+
example: Camry

samples/client/others/typescript-angular/builds/composed-schemas-tagged-unions/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/others/typescript-angular/builds/composed-schemas/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v12-oneOf/builds/default/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v12-provided-in-any/builds/default/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v12-provided-in-root/builds/default/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v12-provided-in-root/builds/with-npm/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v13-oneOf/builds/default/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

samples/client/petstore/typescript-angular-v13-provided-in-any/builds/default/api.base.service.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ export class BaseService {
3737
return consumes.indexOf('multipart/form-data') !== -1;
3838
}
3939

40-
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
40+
protected addToHttpParams(httpParams: HttpParams, value: any, key?: string, isDeep: boolean = false): HttpParams {
4141
// If the value is an object (but not a Date), recursively add its keys.
4242
if (typeof value === 'object' && !(value instanceof Date)) {
43-
return this.addToHttpParamsRecursive(httpParams, value);
43+
return this.addToHttpParamsRecursive(httpParams, value, isDeep ? key : undefined, isDeep);
4444
}
4545
return this.addToHttpParamsRecursive(httpParams, value, key);
4646
}
4747

48-
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams {
48+
protected addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string, isDeep: boolean = false): HttpParams {
4949
if (value === null || value === undefined) {
5050
return httpParams;
5151
}
5252
if (typeof value === 'object') {
5353
// If JSON format is preferred, key must be provided.
5454
if (key != null) {
55-
return httpParams.append(key, JSON.stringify(value));
55+
return isDeep
56+
? Object.keys(value as Record<string, any>).reduce(
57+
(hp, k) => hp.append(`${key}[${k}]`, value[k]),
58+
httpParams,
59+
)
60+
: httpParams.append(key, JSON.stringify(value));
5661
}
5762
// Otherwise, if it's an array, add each element.
5863
if (Array.isArray(value)) {

0 commit comments

Comments
 (0)