feat: implement OR operator (#10086)

* feat: implement or operator

This new feature enables typeorm to allow use multiple operators joining with or

Closes: #10054

* feat: implement or operator

Completed code formating using command.

Closes: #10054

* feat: implement or operator

Completed the documentation update.

Closes: #10054

* feat: implement or operator

Renamed Or operator file name.

Closes: #10054

* feat: implement or operator

Renamed Or operator file name.

Closes: #10054

* feat: implement or operator

Renamed Or operator file name.

Closes: #10054

* feat: implement or operator

Renamed Or operator.

Closes: #10054
This commit is contained in:
Deep khurana 2024-01-02 15:31:01 +05:30 committed by GitHub
parent dd595242a7
commit a00b1df68f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 1 deletions

View File

@ -606,7 +606,9 @@ SELECT * FROM "post" WHERE "titles" IN ('Go To Statement Considered Harmful', 'S
## Combining Advanced Options
Also you can combine these operators with `Not` operator:
Also you can combine these operators with below:
- `Not`
```ts
import { Not, MoreThan, Equal } from "typeorm"
@ -622,3 +624,19 @@ will execute following query:
```sql
SELECT * FROM "post" WHERE NOT("likes" > 10) AND NOT("title" = 'About #2')
```
- `Or`
```ts
import { Not, MoreThan, ILike } from "typeorm"
const loadedPosts = await dataSource.getRepository(Post).findBy({
title: Or(Equal("About #2"), ILike("About%")),
})
```
will execute following query:
```sql
SELECT * FROM "post" WHERE "title" = 'About #2' OR "title" ILIKE 'About%'
```

View File

@ -20,3 +20,4 @@ export type FindOperatorType =
| "arrayOverlap"
| "and"
| "jsonContains"
| "or"

View File

@ -0,0 +1,5 @@
import { FindOperator } from "../FindOperator"
export function Or<T>(...values: FindOperator<T>[]): FindOperator<T> {
return new FindOperator("or", values as any, true, true)
}

View File

@ -67,6 +67,7 @@ export * from "./decorator/Exclusion"
export * from "./decorator/Generated"
export * from "./decorator/EntityRepository"
export * from "./find-options/operator/And"
export * from "./find-options/operator/Or"
export * from "./find-options/operator/Any"
export * from "./find-options/operator/ArrayContainedBy"
export * from "./find-options/operator/ArrayContains"

View File

@ -1127,6 +1127,8 @@ export abstract class QueryBuilder<Entity extends ObjectLiteral> {
)}`
case "and":
return condition.parameters.join(" AND ")
case "or":
return condition.parameters.join(" OR ")
}
throw new TypeError(
@ -1542,6 +1544,20 @@ export abstract class QueryBuilder<Entity extends ObjectLiteral> {
} else if (parameterValue.type === "and") {
const values: FindOperator<any>[] = parameterValue.value
return {
operator: parameterValue.type,
parameters: values.map((operator) =>
this.createWhereConditionExpression(
this.getWherePredicateCondition(
aliasPath,
operator,
),
),
),
}
} else if (parameterValue.type === "or") {
const values: FindOperator<any>[] = parameterValue.value
return {
operator: parameterValue.type,
parameters: values.map((operator) =>

View File

@ -18,6 +18,7 @@ type PredicateOperator =
| "arrayOverlap"
| "and"
| "jsonContains"
| "or"
export interface WherePredicateOperator {
operator: PredicateOperator

View File

@ -0,0 +1,13 @@
import { Entity, Column, PrimaryGeneratedColumn } from "../../../../src"
@Entity({ name: "person" })
export class Person {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column({ type: "int", nullable: true })
age: number | null
}

View File

@ -0,0 +1,65 @@
import { Or, DataSource, ILike, Equal } from "../../../src"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
} from "../../utils/test-utils"
import { Person } from "./entity/Person"
import { expect } from "chai"
describe("github issues > #10054 Nested 'Or' Condition/Operation Support in Repository Where condition", () => {
let dataSources: DataSource[]
before(async () => {
dataSources = await createTestingConnections({
entities: [Person],
enabledDrivers: ["postgres", "mysql"],
schemaCreate: true,
dropSchema: true,
})
})
beforeEach(() => reloadTestingDatabases(dataSources))
after(() => closeTestingConnections(dataSources))
it("should find person where name starts with foo or equal to jane", async () => {
await Promise.all(
dataSources.map(async (dataSource) => {
debugger
const foo = new Person()
foo.name = "Foo"
foo.age = null
const john = new Person()
john.name = "John"
john.age = 11
const dave = new Person()
dave.name = "Jane"
dave.age = 12
const foobar = new Person()
foobar.name = "FooBar"
foobar.age = 14
await dataSource.manager.save([foo, john, dave, foobar])
const persons = await dataSource.manager.find(Person, {
where: {
name: Or(ILike("foo%"), Equal("Jane")),
},
})
expect(persons).to.have.length(3)
expect(persons.find((user) => user.name === "Foo")).to.be.not
.undefined
expect(persons.find((user) => user.name === "Jane")).to.be.not
.undefined
expect(persons.find((user) => user.name === "FooBar")).to.be.not
.undefined
}),
)
})
})