Skip to content

Commit

Permalink
fix: transform values for FindOperators #9381 (#9777)
Browse files Browse the repository at this point in the history
* fix: transform values for FindOperators

Closes: #9381

* refactor: simplify correction

do not transform value, when it is a FindOperator

Closes: #9381

* fix: transform value of FindOperator when it is not a FindOperator

Closes: #9381 #9816

* fix: perform transformation on the array instead of each value in case of JsonContains

* fix: remove anti pattern, correct functionality for operators without multiple parameter

* fix: correct linting

* fix: resolve issue when parameterValue is not an instanceof FindOperator

---------

Co-authored-by: ke <ke@sbs.co.at>
  • Loading branch information
ertl and ertl committed Apr 6, 2023
1 parent 197cc05 commit de1228d
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 5 deletions.
23 changes: 23 additions & 0 deletions src/find-options/FindOperator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ObjectLiteral } from "../common/ObjectLiteral"
import { FindOperatorType } from "./FindOperatorType"
import { InstanceChecker } from "../util/InstanceChecker"
import { ValueTransformer } from "../decorator/options/ValueTransformer"
import { ApplyValueTransformers } from "../util/ApplyValueTransformers"

type SqlGeneratorType = (aliasPath: string) => string

Expand Down Expand Up @@ -135,4 +137,25 @@ export class FindOperator<T> {

return this._getSql
}

transformValue(transformer: ValueTransformer | ValueTransformer[]) {
if (this._value instanceof FindOperator) {
this._value.transformValue(transformer)
} else {
this._value =
Array.isArray(this._value) && this._multipleParameters
? this._value.map(
(v: any) =>
transformer &&
ApplyValueTransformers.transformTo(
transformer,
v,
),
)
: ApplyValueTransformers.transformTo(
transformer,
this._value,
)
}
}
}
14 changes: 9 additions & 5 deletions src/query-builder/SelectQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ import { FindOptionsOrder } from "../find-options/FindOptionsOrder"
import { FindOptionsWhere } from "../find-options/FindOptionsWhere"
import { FindOptionsUtils } from "../find-options/FindOptionsUtils"
import { FindOptionsRelations } from "../find-options/FindOptionsRelations"
import { ApplyValueTransformers } from "../util/ApplyValueTransformers"
import { OrmUtils } from "../util/OrmUtils"
import { EntityPropertyNotFoundError } from "../error/EntityPropertyNotFoundError"
import { AuroraMysqlDriver } from "../driver/aurora-mysql/AuroraMysqlDriver"
import { InstanceChecker } from "../util/InstanceChecker"
import { FindOperator } from "../find-options/FindOperator"
import { ApplyValueTransformers } from "../util/ApplyValueTransformers"

