Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): allow assigning null to embeddable property #1356

Merged
merged 5 commits into from
Jan 28, 2021
Merged

fix(core): allow assigning null to embeddable property #1356

merged 5 commits into from
Jan 28, 2021

Conversation

francisco-sanchez-molina
Copy link
Contributor

@francisco-sanchez-molina francisco-sanchez-molina commented Jan 27, 2021

When you have entity like this:

@Entity()
class Document extends BaseEntity<Document> {
...
  @Embedded({
    entity: () => Summary,
    nullable: true,
  })
  summary!: Summary;
...
}

and do this:

document.assign({summary: null}, { mergeObjects: true });

it explode with:

Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at Function.assignEmbeddable (***/node_modules/@mikro-orm/core/entity/EntityAssigner.js:108:16)

thank you very much for your great work!

When you have entity like this:

```
@entity()
class Document {
...
  @Embedded({
    entity: () => Summary,
    nullable: true,
  })
  summary!: Summary;
...
}
```

and do this:

```
document.assign({summary: null}, { mergeObjects: true });
```

it explode with:
```
Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at Function.assignEmbeddable (***/node_modules/@mikro-orm/core/entity/EntityAssigner.js:108:16)
```

thank you very much for your great work!
@B4nan
Copy link
Member

B4nan commented Jan 27, 2021

Thanks for the fix! Please add a testcase too, otherwise we might fall into same issue during future refactorings easily.

});
if (prop.nullable && value === null) {
entity[propName] = null;
} else if (typeof value === 'object') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd rather keep this as simple else branch (as noted above, if we return early, there is no need for new branching at all), or add a validation if the value is not object. doing it like this, it would silently ignore badly formed data - we should rather fail in such case.

also this will definitely need some test cases to keep the 100% branch coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@B4nan thank you very much for your quick response!
I'll tell you the reasons that made me do it this way:

  • In the first if I understand that null allows to delete from the database, so I assign null but only if the property is nullable, to prevent deleting something if it is not configured for it.
  • In the second if, the object type check allows to discard two cases, on the one hand null which is not nullable and on the other hand undefined, which is an ignored value and respects the previous value.

These are the reasons, do you think it is preferable to make the changes you are talking about?

Thanks a lot!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said, we should not ignore malformed input data, we should throw instead. e.g. we could throw when user tries to set null/undefined and the property is not nullable, but ignoring the request to set a property to null, just because it is not nullable, that sounds wrong to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right! I have updated it


entity[propName][key] = value[key];
});
if (prop.nullable && value === null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd rather not check theh prop.nullable here, also we should think about undefined too (it is possible to force usage of undefined instead of null globally)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ;)

packages/core/src/entity/EntityAssigner.ts Outdated Show resolved Hide resolved
@B4nan B4nan changed the title [bug] Check null value on assignEmbeddable fix(core): allow assigning null to embeddable property Jan 28, 2021
@B4nan
Copy link
Member

B4nan commented Jan 28, 2021

Some tests are failing

Summary of all failing tests
FAIL tests/EntityAssigner.mysql.test.ts
  ● EntityAssignerMySql › assign() should update entity values [mysql]

    TypeError: Cannot read property 'nullable' of undefined

      28 |       let value = data[prop as keyof EntityData<T>];
      29 | 
    > 30 |       if (!props[prop].nullable && (value === undefined || value === null)) {
         |                        ^
      31 |         throw new Error(`You must pass a non-${value} value to the property ${prop} of entity ${entity.constructor.name}.`);
      32 |       }
      33 | 

      at packages/core/src/entity/EntityAssigner.ts:30:24
          at Array.forEach (<anonymous>)
      at Function.assign (packages/core/src/entity/EntityAssigner.ts:23:23)
      at WrappedEntity.assign (packages/core/src/entity/WrappedEntity.ts:61:27)
      at Object.<anonymous> (tests/EntityAssigner.mysql.test.ts:20:16)
          at runMicrotasks (<anonymous>)

FAIL tests/EntityAssigner.mongo.test.ts
  ● EntityAssignerMongo › #assign() should update entity values

    TypeError: Cannot read property 'nullable' of undefined

      28 |       let value = data[prop as keyof EntityData<T>];
      29 | 
    > 30 |       if (!props[prop].nullable && (value === undefined || value === null)) {
         |                        ^
      31 |         throw new Error(`You must pass a non-${value} value to the property ${prop} of entity ${entity.constructor.name}.`);
      32 |       }
      33 | 

      at packages/core/src/entity/EntityAssigner.ts:30:24
          at Array.forEach (<anonymous>)
      at Function.assign (packages/core/src/entity/EntityAssigner.ts:23:23)
      at Book.assign (packages/core/src/entity/BaseEntity.ts:36:27)
      at Object.<anonymous> (tests/EntityAssigner.mongo.test.ts:20:10)
          at runMicrotasks (<anonymous>)

@B4nan B4nan merged commit f3a091e into mikro-orm:master Jan 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants