diff --git a/src/recast.ts b/src/recast.ts index a0f1b19..0dfe5b6 100644 --- a/src/recast.ts +++ b/src/recast.ts @@ -1,5 +1,5 @@ import { InvalidRequest } from './exceptions'; -import { Callable, integer, Integer } from './interface'; +import { BaseModel, Callable, integer, Integer } from './interface'; type primitive = string | number | boolean | bigint | integer | object; @@ -70,7 +70,7 @@ export const transformValue = ( }); } else { // if type is plain object, we leave it as is - if (Object.is(cls, Object)) { + if (Object.is(cls, Object) || cls.prototype instanceof BaseModel) { return value; } if ( diff --git a/tests/data/sample-model.ts b/tests/data/sample-model.ts index aed0cec..b8680db 100644 --- a/tests/data/sample-model.ts +++ b/tests/data/sample-model.ts @@ -200,6 +200,25 @@ export class DeeperDict extends BaseModel { deepestList?: Optional>; } +export class TagsModel extends BaseModel { + ['constructor']: typeof TagsModel; + + @Expose({ name: 'Tags' }) + @Transform((value, obj) => transformValue(Tag, 'tags', value, obj, [Set]), { + toClassOnly: true, + }) + tags?: Optional>; +} + +class Tag extends BaseModel { + ['constructor']: typeof Tag; + + @Expose({ name: 'Name' }) + name: string; + @Expose({ name: 'Value' }) + value: string; +} + export class SimpleResourceModel extends BaseModel { ['constructor']: typeof SimpleResourceModel; diff --git a/tests/lib/recast.test.ts b/tests/lib/recast.test.ts index 5fca35c..f55b987 100644 --- a/tests/lib/recast.test.ts +++ b/tests/lib/recast.test.ts @@ -3,6 +3,7 @@ import { transformValue, recastPrimitive } from '~/recast'; import { ResourceModel as ComplexResourceModel, SimpleResourceModel, + TagsModel, } from '../data/sample-model'; describe('when recasting objects', () => { @@ -105,15 +106,29 @@ describe('when recasting objects', () => { ); }); + test('recast set type - array with unique items', () => { + const payload = { + Tags: [{ key: 'name', value: 'value' }], + }; + const expected = { + Tags: new Set([{ key: 'name', value: 'value' }]), + }; + const model = TagsModel.deserialize(payload); + const serialized = JSON.parse(JSON.stringify(model)); + expect(serialized).toMatchObject(expected); + expect(TagsModel.deserialize(serialized).serialize()).toMatchObject(expected); + }); + test('recast object invalid sub type', () => { + class InvalidClass {} const k = 'key'; const v = { a: 1, b: 2 }; const recastObject = () => { - transformValue(SimpleResourceModel, k, v, {}); + transformValue(InvalidClass, k, v, {}); }; expect(recastObject).toThrow(exceptions.InvalidRequest); expect(recastObject).toThrow( - `Unsupported type: ${typeof v} [${SimpleResourceModel.name}] for ${k}` + `Unsupported type: ${typeof v} [${InvalidClass.name}] for ${k}` ); });