Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: extends discriminator lookup #857

Open
getlarge opened this issue Aug 5, 2021 · 2 comments · May be fixed by #858
Open

feature: extends discriminator lookup #857

getlarge opened this issue Aug 5, 2021 · 2 comments · May be fixed by #858
Labels
flag: needs discussion Issues which needs discussion before implementation. type: feature Issues related to new features.

Comments

@getlarge
Copy link

getlarge commented Aug 5, 2021

Description

I truly appreciate the possibility to have pseudo dynamic class in my models.
Unfortunately, it's not always possible to add a new specific property to make the lookup working and moreover quite often the discriminator can already be found in the parent object.

export class SignTransaction {
  @Type(() => Identity)
  @ValidateNested()
  identity: Identity;

  @Type(() => LedgerTransaction, {
    discriminator: {
      property: ['identity', 'coinType'],
      parentProperty: true,
      subTypes: [
        { value: BigChainTransaction, name: 822 },
        { value: EthereumTransaction, name: 60 },
      ],
    },
    keepDiscriminatorProperty: true,
  })
  @ValidateNested()
  transaction: BigChainTransaction | EthereumTransaction;
}

Proposed solution

  • Allow to lookup discriminator in parent value
  • Allow search through nested properties
  • Allow subTypes.name to be string or number

Relates to :

@getlarge getlarge added flag: needs discussion Issues which needs discussion before implementation. type: feature Issues related to new features. labels Aug 5, 2021
@getlarge getlarge linked a pull request Aug 5, 2021 that will close this issue
7 tasks
@jonasof
Copy link

jonasof commented Sep 8, 2022

Tip: While that solutions are not implemented I'm using the generic @Transform decorator to convert to the specific classes. Example with top-level param:

export abstract class Photo {
  id: number;
  filename: string;
}

export class Landscape extends Photo {
  panorama: boolean;
}

export class Portrait extends Photo {
  person: Person;
}

export class UnderWater extends Photo {
  depth: number;
}

enum TopPhotoType {
  'landscape' = 'landscape',
  'portrait' = 'portrait',
  'underwater' = 'underwater'
}

const topPhotoTypeMap:  { [key in TopPhotoType]: new () => Photo } = {
  'landscape': Landscape,
  'portrait': Portrait,
  'underwater': UnderWater
}

export class Album {
  id: number;
  name: string;

  topPhotoType: TopPhotoType;

  @Transform(
    ({ value, obj }) => {
      const specificClass = topPhotoTypeMap[obj.topPhotoType];

      return plainToInstance(specificClass, value);
    },
    {
      toClassOnly: true
    }
  )
  @Type(() => Object)
  topPhoto: Landscape | Portrait | UnderWater;
}

let album = plainToClass(Album, albumJson);

@getlarge
Copy link
Author

getlarge commented Jan 2, 2023

To make @jonasof solution even more useful i suggest to also resolve the dynamic type so that @ValidateNested can also be used.
To continue with his example:

export abstract class Photo {
  id: number;
  filename: string;
}

export class Landscape extends Photo {
  panorama: boolean;
}

export class Portrait extends Photo {
  person: Person;
}

export class UnderWater extends Photo {
  depth: number;
}

enum TopPhotoType {
  'landscape' = 'landscape',
  'portrait' = 'portrait',
  'underwater' = 'underwater'
}

const topPhotoTypeMap:  { [key in TopPhotoType]: new () => Photo } = {
  'landscape': Landscape,
  'portrait': Portrait,
  'underwater': UnderWater
}

export class Album {
  id: number;
  name: string;

  topPhotoType: TopPhotoType;

  @Transform(
    ({ value, obj }) => {
      const specificClass = topPhotoTypeMap[obj.topPhotoType];
      return plainToInstance(specificClass, value);
    },
    {
      toClassOnly: true
    }
  )
  @Type(({ object }) => topPhotoTypeMap[object?.topPhotoType])
  @ValidateNested()
  topPhoto: Landscape | Portrait | UnderWater;
}

let album = plainToClass(Album, albumJson);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flag: needs discussion Issues which needs discussion before implementation. type: feature Issues related to new features.
Development

Successfully merging a pull request may close this issue.

2 participants