Skip to content

Commit

Permalink
fix(core): Look up the proper assembler with inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-martin committed Oct 16, 2020
1 parent 13fdd2b commit 8bd22c5
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 14 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/assemblers/assembler.deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ export function AssemblerDeserializer<T>(deserializer: AssemblerDeserializer<T>)
}

export function getAssemblerDeserializer<DTO>(DTOClass: Class<DTO>): MetaValue<AssemblerDeserializer<DTO>> {
return reflector.get(DTOClass);
return reflector.get(DTOClass, true);
}
28 changes: 18 additions & 10 deletions packages/core/src/assemblers/assembler.factory.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import { Class, DeepPartial } from '../common';
import { Assembler, getAssembler } from './assembler';
import { Assembler, getAssemblers } from './assembler';
import { DefaultAssembler } from './default.assembler';

/**
* Assembler Service used by query services to look up Assemblers.
*/
export class AssemblerFactory {
static getAssembler<From, To, C = DeepPartial<From>, CE = DeepPartial<To>, U = C, UE = CE>(
FromClass: Class<From>,
ToClass: Class<To>,
): Assembler<From, To, C, CE, U, UE> {
const AssemblerClass = getAssembler<From, To, C, CE, U, UE>(FromClass, ToClass);
if (AssemblerClass) {
return new AssemblerClass();
static getAssembler<DTO, Entity, C = DeepPartial<DTO>, CE = DeepPartial<Entity>, U = C, UE = CE>(
DTOClass: Class<DTO>,
EntityClass: Class<Entity>,
): Assembler<DTO, Entity, C, CE, U, UE> {
const AssemblerClasses = getAssemblers(DTOClass);
if (AssemblerClasses) {
const AssemblerClass = AssemblerClasses.get(EntityClass);
if (AssemblerClass) {
return new AssemblerClass() as Assembler<DTO, Entity, C, CE, U, UE>;
}
const keys = [...AssemblerClasses.keys()];
const keysWithParent = keys.filter((k) => k.prototype instanceof EntityClass);
if (keysWithParent.length === 1) {
return this.getAssembler(DTOClass, keysWithParent[0] as Class<Entity>);
}
}
const defaultAssember = new DefaultAssembler(FromClass, ToClass);
const defaultAssembler = new DefaultAssembler(DTOClass, EntityClass);
// if its a default just assume the types can be converted for all types
return (defaultAssember as unknown) as Assembler<From, To, C, CE, U, UE>;
return (defaultAssembler as unknown) as Assembler<DTO, Entity, C, CE, U, UE>;
}
}
2 changes: 1 addition & 1 deletion packages/core/src/assemblers/assembler.serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ export function AssemblerSerializer<T>(serializer: AssemblerSerializer<T>) {
}

export function getAssemblerSerializer<DTO>(DTOClass: Class<DTO>): MetaValue<AssemblerSerializer<DTO>> {
return reflector.get(DTOClass);
return reflector.get(DTOClass, true);
}
6 changes: 6 additions & 0 deletions packages/core/src/assemblers/assembler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ export function getAssembler<DTO, Entity, C, CE, U, UE>(
return reflector.get(DTOClass, EntityClass);
}

export function getAssemblers<DTO>(
DTOClass: Class<DTO>,
): MetaValue<Map<Class<unknown>, Class<Assembler<DTO, unknown, unknown, unknown, unknown, unknown>>>> {
return reflector.get(DTOClass);
}

export function getAssemblerClasses<DTO, Entity, C, CE, U, UE>(
AssemblerClass: Class<Assembler<DTO, Entity, C, CE, U, UE>>,
): MetaValue<AssemblerClasses<DTO, Entity>> {
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/assemblers/class-transformer.assembler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export abstract class ClassTransformerAssembler<DTO, Entity> extends AbstractAss
if (serializer) {
return serializer(entityOrDto);
}
} else if ('constructor' in entityOrDto) {
// eslint-disable-next-line @typescript-eslint/ban-types
const serializer = getAssemblerSerializer((entityOrDto as object).constructor as Class<unknown>);
if (serializer) {
return serializer(entityOrDto);
}
}
// eslint-disable-next-line @typescript-eslint/ban-types
return (entityOrDto as unknown) as object;
Expand Down
18 changes: 16 additions & 2 deletions packages/core/src/common/reflect.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,22 @@ export class MapReflector<K = string> extends Reflector {
this.defineMetadata(metadata, DTOClass);
}

get<DTO, Data>(DTOClass: Class<DTO>, key: K, includeParents = false): MetaValue<Data> {
return this.getMetadata<Map<K, Data>>(DTOClass, includeParents)?.get(key);
get<DTO, Data>(DTOClass: Class<DTO>, includeParents?: boolean): MetaValue<Map<K, Data>>;
get<DTO, Data>(DTOClass: Class<DTO>, key: K, includeParents?: boolean): MetaValue<Data>;
get<DTO, Data>(
DTOClass: Class<DTO>,
key: K | boolean | undefined,
includeParents?: boolean,
): MetaValue<Data | Map<K, Data>> {
if (typeof key === 'boolean' || typeof key === 'undefined') {
return this.getMetadata<Map<K, Data>>(DTOClass, includeParents ?? false);
}
return this.getMetadata<Map<K, Data>>(DTOClass, includeParents ?? false)?.get(key);
}

getValues<DTO, Data>(DTOClass: Class<DTO>, includeParents = false): MetaValue<Data[]> {
const values = this.getMetadata<Map<K, Data>>(DTOClass, includeParents)?.values();
return values ? [...values] : undefined;
}

has<DTO>(DTOClass: Class<DTO>, key: K): boolean {
Expand Down

0 comments on commit 8bd22c5

Please sign in to comment.