Skip to content

Commit

Permalink
fix: fixes performance issue in java when calling parent unions
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethaasan committed Sep 8, 2023
1 parent c02aca4 commit 68d70fe
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 193 deletions.
112 changes: 61 additions & 51 deletions src/generators/AbstractGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,10 @@ export abstract class AbstractGenerator<
return options.dependencyManager;
}

/**
* Generates the full output of a model, instead of a scattered model.
*
* OutputModels result is no longer the model itself, but including package, package dependencies and model dependencies.
*
*/
public async generateCompleteModels(
input: any | InputMetaModel,
completeOptions: Partial<RenderCompleteModelOptions>
): Promise<OutputModel[]> {
const inputModel = await this.processInput(input);

private getConstrainedModels(inputModel: InputMetaModel): Array<{
constrainedModel: ConstrainedMetaModel;
dependencyManager: AbstractDependencyManager;
}> {
interface ConstrainedMetaModelWithDepManager {
constrainedModel: ConstrainedMetaModel;
dependencyManager: AbstractDependencyManager;
Expand Down Expand Up @@ -156,6 +148,7 @@ export abstract class AbstractGenerator<
unionConstrainedModelsWithDepManager.push(
getConstrainedMetaModelWithDepManager(model)
);
continue;
}

constrainedModelsWithDepManager.push(
Expand Down Expand Up @@ -185,25 +178,42 @@ export abstract class AbstractGenerator<
}
}

return [
...unionConstrainedModelsWithDepManager,
...constrainedModelsWithDepManager
];
}

/**
* Generates the full output of a model, instead of a scattered model.
*
* OutputModels result is no longer the model itself, but including package, package dependencies and model dependencies.
*
*/
public async generateCompleteModels(
input: any | InputMetaModel,
completeOptions: Partial<RenderCompleteModelOptions>
): Promise<OutputModel[]> {
const inputModel = await this.processInput(input);

return Promise.all(
[
...unionConstrainedModelsWithDepManager,
...constrainedModelsWithDepManager
].map(async ({ constrainedModel, dependencyManager }) => {
const renderedOutput = await this.renderCompleteModel({
constrainedModel,
inputModel,
completeOptions,
options: { dependencyManager } as DeepPartial<Options>
});
return OutputModel.toOutputModel({
result: renderedOutput.result,
modelName: renderedOutput.renderedName,
dependencies: renderedOutput.dependencies,
model: constrainedModel,
inputModel
});
})
this.getConstrainedModels(inputModel).map(
async ({ constrainedModel, dependencyManager }) => {
const renderedOutput = await this.renderCompleteModel({
constrainedModel,
inputModel,
completeOptions,
options: { dependencyManager } as DeepPartial<Options>
});
return OutputModel.toOutputModel({
result: renderedOutput.result,
modelName: renderedOutput.renderedName,
dependencies: renderedOutput.dependencies,
model: constrainedModel,
inputModel
});
}
)
);
}

Expand All @@ -212,27 +222,27 @@ export abstract class AbstractGenerator<
*/
public async generate(input: any | InputMetaModel): Promise<OutputModel[]> {
const inputModel = await this.processInput(input);
const renders = Object.values(inputModel.models).map(async (model) => {
const dependencyManager = this.getDependencyManager(this.options);
const constrainedModel = this.constrainToMetaModel(model, {
dependencyManager
} as DeepPartial<Options>);
const renderedOutput = await this.render({
constrainedModel,
inputModel,
options: {
dependencyManager
} as DeepPartial<Options>
});
return OutputModel.toOutputModel({
result: renderedOutput.result,
modelName: renderedOutput.renderedName,
dependencies: renderedOutput.dependencies,
model: constrainedModel,
inputModel
});
});
return Promise.all(renders);

return Promise.all(
this.getConstrainedModels(inputModel).map(
async ({ constrainedModel, dependencyManager }) => {
const renderedOutput = await this.render({
constrainedModel,
inputModel,
options: {
dependencyManager
} as DeepPartial<Options>
});
return OutputModel.toOutputModel({
result: renderedOutput.result,
modelName: renderedOutput.renderedName,
dependencies: renderedOutput.dependencies,
model: constrainedModel,
inputModel
});
}
)
);
}

