typeorm: PrimaryGeneratedColumn does not have `transformer` option

Issue type:

[ ] question [ ] bug report [x] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ ] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [x] postgres [ ] cockroachdb [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

TypeORM version:

[x] latest [ ] @next [ ] 0.x.x (or put your version here)

Steps to reproduce or a small repository showing the problem:

This hack is great for converting stringified numbers to actual numbers:

https://github.com/typeorm/typeorm/issues/873#issuecomment-424643086

But it cannot be applied to the PrimaryGeneratedColumn column type, because it does not have a transformer option.

Thanks!

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 8
  • Comments: 16 (2 by maintainers)

Most upvoted comments

Here’s a way to do it !

I wasted so much time on this before figuring this out

const hashidTransformer = {
    from: (dbValue) => hashids.encode(dbValue),
    to: (entityValue) => hashids.decode(entityValue)[0],
};

@Generated()
@PrimaryColumn({
     type: 'bigint',
     transformer: hashidTransformer,
})
id: number;

Actually, this was related to converting stringified bigint to a number type. But I think this is a deeper problem with bigints that cannot be handled in JS. I was just trying to do that via the standard TypeORM API. But I don’t think this is an issue.


But an overall issue still is relevant. I know several use cases where the PrimaryGeneratedColumn type needs to be converted back and forth.

For example, using Nano ID, which is generated from an INT for the user facing stuff, but then deflating it back to an INT.

Spent a little bit up time trying to get transformers working for PrimaryGeneratedColumn here https://github.com/typeorm/typeorm/compare/master...salolivares:primary-generated-column-transformer. All it took was updating the types.

I got it working but it definitely needs more polishing. For example, entityValue is undefined so I need to account for that in the to: function. I only tested out BigInt since that was my immediate interest so I’m missing many more potential cases.

In my case we are using Entity ID classes in code. Instance of that class wraps primitive value. I need a possibility to wrap generated ID to that instance or take it out from it when storing.

export class EntityIdTransformer<T extends EntityId> implements ValueTransformer {
  private readonly entityClass: { new(value: any): T }

  public constructor(c: { new(value: any): T }) {
    this.entityClass = c
  }

  public to(entityIdOrFindOperator: T | FindOperator<T[]> | undefined): any {
    if (entityIdOrFindOperator instanceof EntityId) {
      return entityIdOrFindOperator.toPrimitive()
    }

    if (entityIdOrFindOperator instanceof FindOperator && Array.isArray(entityIdOrFindOperator.value)) {
      return new FindOperator(
        entityIdOrFindOperator["_type"],
        entityIdOrFindOperator.value.map(entityId => entityId.toPrimitive()),
        entityIdOrFindOperator["_useParameter"],
        entityIdOrFindOperator["_multipleParameters"]
      )
    }

    return entityIdOrFindOperator
  }

  public from(value: any | undefined): T {
    return value && new this.entityClass(value)
  }
}

(There is also a hack for FindOperator in that implementation)