diff --git a/src/find-options/FindOperator.ts b/src/find-options/FindOperator.ts index 30dcc166fd..95fa581141 100644 --- a/src/find-options/FindOperator.ts +++ b/src/find-options/FindOperator.ts @@ -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 @@ -135,4 +137,25 @@ export class FindOperator { 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, + ) + } + } } diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 7a8ef9fce0..10e0c5a764 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -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. @@ -4182,10 +4183,13 @@ export class SelectQueryBuilder 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) { diff --git a/test/github-issues/9381/entity/ExampleEntity.ts b/test/github-issues/9381/entity/ExampleEntity.ts new file mode 100644 index 0000000000..ecd0f6b1f0 --- /dev/null +++ b/test/github-issues/9381/entity/ExampleEntity.ts @@ -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 +} diff --git a/test/github-issues/9381/entity/JsonExampleEntity.ts b/test/github-issues/9381/entity/JsonExampleEntity.ts new file mode 100644 index 0000000000..eee436682a --- /dev/null +++ b/test/github-issues/9381/entity/JsonExampleEntity.ts @@ -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 +} diff --git a/test/github-issues/9381/issue-9381.ts b/test/github-issues/9381/issue-9381.ts new file mode 100644 index 0000000000..2421f7592e --- /dev/null +++ b/test/github-issues/9381/issue-9381.ts @@ -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 +})