tannerntannern / ts-mixer

A small TypeScript library that provides tolerable Mixin functionality.
MIT License
384 stars 27 forks source link

Does not work with decorators of `nestjs-seeder` #64

Closed MoWafy001 closed 1 year ago

MoWafy001 commented 1 year ago

Decorators of nestjs-seeder don't run when inherited.

import { Factory } from 'nestjs-seeder';
import { decorate } from 'ts-mixer';
import { Column } from 'typeorm';
import { hashPassword } from 'path-to-method';

export class HasPassword {
  @decorate(Column({ type: 'varchar' }))
  @decorate(Factory((_f) => hashPassword('password')))
  password: string;
}
export class User extends Mixin(HasPassword) {}
const user: Array<Partial<User>> = DataFactory.createForClass(User).generate(1)
// doesn't have a `password` property

In this example, the Column decorator of typeorm does work but the Factory decorator of nestjs-seeder doesn't work

tannerntannern commented 1 year ago

There are number of reasons this might not be working. Before I spend time on this, please help me by sharing the results of these two tests:

  1. Do you get the desired behavior if you make the following replacement:
    -export class User extends Mixin(HasPassword) {}
    +export const User = Mixin(HasPassword);
  2. Separately, does the issue persist if you make the following replacement:
    -export class User extends Mixin(HasPassword) {}
    +export class User extends HasPassword {}

If both of these tests answer "yes", then this would suggest to me that there's an issue with nestjs-seeder not respecting inheritance, which is completely out of ts-mixer's control. ts-mixer can track which decorators are applied to the classes you use in a mixin (HasPassword in this case) and reapply them to the mixed class. However, that's not User in this case, but rather Mixin(HasPassword). The User (class as written in your example) is outside the control of ts-mixer. It merely inherits from a ts-mixer-controlled class.

If one or both of these tests result in "no", then I'd be happy to investigate further, but that's my theory at the moment. Please let me know what you find.

Thanks!

MoWafy001 commented 1 year ago

OK, I run 3 tests.

HasPassword Class

export class HasPassword {
  @decorate(Column({ type: 'varchar' }))
  @decorate(Factory((_f) => hashPassword('password')))
  password: string;
}

1. (OG) class extending Mixin(HasPassword) failed

class Test1 extends Mixin(HasPassword){}
const mockTest1 = DataFactory.createForClass(Test1).generate(1).shift();
console.log("mockTest1", mockTest1);
// output: mockTest1 {}

2. class extending HasPassword failed

class Test2 extends HasPassword{}
const mockTest2 = DataFactory.createForClass(Test2).generate(1).shift();
console.log("mockTest2", mockTest2);
// output: mockTest2 {}

3. const = Mixin(HasPassword) succeeded

const Test3 = Mixin(HasPassword);
const mockTest3 = DataFactory.createForClass(Test3).generate(1).shift();
console.log("mockTest3", mockTest3);
// mockTest3 {
//   password: 'hashed-password'
// }
tannerntannern commented 1 year ago

Thanks @MoWafy001, this does indeed confirm my theory. Number 2 in particular shows why the OG example doesn't work: nestjs-seeder doesn't respect inheritance whether ts-mixer is involved or not, so that's an issue you'd have to take up with them.