Skip to content

EntityManager update/delete/softDelete don't work with list of where condition objects #10517

@sumbricht

Description

@sumbricht

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.

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