/**
Expand Down
25 changes: 13 additions & 12 deletions test/TestUtils/TestGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
AbstractGenerator,
InputMetaModel,
IndentationTypes,
RenderOutput,
ConstrainedMetaModel,
MetaModel,
ConstrainedAnyModel,
Preset
Preset,
AbstractGeneratorRenderCompleteModelArgs,
AbstractGeneratorRenderArgs
} from '../../src';
import { AbstractDependencyManager } from '../../src/generators/AbstractDependencyManager';

Expand All @@ -23,37 +24,37 @@ export class TestGenerator extends AbstractGenerator<any, any> {
}

public constrainToMetaModel(model: MetaModel): ConstrainedMetaModel {
return new ConstrainedAnyModel(model.name, undefined, '');
return new ConstrainedAnyModel(model.name, undefined, {}, '');
}

public splitMetaModel(model: MetaModel): MetaModel[] {
return [model];
}
public render(
model: MetaModel,
inputModel: InputMetaModel
): Promise<RenderOutput> {

public render(args: AbstractGeneratorRenderArgs<any>): Promise<RenderOutput> {
return Promise.resolve(
RenderOutput.toRenderOutput({
result: model.name || 'rendered content',
result: args.constrainedModel.name || 'rendered content',
renderedName: 'TestName'
})
);
}

public renderCompleteModel(
model: MetaModel,
inputModel: InputMetaModel,
options: any
args: AbstractGeneratorRenderCompleteModelArgs<any, any>
): Promise<RenderOutput> {
return Promise.resolve(
RenderOutput.toRenderOutput({
result: model.name || 'rendered complete content',
result: args.constrainedModel.name || 'rendered complete content',
renderedName: 'TestName'
})
);
}

public testGetPresets(string: string): Array<[Preset, unknown]> {
return this.getPresets(string);
}

public getDependencyManager(options: any): AbstractDependencyManager {
return new AbstractDependencyManager();
}
Expand Down
25 changes: 16 additions & 9 deletions test/generators/AbstractGenerator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { InputMetaModel, CommonModel, AnyModel } from '../../src/models';
import {
InputMetaModel,
AnyModel,
ConstrainedMetaModel
} from '../../src/models';
import { TestGenerator } from '../TestUtils/TestGenerator';

describe('AbstractGenerator', () => {
let generator: TestGenerator;
beforeEach(() => {
Expand All @@ -8,7 +13,7 @@ describe('AbstractGenerator', () => {

test('generate() should return OutputModels', async () => {
const cim = new InputMetaModel();
const model = new AnyModel('test', undefined);
const model = new AnyModel('test', undefined, {});
cim.models[model.name] = model;
const outputModels = await generator.generate(cim);

Expand All @@ -18,7 +23,7 @@ describe('AbstractGenerator', () => {

test('generateCompleteModels() should return OutputModels', async () => {
const cim = new InputMetaModel();
const model = new AnyModel('test', undefined);
const model = new AnyModel('test', undefined, {});
cim.models[model.name] = model;
const outputModels = await generator.generateCompleteModels(cim, {});

Expand All @@ -28,7 +33,7 @@ describe('AbstractGenerator', () => {

test('generate() should process InputMetaModel instance', async () => {
const cim = new InputMetaModel();
const model = new AnyModel('test', undefined);
const model = new AnyModel('test', undefined, {});
cim.models[model.name] = model;
const outputModels = await generator.generate(cim);
expect(outputModels[0].result).toEqual('test');
Expand All @@ -37,7 +42,7 @@ describe('AbstractGenerator', () => {

test('generateCompleteModels() should process InputMetaModel instance', async () => {
const cim = new InputMetaModel();
const model = new AnyModel('test', undefined);
const model = new AnyModel('test', undefined, {});
cim.models[model.name] = model;
const outputModels = await generator.generateCompleteModels(cim, {});

Expand All @@ -64,10 +69,12 @@ describe('AbstractGenerator', () => {
const doc: any = { type: 'string', $id: 'SomeModel' };
const commonInputModel = await generator.process(doc);
const keys = Object.keys(commonInputModel.models);
const renderedContent = await generator.render(
commonInputModel.models[keys[0]],
commonInputModel
);
const renderedContent = await generator.render({
constrainedModel: commonInputModel.models[
keys[0]
] as ConstrainedMetaModel,
inputModel: commonInputModel
});

expect(renderedContent.result).toEqual('SomeModel');
expect(renderedContent.renderedName).toEqual('TestName');
Expand Down
2 changes: 1 addition & 1 deletion test/generators/java/JavaGenerator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('JavaGenerator', () => {
const models = await generator.generate(doc);
expect(models).toHaveLength(4);
expect(models.map((model) => model.result)).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[3].dependencies).toEqual(expectedDependencies);
});

test('should work custom preset for `class` type', async () => {
Expand Down
52 changes: 26 additions & 26 deletions test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,17 @@ public interface Pet {

exports[`JavaGenerator oneOf/discriminator with jackson preset should create an interface for child models 1`] = `
Array [
"@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, property=\\"vehicleType\\", visible=true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Car.class, name = \\"Car\\"),
@JsonSubTypes.Type(value = Truck.class, name = \\"Truck\\")
})
/**
* Vehicle represents a union of types: Car, Truck
*/
public interface Vehicle {
VehicleType getVehicleType();
}",
"public class Cargo {
@JsonProperty(\\"vehicle\\")
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down Expand Up @@ -690,17 +701,6 @@ Array [
}
return o.toString().replace(\\"\\\\n\\", \\"\\\\n \\");
}
}",
"@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, property=\\"vehicleType\\", visible=true)
@JsonSubTypes({
@JsonSubTypes.Type(value = Car.class, name = \\"Car\\"),
@JsonSubTypes.Type(value = Truck.class, name = \\"Truck\\")
})
/**
* Vehicle represents a union of types: Car, Truck
*/
public interface Vehicle {
VehicleType getVehicleType();
}",
"public class Car implements Vehicle {
@NotNull
Expand Down Expand Up @@ -849,6 +849,9 @@ exports[`JavaGenerator should not render reserved keyword 1`] = `

exports[`JavaGenerator should render \`class\` type 1`] = `
Array [
"",
"",
"",
"public class Address {
private String streetName;
private String city;
Expand Down Expand Up @@ -883,9 +886,6 @@ Array [
public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
}",
"",
"",
"",
]
`;

Expand Down Expand Up @@ -1052,6 +1052,18 @@ exports[`JavaGenerator should render enums with translated special characters 1`
exports[`JavaGenerator should render models and their dependencies 1`] = `
Array [
"package test.packageName;
",
"package test.packageName;
",
"package test.packageName;
",
"package test.packageName;
import test.packageName.OtherModel;
import java.util.Map;
public class Address {
Expand Down Expand Up @@ -1094,14 +1106,6 @@ public class Address {
}",
"package test.packageName;
",
"package test.packageName;
",
"package test.packageName;
import java.util.Map;
public class OtherModel {
private String streetName;
Expand All @@ -1113,10 +1117,6 @@ public class OtherModel {
public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
}",
"package test.packageName;
",
]
`;
Expand Down
Loading

0 comments on commit 68d70fe

Please sign in to comment.