mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
feat: add isolated where statements (#10213)
- Add `isolateWhereStatements` to the `BaseDataSourceOptions` object and automatically isolate where statements in the query builder if it is true
This commit is contained in:
parent
149226dd67
commit
3cda7ec39d
@ -98,6 +98,9 @@ Different RDBMS-es have their own specific options.
|
||||
- `cache` - Enables entity result caching. You can also configure cache type and other cache options here.
|
||||
Read more about caching [here](caching.md).
|
||||
|
||||
- `isolateWhereStatements` - Enables where statement isolation, wrapping each where clause in brackets automatically.
|
||||
eg. `.where("user.firstName = :search OR user.lastName = :search")` becomes `WHERE (user.firstName = ? OR user.lastName = ?)` instead of `WHERE user.firstName = ? OR user.lastName = ?`
|
||||
|
||||
## `mysql` / `mariadb` data source options
|
||||
|
||||
- `url` - Connection url where perform connection to. Please note that other data source options will override parameters set from url.
|
||||
|
||||
@ -208,4 +208,9 @@ export interface BaseDataSourceOptions {
|
||||
*/
|
||||
readonly ignoreErrors?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows automatic isolation of where clauses
|
||||
*/
|
||||
readonly isolateWhereStatements?: boolean
|
||||
}
|
||||
|
||||
@ -1008,9 +1008,31 @@ export abstract class QueryBuilder<Entity extends ObjectLiteral> {
|
||||
|
||||
switch (clause.type) {
|
||||
case "and":
|
||||
return (index > 0 ? "AND " : "") + expression
|
||||
return (
|
||||
(index > 0 ? "AND " : "") +
|
||||
`${
|
||||
this.connection.options.isolateWhereStatements
|
||||
? "("
|
||||
: ""
|
||||
}${expression}${
|
||||
this.connection.options.isolateWhereStatements
|
||||
? ")"
|
||||
: ""
|
||||
}`
|
||||
)
|
||||
case "or":
|
||||
return (index > 0 ? "OR " : "") + expression
|
||||
return (
|
||||
(index > 0 ? "OR " : "") +
|
||||
`${
|
||||
this.connection.options.isolateWhereStatements
|
||||
? "("
|
||||
: ""
|
||||
}${expression}${
|
||||
this.connection.options.isolateWhereStatements
|
||||
? ")"
|
||||
: ""
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
return expression
|
||||
|
||||
18
test/functional/query-builder/isolated-where/entity/User.ts
Normal file
18
test/functional/query-builder/isolated-where/entity/User.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Entity } from "../../../../../src/decorator/entity/Entity"
|
||||
import { PrimaryGeneratedColumn } from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"
|
||||
import { Column } from "../../../../../src/decorator/columns/Column"
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Column()
|
||||
firstName: string
|
||||
|
||||
@Column()
|
||||
lastName: string
|
||||
|
||||
@Column()
|
||||
isAdmin: boolean
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
import "../../../utils/test-setup"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../../utils/test-utils"
|
||||
import { expect } from "chai"
|
||||
import { DataSource } from "../../../../src"
|
||||
import { User } from "./entity/User"
|
||||
|
||||
describe("query builder > isolated-where", () => {
|
||||
let connections: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(connections = await createTestingConnections({
|
||||
entities: [User],
|
||||
enabledDrivers: ["sqlite"],
|
||||
isolateWhereStatements: true,
|
||||
})),
|
||||
)
|
||||
beforeEach(() => reloadTestingDatabases(connections))
|
||||
after(() => closeTestingConnections(connections))
|
||||
|
||||
it("should correctly apply brackets when where statement isolation is enabled", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const sql = connection.manager
|
||||
.createQueryBuilder(User, "user")
|
||||
.where("user.id = :userId", { userId: "user-id" })
|
||||
.andWhere(
|
||||
"user.firstName = :search OR user.lastName = :search",
|
||||
{
|
||||
search: "search-term",
|
||||
},
|
||||
)
|
||||
.disableEscaping()
|
||||
.getSql()
|
||||
|
||||
expect(sql).to.be.equal(
|
||||
"SELECT user.id AS user_id, user.firstName AS user_firstName, " +
|
||||
"user.lastName AS user_lastName, user.isAdmin AS user_isAdmin " +
|
||||
"FROM user user " +
|
||||
"WHERE user.id = ? " +
|
||||
"AND (user.firstName = ? OR user.lastName = ?)",
|
||||
)
|
||||
}),
|
||||
))
|
||||
})
|
||||
@ -159,6 +159,11 @@ export interface TestingOptions {
|
||||
| Logger
|
||||
|
||||
relationLoadStrategy?: "join" | "query"
|
||||
|
||||
/**
|
||||
* Allows automatic isolation of where clauses
|
||||
*/
|
||||
isolateWhereStatements?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,6 +300,9 @@ export function setupTestingConnections(
|
||||
newOptions.metadataTableName = options.metadataTableName
|
||||
if (options && options.relationLoadStrategy)
|
||||
newOptions.relationLoadStrategy = options.relationLoadStrategy
|
||||
if (options && options.isolateWhereStatements)
|
||||
newOptions.isolateWhereStatements =
|
||||
options.isolateWhereStatements
|
||||
|
||||
newOptions.baseDirectory = path.dirname(getOrmFilepath())
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user