Skip to content

Foreign key property transformation processes undefined value upon save #9565

@akwodkiewicz

Description

@akwodkiewicz

Issue Description

Expected Behavior

Newly created entity containing a foreign key id property (of a custom object type) is properly transformed and then inserted to the database.

Actual Behavior

Foreign key is ignored on some stage of the insert, resulting in an error during transformation of the property/foreign key value:

TypeError: Cannot read properties of undefined (reading 'value')
    at Object.to (/home/aw/project-3/typeorm-example/src/entities/post.entity.ts:31:19)
    at Function.transformTo (/home/aw/project-3/typeorm-example/src/util/ApplyValueTransformers.ts:28:28)
    at SqliteDriver.preparePersistentValue (/home/aw/project-3/typeorm-example/src/driver/sqlite-abstract/AbstractSqliteDriver.ts:319:44)
    at /home/aw/project-3/typeorm-example/src/query-builder/InsertQueryBuilder.ts:717:56
    at Array.forEach (<anonymous>)
    at /home/aw/project-3/typeorm-example/src/query-builder/InsertQueryBuilder.ts:688:25
    at Array.forEach (<anonymous>)
    at InsertQueryBuilder.createValuesExpression (/home/aw/project-3/typeorm-example/src/query-builder/InsertQueryBuilder.ts:687:23)
    at InsertQueryBuilder.createInsertExpression (/home/aw/project-3/typeorm-example/src/query-builder/InsertQueryBuilder.ts:406:39)
    at InsertQueryBuilder.getQuery (/home/aw/project-3/typeorm-example/src/query-builder/InsertQueryBuilder.ts:39:21)

Steps to Reproduce

I prepared a dedicated repository for this issue:

https://github.com/akwodkiewicz/typeorm-bug-report

README should explain how to use the repository to reproduce the error.

Nonetheless, below I'm pasting the trimmed version of the files used in this repository, so that this bug report does not need to rely on my repository in the future.

Id classes

/// src/entities/user-id.ts
export class UserId {
  constructor(public readonly value: string) {}
}
/// src/entities/post-id.ts
export class PostId {
  constructor(public readonly value: string) {}
}

Entities

/// src/entities/user.entity.ts
import { Column, Entity, PrimaryColumn } from "typeorm";
import { UserId } from "./user-id";

@Entity()
export class User {
  @PrimaryColumn({
    type: "text",
    transformer: {
      from(value: string) {
        return new UserId(value);
      },
      to(id: UserId) {
        return id.value;
      },
    },
  })
  id!: UserId;

  @Column()
  name!: string;
}
/// src/entities/post.entity.ts
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { PostId } from "./post-id";
import { UserId } from "./user-id";
import { User } from "./user.entity";

@Entity()
export class Post {
  @PrimaryColumn({
    type: "text",
    transformer: {
      from(value: string) {
        return new PostId(value);
      },
      to(id: PostId) {
        return id.value;
      },
    },
  })
  id!: PostId;

  @ManyToOne(() => User)
  author?: User;

  @Column({
    type: "text",
    transformer: {
      from(value: string) {
        return new UserId(value);
      },
      to(id: UserId) {
        return id.value;
      },
    },
  })
  authorId!: UserId;
}

Faulty save

/// src/main.ts
import { dataSource } from "./data-source";
import { PostId } from "./entities/post-id";
import { Post } from "./entities/post.entity";
import { UserId } from "./entities/user-id";
import { User } from "./entities/user.entity";

const USER_ID = new UserId("abcd-1234");
const POST_ID = new PostId("first");

async function insertData() {
  const user = dataSource.manager.create(User, {
    id: USER_ID,
    name: "Tom",
  });
  await dataSource.manager.save(user);

  const post = dataSource.manager.create(Post, {
    authorId: USER_ID,
    id: POST_ID,
  });
  await dataSource.manager.save(post); // <-- this fails
}


async function main() {
  await dataSource.initialize();
  await insertData();
}

main().catch((e) => console.error(e));

My Environment

Dependency Version
Operating System WSL (Ubuntu on Windows 11)
Node.js version 18.12.0
Typescript version 4.9.3
TypeORM version 0.3.10

Additional Context

The error does not happen when the foreign keys and entity ids are typed as primitive strings.

I'm using sqlite driver, did not try to test it on other drivers.

Also, if you create the Post by specifying author: user instead of authorId: USER_ID then the insert is successful.

Relevant Database Driver(s)

DB Type Reproducible
aurora-mysql no
aurora-postgres no
better-sqlite3 no
cockroachdb no
cordova no
expo no
mongodb no
mysql no
nativescript no
oracle no
postgres no
react-native no
sap no
spanner no
sqlite yes
sqlite-abstract no
sqljs no
sqlserver no

Are you willing to resolve this issue by submitting a Pull Request?

  • ✖️ Yes, I have the time, and I know how to start.
  • ✅ Yes, I have the time, but I don't know how to start. I would need guidance.
  • ✖️ No, I don’t have the time, but I can support (using donations) development.
  • ✖️ No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions