Skip to content

Commit a4ad113

Browse files
committed
add discriminator support
1 parent b5d6b50 commit a4ad113

16 files changed

+426
-92
lines changed

.snapshot/all/models.ts

+112-1
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,35 @@ import { Guid } from './Guid';
22
import { toDateIn, toDateOut } from './date-converters';
33
import type * as $types from './types';
44

5+
export enum CategoryUnionTypes {
6+
CategoryElectronicsDto = '1',
7+
CategoryMotorsDto = '2'
8+
}
9+
510
export enum ProductStatus {
611
InStock = 0,
712
OutOfStock = -1,
813
UnderTheOrder = 1
914
}
1015

16+
interface ICategoryElectronicsDtoBaseInterface {
17+
syntheticTest: $types.TypeOrUndefinedNullable<number>;
18+
}
19+
20+
interface ICategoryMotorsDtoBaseInterface {
21+
volume: $types.TypeOrUndefinedNullable<number>;
22+
}
23+
1124
export interface ICategory {
1225
name: $types.TypeOrUndefinedNullable<string>;
26+
type: $types.TypeOrUndefined<string>;
1327
}
1428

29+
export type ICategoryElectronicsDto = ICategoryElectronicsDtoBaseInterface & ICategory;
30+
export type ICategoryMotorsDto = ICategoryMotorsDtoBaseInterface & ICategory;
31+
1532
export interface IProduct {
33+
categories: $types.TypeOrUndefinedNullable<ICategory[]>;
1634
category: $types.TypeOrUndefinedNullable<ICategory>;
1735
colors: $types.TypeOrUndefined<string[]>;
1836
expireDate: $types.TypeOrUndefined<string>;
@@ -27,6 +45,47 @@ export interface IProductIdentityDTO {
2745
id: $types.TypeOrUndefined<string>;
2846
}
2947

48+
export type CategoryUnion = Category | CategoryElectronicsDto | CategoryMotorsDto;
49+
export type ICategoryUnion = ICategory | ICategoryElectronicsDto | ICategoryMotorsDto;
50+
51+
export class CategoryUnionClass {
52+
public static fromDTO(dto: ICategoryUnion): CategoryUnion {
53+
if (this.isCategoryElectronicsDto(dto)) {
54+
return CategoryElectronicsDto.fromDTO(dto);
55+
}
56+
if (this.isCategoryMotorsDto(dto)) {
57+
return CategoryMotorsDto.fromDTO(dto);
58+
}
59+
return Category.fromDTO(dto);
60+
}
61+
62+
public static toDTO(model: CategoryUnion): ICategoryUnion {
63+
if (this.isICategoryElectronicsDto(model)) {
64+
return CategoryElectronicsDto.toDTO(model);
65+
}
66+
if (this.isICategoryMotorsDto(model)) {
67+
return CategoryMotorsDto.toDTO(model);
68+
}
69+
return Category.toDTO(model);
70+
}
71+
72+
private static isCategoryElectronicsDto(dto: ICategoryUnion): dto is ICategoryElectronicsDto {
73+
return dto.type === CategoryUnionTypes.CategoryElectronicsDto;
74+
}
75+
76+
private static isCategoryMotorsDto(dto: ICategoryUnion): dto is ICategoryMotorsDto {
77+
return dto.type === CategoryUnionTypes.CategoryMotorsDto;
78+
}
79+
80+
private static isICategoryElectronicsDto(dto: CategoryUnion): dto is CategoryElectronicsDto {
81+
return dto.type === CategoryUnionTypes.CategoryElectronicsDto;
82+
}
83+
84+
private static isICategoryMotorsDto(dto: CategoryUnion): dto is CategoryMotorsDto {
85+
return dto.type === CategoryUnionTypes.CategoryMotorsDto;
86+
}
87+
}
88+
3089
export class ProductIdentityDTO {
3190
public id: Guid;
3291
private __productIdentityDTO!: string;
@@ -42,23 +101,73 @@ export class ProductIdentityDTO {
42101

43102
export class Category {
44103
public name: $types.TypeOrUndefinedNullable<string> = undefined;
104+
public type: $types.TypeOrUndefined<string> = undefined;
45105
private __category!: string;
46106

47107
public static toDTO(model: Partial<Category>): ICategory {
48108
return {
49109
name: model.name,
110+
type: model.type,
50111
};
51112
}
52113

53114
public static fromDTO(dto: ICategory): Category {
54115
const model = new Category();
55116
model.name = dto.name;
117+
model.type = dto.type;
118+
return model;
119+
}
120+
}
121+
122+
export class CategoryElectronicsDto {
123+
public name: $types.TypeOrUndefinedNullable<string> = undefined;
124+
public type: $types.TypeOrUndefined<string> = undefined;
125+
public syntheticTest: $types.TypeOrUndefinedNullable<number> = undefined;
126+
private __categoryElectronicsDto!: string;
127+
128+
public static toDTO(model: Partial<CategoryElectronicsDto>): ICategoryElectronicsDto {
129+
return {
130+
syntheticTest: model.syntheticTest,
131+
name: model.name,
132+
type: model.type,
133+
};
134+
}
135+
136+
public static fromDTO(dto: ICategoryElectronicsDto): CategoryElectronicsDto {
137+
const model = new CategoryElectronicsDto();
138+
model.syntheticTest = dto.syntheticTest;
139+
model.name = dto.name;
140+
model.type = dto.type;
141+
return model;
142+
}
143+
}
144+
145+
export class CategoryMotorsDto {
146+
public name: $types.TypeOrUndefinedNullable<string> = undefined;
147+
public type: $types.TypeOrUndefined<string> = undefined;
148+
public volume: $types.TypeOrUndefinedNullable<number> = undefined;
149+
private __categoryMotorsDto!: string;
150+
151+
public static toDTO(model: Partial<CategoryMotorsDto>): ICategoryMotorsDto {
152+
return {
153+
volume: model.volume,
154+
name: model.name,
155+
type: model.type,
156+
};
157+
}
158+
159+
public static fromDTO(dto: ICategoryMotorsDto): CategoryMotorsDto {
160+
const model = new CategoryMotorsDto();
161+
model.volume = dto.volume;
162+
model.name = dto.name;
163+
model.type = dto.type;
56164
return model;
57165
}
58166
}
59167

60168
export class Product {
61-
public category: $types.TypeOrUndefinedNullable<Category> = undefined;
169+
public categories: CategoryUnionClass[] = [];
170+
public category: $types.TypeOrUndefinedNullable<CategoryUnionClass> = undefined;
62171
public colors: string[] = [];
63172
public expireDate: $types.TypeOrUndefined<Date> = undefined;
64173
public externalId: $types.TypeOrUndefinedNullable<Guid> = undefined;
@@ -70,6 +179,7 @@ export class Product {
70179

71180
public static toDTO(model: Partial<Product>): IProduct {
72181
return {
182+
categories: model.categories ? model.categories.map(x => Category.toDTO(x)) : undefined,
73183
category: model.category ? Category.toDTO(model.category) : undefined,
74184
colors: model.colors,
75185
expireDate: toDateOut(model.expireDate),
@@ -83,6 +193,7 @@ export class Product {
83193

84194
public static fromDTO(dto: IProduct): Product {
85195
const model = new Product();
196+
model.categories = dto.categories ? dto.categories.map(x => Category.fromDTO(x)) : [];
86197
model.category = dto.category ? Category.fromDTO(dto.category) : undefined;
87198
model.colors = dto.colors ? dto.colors : [];
88199
model.expireDate = toDateIn(dto.expireDate);

package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@luxbss/gengen",
3-
"version": "1.2.6",
3+
"version": "1.2.7",
44
"description": "Tool for generating models and Angular services based on OpenAPIs and Swagger's JSON",
55
"bin": {
66
"gengen": "./bin/index.js"

src/generators/ModelsGenerator.ts

+76-5
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import {
1212
} from 'ts-morph';
1313
import { IEnumModel } from '../models/EnumModel';
1414
import { IIdentityModel } from '../models/IdentityModel';
15-
import { IInterfaceModel } from '../models/InterfaceModel';
15+
import { IInterfaceModel, IInterfaceUnionModel } from '../models/InterfaceModel';
1616
import { IModelsContainer } from '../models/ModelsContainer';
1717
import { IObjectModel, IObjectPropertyModel } from '../models/ObjectModel';
1818
import { PropertyKind } from '../models/kinds/PropertyKind';
1919
import { IOptions } from '../options';
2020
import { PathBuilder } from '../services/PathBuilder';
21-
import { lowerFirst } from '../utils';
21+
import { getInterfaceName, lowerFirst } from '../utils';
2222
import { InterfacesGenerator } from './models-generator/InterfacesGenerator';
2323
import { TypeSerializer } from './utils/TypeSerializer';
2424
import { ARRAY_STRING, NULL_STRING, TYPES_NAMESPACE, UNDEFINED_STRING } from './utils/consts';
@@ -37,6 +37,8 @@ export class ModelsGenerator {
3737
...this.getImports(),
3838
...this.getEnums(models.enums),
3939
...this.interfaceGenerator.getCodeStructure(models.interfaces),
40+
...this.interfaceGenerator.getCodeUnionsStructure(models.unionInterfaces),
41+
...this.getUnionObjects(models.unionInterfaces),
4042
...this.getIdentities(models.identities, models.interfaces),
4143
...this.getObjects(models.objects)
4244
];
@@ -120,6 +122,71 @@ export class ModelsGenerator {
120122
})
121123
);
122124
}
125+
private getUnionObjects(objects: IInterfaceUnionModel[]): ClassDeclarationStructure[] {
126+
return objects.map((z) => ({
127+
kind: StructureKind.Class,
128+
isExported: true,
129+
name: z.name + 'Class',
130+
properties: [],
131+
methods: [
132+
{
133+
scope: Scope.Public,
134+
isStatic: true,
135+
name: FROM_DTO_METHOD,
136+
parameters: [{ name: 'dto', type: getInterfaceName(z.name) }],
137+
returnType: z.name,
138+
statements: (x) => {
139+
z.unionInterfaces.forEach((i) => {
140+
x.writeLine('if (this.is' + i + '(dto)){');
141+
x.writeLine('return ' + i + '.fromDTO(dto);');
142+
x.writeLine('}');
143+
});
144+
145+
x.writeLine('return ' + z.parentInterface + '.fromDTO(dto);');
146+
}
147+
},
148+
149+
{
150+
scope: Scope.Public,
151+
isStatic: true,
152+
name: TO_DTO_METHOD,
153+
parameters: [{ name: 'model', type: z.name }],
154+
returnType: getInterfaceName(z.name),
155+
statements: (x) => {
156+
z.unionInterfaces.forEach((i) => {
157+
x.writeLine('if (this.is' + getInterfaceName(i) + '(model)){');
158+
x.writeLine('return ' + i + '.toDTO(model);');
159+
x.writeLine('}');
160+
});
161+
162+
x.writeLine('return ' + z.parentInterface + '.toDTO(model);');
163+
}
164+
},
165+
166+
...z.unionInterfaces.map((i) => ({
167+
scope: Scope.Private,
168+
isStatic: true,
169+
name: 'is' + i,
170+
parameters: [{ name: 'dto', type: getInterfaceName(z.name) }],
171+
returnType: 'dto is ' + getInterfaceName(i),
172+
statements: (x: CodeBlockWriter) => {
173+
x.writeLine('return dto.type === ' + z.name + 'Types.' + i + ';');
174+
}
175+
})),
176+
177+
...z.unionInterfaces.map((i) => ({
178+
scope: Scope.Private,
179+
isStatic: true,
180+
name: 'is' + getInterfaceName(i),
181+
parameters: [{ name: 'dto', type: z.name }],
182+
returnType: 'dto is ' + i,
183+
statements: (x: CodeBlockWriter) => {
184+
x.writeLine('return dto.type === ' + z.name + 'Types.' + i + ';');
185+
}
186+
}))
187+
]
188+
}));
189+
}
123190

124191
private getObjects(objects: IObjectModel[]): ClassDeclarationStructure[] {
125192
return objects.map((z) => ({
@@ -191,7 +258,7 @@ export class ModelsGenerator {
191258
scope: Scope.Public,
192259
name: objectProperty.name,
193260
type: new TypeSerializer({
194-
type: { name: objectProperty.type },
261+
type: { name: objectProperty.typeAlias ?? objectProperty.type },
195262
isNullable: objectProperty.isNullable,
196263
isCollection: objectProperty.isCollection
197264
}).toString(),
@@ -239,7 +306,9 @@ export class ModelsGenerator {
239306

240307
case PropertyKind.Object:
241308
if (property.isCollection) {
242-
return `${modelProperty} ? ${modelProperty}.map(x => ${property.type}.${TO_DTO_METHOD}(x)) : ${UNDEFINED_STRING}`;
309+
return `${modelProperty} ? ${modelProperty}.map(x => ${
310+
property.dtoTypeAlias ?? property.type
311+
}.${TO_DTO_METHOD}(x)) : ${UNDEFINED_STRING}`;
243312
}
244313

245314
return `${modelProperty} ? ${property.type}.${TO_DTO_METHOD}(${modelProperty}) : ${UNDEFINED_STRING}`;
@@ -279,7 +348,9 @@ export class ModelsGenerator {
279348

280349
case PropertyKind.Object:
281350
if (property.isCollection) {
282-
return `${dtoProperty} ? ${dtoProperty}.map(x => ${property.type}.${FROM_DTO_METHOD}(x)) : ${ARRAY_STRING}`;
351+
return `${dtoProperty} ? ${dtoProperty}.map(x => ${
352+
property.dtoTypeAlias ?? property.type
353+
}.${FROM_DTO_METHOD}(x)) : ${ARRAY_STRING}`;
283354
}
284355

285356
return `${dtoProperty} ? ${property.type}.${FROM_DTO_METHOD}(${dtoProperty}) : ${UNDEFINED_STRING}`;

src/generators/models-generator/InterfacesGenerator.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import {
66
TypeAliasDeclarationStructure
77
} from 'ts-morph';
88

9-
import { IInterfaceModel, IInterfacePropertyModel } from '../../models/InterfaceModel';
9+
import { IInterfaceModel, IInterfacePropertyModel, IInterfaceUnionModel } from '../../models/InterfaceModel';
1010
import { TypeSerializer } from '../utils/TypeSerializer';
11+
import { getInterfaceName } from '../../utils';
1112

1213
export class InterfacesGenerator {
1314
public getCodeStructure(interfaces: IInterfaceModel[]): (InterfaceDeclarationStructure | TypeAliasDeclarationStructure)[] {
@@ -39,6 +40,26 @@ export class InterfacesGenerator {
3940
return [...baseInterfaces, ...types];
4041
}
4142

43+
public getCodeUnionsStructure(interfaces: IInterfaceUnionModel[]): TypeAliasDeclarationStructure[] {
44+
const classUnion: TypeAliasDeclarationStructure[] = interfaces.map((z) => {
45+
return {
46+
kind: StructureKind.TypeAlias,
47+
type: z.parentInterface + '|' + z.unionInterfaces.join(' | '),
48+
name: z.name,
49+
isExported: true
50+
};
51+
});
52+
const interfacesUnion: TypeAliasDeclarationStructure[] = interfaces.map((z) => {
53+
return {
54+
kind: StructureKind.TypeAlias,
55+
type: getInterfaceName(z.parentInterface) + '|' + z.unionInterfaces.map((x) => getInterfaceName(x)).join(' | '),
56+
name: getInterfaceName(z.name),
57+
isExported: true
58+
};
59+
});
60+
return [...classUnion, ...interfacesUnion];
61+
}
62+
4263
protected getInterfaceProperty(model: IInterfacePropertyModel): OptionalKind<PropertySignatureStructure> {
4364
return {
4465
name: model.name,

src/models/EnumModel.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export interface IEnumModel {
22
name: string;
33
isNullable: boolean;
4-
items: { key: string; value: number }[];
4+
items: { key: string; value: number | string }[];
55
}

src/models/InterfaceModel.ts

+6
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ export interface IInterfaceModel {
1010
properties: IInterfacePropertyModel[];
1111
combineInterfaces: string[];
1212
}
13+
14+
export interface IInterfaceUnionModel {
15+
name: string;
16+
parentInterface: string;
17+
unionInterfaces: string[];
18+
}

0 commit comments

Comments
 (0)