-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Description
Issue description
EntityManager update/delete/softDelete don't work with list of where condition objects
Expected Behavior
A list of where condition objects should be allowed for update/delete/softDelete/restore. The following should all work:
const whereConditions = [
{ id: LessThan(5) },
{ id: MoreThan(10) }
]
// These are working fine:
await dataSource.manager.find(target, { where: whereConditions })
await dataSource.manager.findBy(target, whereConditions)
// These all fail:
await dataSource.manager.update(target, whereConditions, { someColumn: 'foo' })
await dataSource.manager.softDelete(target, whereConditions)
await dataSource.manager.delete(target, whereConditions)
await dataSource.manager.restore(target, whereConditions)Actual Behavior
For update/delete/softDelete/restore, EntityManager interprets the list of condition objects as list of primitive values and therefore always creates an SQL statement like this:
... WHERE "id" IN ($1, $2)with parameters
[
{"_type":"lessThan","_value":5,"_useParameter":true,"_multipleParameters":false},
{"_type":"moreThan","_value":10,"_useParameter":true,"_multipleParameters":false}
]This behavior makes sense when a list of numbers / strings / Dates was given, but not for complex objects where providing an Array of objects should be interpreted as an OR of multiple conditions.
The responsible code section exists in the 4 methods EntityManager.update/delete/softDelete/restore. Here the example for update:
if (
typeof criteria === "string" ||
typeof criteria === "number" ||
criteria instanceof Date ||
Array.isArray(criteria)
) {
return this.createQueryBuilder()
.update(target)
.set(partialEntity)
.whereInIds(criteria)
.execute()
} else {
return this.createQueryBuilder()
.update(target)
.set(partialEntity)
.where(criteria)
.execute()
}I would propose changing the condition in the if such that it only applies for Arrays that contain only strings, numbers and Dates:
// added this method
private isCriteriaOnlyPrimitiveValues(criteria: any) {
if(
typeof criteria === "string" ||
typeof criteria === "number" ||
criteria instanceof Date
) return true
if(Array.isArray(criteria)) {
if(!criteria.length) return true // treat empty array as array of primitive values for backwards compatibility
return criteria.every(item => !Array.isArray(item) && this.isCriteriaOnlyPrimitiveValues(item))
}
}
update(target, criteria, partialEntity) {
// if user passed empty criteria or empty list of criterias, then throw an error
if (criteria === undefined ||
criteria === null ||
criteria === "" ||
(Array.isArray(criteria) && criteria.length === 0)) {
return Promise.reject(new error_1.TypeORMError(`Empty criteria(s) are not allowed for the update method.`));
}
// changed this condition
if (this.isCriteriaOnlyPrimitiveValues(criteria)) {
[..]
}
else {
[..]
}
}Steps to reproduce
See example above. The bug is independent of the DB type used (I used Postgres).
My Environment
| Dependency | Version |
|---|---|
| Operating System | Linux (shouldn't matter) |
| Node.js version | 18.17.0 (shouldn't matter) |
| Typescript version | 5.3.2 (shouldn't matter) |
| TypeORM version | 0.3.17 |
Additional Context
No response
Relevant Database Driver(s)
- aurora-mysql
- aurora-postgres
- better-sqlite3
- cockroachdb
- cordova
- expo
- mongodb
- mysql
- nativescript
- oracle
- postgres
- react-native
- sap
- spanner
- sqlite
- sqlite-abstract
- sqljs
- sqlserver
Are you willing to resolve this issue by submitting a Pull Request?
Yes, I have the time, and I know how to start.