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

feat: new array find operators #8766

Merged
merged 2 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,13 @@ This change was required to simplify ORM internals and introduce new features.

* issue with non-reliable `new Date(ISOString)` parsing ([#7796](https://github.com/typeorm/typeorm/pull/7796))

* true JSON / JSONB support - manual `JSON.stringify` was removed,
instead object handled by underlying driver. This opens ability to properly work with json/jsonb structures,
but brings few breaking changes:

* `array: true` must be explicitly defined for array json/jsonb values
* strings being JSON-stringified must be manually escaped

### DEPRECATIONS

* all CLI commands do not support `ormconfig` anymore. You must specify a file with data source instance instead.
Expand Down
48 changes: 48 additions & 0 deletions docs/find-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,54 @@ will execute following query:
SELECT * FROM "post" WHERE "title" IS NULL
```

- `ArrayContains`

```ts
import { ArrayContains } from "typeorm"

const loadedPosts = await dataSource.getRepository(Post).findBy({
categories: ArrayContains(["TypeScript"]),
})
```

will execute following query:

```sql
SELECT * FROM "post" WHERE "categories" @> '{TypeScript}'
```

- `ArrayContainedBy`

```ts
import { ArrayContainedBy } from "typeorm"

const loadedPosts = await dataSource.getRepository(Post).findBy({
categories: ArrayContainedBy(["TypeScript"]),
})
```

will execute following query:

```sql
SELECT * FROM "post" WHERE "categories" <@ '{TypeScript}'
```

- `ArrayOverlap`

```ts
import { ArrayOverlap } from "typeorm"

const loadedPosts = await dataSource.getRepository(Post).findBy({
categories: ArrayOverlap(["TypeScript"]),
})
```

will execute following query:

```sql
SELECT * FROM "post" WHERE "categories" && '{TypeScript}'
```

- `Raw`

```ts
Expand Down
2 changes: 1 addition & 1 deletion src/driver/postgres/PostgresDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ export class PostgresDriver implements Driver {
columnMetadata.type,
) >= 0
) {
return JSON.stringify(value)
return value // JSON.stringify()
} else if (columnMetadata.type === "hstore") {
if (typeof value === "string") {
return value
Expand Down
3 changes: 3 additions & 0 deletions src/find-options/FindOperatorType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ export type FindOperatorType =
| "ilike"
| "like"
| "raw"
| "arrayContains"
| "arrayContainedBy"
| "arrayOverlap"
11 changes: 11 additions & 0 deletions src/find-options/operator/ArrayContainedBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FindOperator } from "../FindOperator"

/**
* FindOptions Operator.
* Example: { someField: ArrayContainedBy([...]) }
*/
export function ArrayContainedBy<T>(
value: T[] | FindOperator<T>,
): FindOperator<any> {
return new FindOperator("arrayContainedBy", value as any)
}
11 changes: 11 additions & 0 deletions src/find-options/operator/ArrayContains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FindOperator } from "../FindOperator"

/**
* FindOptions Operator.
* Example: { someField: ArrayContains([...]) }
*/
export function ArrayContains<T>(
value: T[] | FindOperator<T>,
): FindOperator<any> {
return new FindOperator("arrayContains", value as any)
}
11 changes: 11 additions & 0 deletions src/find-options/operator/ArrayOverlap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FindOperator } from "../FindOperator"

/**
* FindOptions Operator.
* Example: { someField: ArrayOverlap([...]) }
*/
export function ArrayOverlap<T>(
value: T[] | FindOperator<T>,
): FindOperator<any> {
return new FindOperator("arrayOverlap", value as any)
}
6 changes: 6 additions & 0 deletions src/query-builder/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,12 @@ export abstract class QueryBuilder<Entity> {
return `${condition.parameters[0]} < ${condition.parameters[1]}`
case "lessThanOrEqual":
return `${condition.parameters[0]} <= ${condition.parameters[1]}`
case "arrayContains":
return `${condition.parameters[0]} @> ${condition.parameters[1]}`
case "arrayContainedBy":
return `${condition.parameters[0]} <@ ${condition.parameters[1]}`
case "arrayOverlap":
return `${condition.parameters[0]} && ${condition.parameters[1]}`
case "moreThan":
return `${condition.parameters[0]} > ${condition.parameters[1]}`
case "moreThanOrEqual":
Expand Down
3 changes: 3 additions & 0 deletions src/query-builder/WhereClause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ type PredicateOperator =
| "in"
| "any"
| "isNull"
| "arrayContains"
| "arrayContainedBy"
| "arrayOverlap"

export interface WherePredicateOperator {
operator: PredicateOperator
Expand Down
2 changes: 1 addition & 1 deletion test/benchmark/bulk-save-case2/entity/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class Document {
@Column("text")
context: string

@Column({ type: "jsonb" })
@Column({ type: "jsonb", array: true })
distributions: Distribution[]

@Column({ type: "timestamp with time zone" })
Expand Down