/**
* Allows to build complex sql queries in a fashion way and execute those queries.
Expand Down Expand Up @@ -4182,10 +4183,13 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
parameterValue = where[key].value
}
if (column.transformer) {
parameterValue = ApplyValueTransformers.transformTo(
column.transformer,
parameterValue,
)
parameterValue instanceof FindOperator
? parameterValue.transformValue(column.transformer)
: (parameterValue =
ApplyValueTransformers.transformTo(
column.transformer,
parameterValue,
))
}

// if (parameterValue === null) {
Expand Down
17 changes: 17 additions & 0 deletions test/github-issues/9381/entity/ExampleEntity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Entity, Generated, PrimaryColumn } from "../../../../src"

const ID_TRANSFORMER = {
from: (dbValue: number) => dbValue?.toString(),
to: (entityValue: string) =>
entityValue ? Number(entityValue) : entityValue,
}

@Entity()
export class ExampleEntity {
@Generated("increment")
@PrimaryColumn({
type: "integer",
transformer: ID_TRANSFORMER,
})
id: string
}
29 changes: 29 additions & 0 deletions test/github-issues/9381/entity/JsonExampleEntity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Column, Entity, Generated, PrimaryColumn } from "../../../../src"

const ID_TRANSFORMER = {
from: (dbValue: number) => dbValue?.toString(),
to: (entityValue: string) =>
entityValue ? Number(entityValue) : entityValue,
}

const JSON_TRANSFORMER = {
to: (value: any) => ({ wrap: value }),
from: (value: { wrap: any }) => value.wrap,
}

@Entity()
export class JsonExampleEntity {
constructor(value: any) {
this.jsonvalue = value
}

@Generated("increment")
@PrimaryColumn({
type: "integer",
transformer: ID_TRANSFORMER,
})
id: string

@Column({ type: "jsonb", transformer: JSON_TRANSFORMER })
jsonvalue: any
}
124 changes: 124 additions & 0 deletions test/github-issues/9381/issue-9381.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import "reflect-metadata"
import {
closeTestingConnections,
createTestingConnections,
} from "../../utils/test-utils"
import { In, JsonContains, Not } from "../../../src"
import { ExampleEntity } from "./entity/ExampleEntity"
import { expect } from "chai"
import { JsonExampleEntity } from "./entity/JsonExampleEntity"

describe("github issues > #9381 The column option 《transformer》 affects the result of the query condition generation", () => {
it("transform and find values", async () => {
const dataSources = await createTestingConnections({
entities: [__dirname + "/entity/ExampleEntity{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
})

await Promise.all(
dataSources.map(async (dataSource) => {
let repository = dataSource.getRepository(ExampleEntity)
await repository.save(new ExampleEntity())
await repository.save(new ExampleEntity())
await repository.save(new ExampleEntity())
await repository.save(new ExampleEntity())
await repository.save(new ExampleEntity())
const resultFindAll = await repository.find()
expect(resultFindAll.length).to.be.eql(5)

const resultTransformer = await repository.findBy({
id: Not(In(["1", "3", "5"])),
})
expect(resultTransformer).to.be.eql([
{
id: "2",
},
{
id: "4",
},
])
const findEqualsTransformer = await repository.findOne({
where: {
id: "1",
},
})
expect(findEqualsTransformer).to.be.eql({ id: "1" })
}),
)

await closeTestingConnections(dataSources)
})

it("transform json values and find values", async () => {
const dataSources = await createTestingConnections({
entities: [__dirname + "/entity/JsonExampleEntity{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
enabledDrivers: ["postgres"],
})

await Promise.all(
dataSources.map(async (dataSource) => {
let repository = dataSource.getRepository(JsonExampleEntity)
await repository.save(new JsonExampleEntity({ foo: "bar1" }))
await repository.save(new JsonExampleEntity({ foo: "bar2" }))
await repository.save(new JsonExampleEntity({ foo: "bar3" }))
await repository.save(new JsonExampleEntity({ foo: "bar4" }))
await repository.save(new JsonExampleEntity({ foo: "bar5" }))
await repository.save(
new JsonExampleEntity({ foo: { bar: [5, 6, 7, 8] } }),
)
await repository.save(new JsonExampleEntity([5, 6, 7, 8]))

const resultTransformer = await repository.findBy({
id: Not(In(["1", "3", "5", "6", "7"])),
})
expect(resultTransformer).to.be.eql([
{
id: "2",
jsonvalue: {
foo: "bar2",
},
},
{
id: "4",
jsonvalue: {
foo: "bar4",
},
},
])

let result = await repository.findOneBy({
jsonvalue: JsonContains({ foo: "bar1" }),
})
expect(result).to.be.eql({
id: "1",
jsonvalue: {
foo: "bar1",
},
})

result = await repository.findOneBy({
jsonvalue: JsonContains({ foo: {} }),
})
expect(result).to.be.eql({
id: "6",
jsonvalue: {
foo: { bar: [5, 6, 7, 8] },
},
})

result = await repository.findOneBy({
jsonvalue: JsonContains([5, 6, 7, 8] as any),
})
expect(result).to.be.eql({
id: "7",
jsonvalue: [5, 6, 7, 8],
})
}),
)
await closeTestingConnections(dataSources)
})
// you can add additional tests if needed
})

0 comments on commit de1228d

Please sign in to comment.