Skip to content

Inserting entities with complex objects with circular references results in stack overflowΒ #5096

@ferk6a

Description

@ferk6a

Issue type:
[x] bug report

Database system/driver:
[x] sqlite

TypeORM version:

[x] latest
[x] 0.2.20

Steps to reproduce or a small repository showing the problem:

import {
  Instant
} from '@js-joda/core';

class InstantTransformer implements ValueTransformer {
  to(entityValue: Instant | null): number | null {
    if (entityValue === null) { return null; }
    return entityValue.toEpochMilli()
  }

  from(databaseValue: number | null): Instant | null {
    if (databaseValue === null) { return null; }
    return Instant.ofEpochMilli(databaseValue)
  }
}

@Entity()
export class Project {
  @PrimaryGeneratedColumn('uuid')
  uuid: string;

  @Column({
    transformer: new InstantTransformer()
  })
  creationInstant: Instant;
}

When attempting to create a Project, something like this:

  const project = new Project();
  project.creationInstant = Instant.parse(creationInstant);
  await connection.manager.save(project);

We end up with:

RangeError: Maximum call stack size exceeded
    at Array.shift (<anonymous>)
    at Function.OrmUtils.mergeDeep (node_modules/typeorm/util/OrmUtils.js:70:30)
    at Function.OrmUtils.mergeDeep (node_modules/typeorm/util/OrmUtils.js:86:26)
...
    at Function.OrmUtils.mergeDeep (node_modules/typeorm/util/OrmUtils.js:63:19)
    at node_modules/typeorm/persistence/Subject.js:169:33
    at Array.reduce (<anonymous>)
    at Subject.createValueSetAndPopChangeMap (node_modules/typeorm/persistence/Subject.js:125:41)
    at node_modules/typeorm/persistence/SubjectExecutor.js:237:85
    at Array.forEach (<anonymous>)
    at SubjectExecutor.<anonymous> (node_modules/typeorm/persistence/SubjectExecutor.js:225:58)
    at step (node_modules/tslib/tslib.js:136:27)
    at Object.next (node_modules/tslib/tslib.js:117:57)
    at node_modules/tslib/tslib.js:110:75

The best solution should probably change this mess:

if (this.isObject(source[propertyKey])
&& !(source[propertyKey] instanceof Map)
&& !(source[propertyKey] instanceof Set)
&& !(source[propertyKey] instanceof Date)
&& !(source[propertyKey] instanceof Buffer)) {

Into a solution which uses getPrototypeOf, constructor, and etc to see if an object is a plain object like lodash does.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions