mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: ensure correct MSSQL parameter conversion in where conditions
Fixes input parameter conversion in SelectQueryBuilder when using an MSSQL connection. Closes #11285
This commit is contained in:
parent
8c2b2ae240
commit
ecae9f5990
@ -45,6 +45,7 @@ import { AuroraMysqlDriver } from "../driver/aurora-mysql/AuroraMysqlDriver"
|
||||
import { InstanceChecker } from "../util/InstanceChecker"
|
||||
import { FindOperator } from "../find-options/FindOperator"
|
||||
import { ApplyValueTransformers } from "../util/ApplyValueTransformers"
|
||||
import { SqlServerDriver } from "../driver/sqlserver/SqlServerDriver"
|
||||
|
||||
/**
|
||||
* Allows to build complex sql queries in a fashion way and execute those queries.
|
||||
@ -4265,6 +4266,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
if (InstanceChecker.isEqualOperator(where[key])) {
|
||||
parameterValue = where[key].value
|
||||
}
|
||||
|
||||
if (column.transformer) {
|
||||
if (parameterValue instanceof FindOperator) {
|
||||
parameterValue.transformValue(column.transformer)
|
||||
@ -4276,6 +4278,25 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
}
|
||||
}
|
||||
|
||||
// MSSQL requires parameters to carry extra type information
|
||||
if (this.connection.driver.options.type === "mssql") {
|
||||
const driver = this.connection.driver as SqlServerDriver
|
||||
if (parameterValue instanceof FindOperator) {
|
||||
if (parameterValue.type !== "raw") {
|
||||
parameterValue.transformValue({
|
||||
to: (v) =>
|
||||
driver.parametrizeValue(column, v),
|
||||
from: (v) => v,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
parameterValue = driver.parametrizeValue(
|
||||
column,
|
||||
parameterValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// if (parameterValue === null) {
|
||||
// andConditions.push(`${aliasPath} IS NULL`);
|
||||
//
|
||||
|
||||
13
test/github-issues/11285/entity/user.ts
Normal file
13
test/github-issues/11285/entity/user.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Column, Entity, Index, PrimaryGeneratedColumn } from "../../../../src"
|
||||
|
||||
@Entity({
|
||||
name: "user",
|
||||
})
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Index()
|
||||
@Column({ type: "varchar", nullable: true })
|
||||
memberId: string
|
||||
}
|
||||
197
test/github-issues/11285/issue-11285.ts
Normal file
197
test/github-issues/11285/issue-11285.ts
Normal file
@ -0,0 +1,197 @@
|
||||
import "reflect-metadata"
|
||||
import { expect } from "chai"
|
||||
import sinon from "sinon"
|
||||
|
||||
import {
|
||||
createTestingConnections,
|
||||
closeTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { DataSource, MssqlParameter, Not, Raw } from "../../../src/index.js"
|
||||
import { SqlServerQueryRunner } from "../../../src/driver/sqlserver/SqlServerQueryRunner"
|
||||
import { User } from "./entity/user"
|
||||
import { PostgresQueryRunner } from "../../../src/driver/postgres/PostgresQueryRunner"
|
||||
|
||||
describe("github issues > #11285 Missing MSSQL input type", () => {
|
||||
describe("mssql connection", () => {
|
||||
let dataSources: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(dataSources = await createTestingConnections({
|
||||
entities: [User],
|
||||
enabledDrivers: ["mssql"],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
})),
|
||||
)
|
||||
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
afterEach(() => sinon.restore())
|
||||
|
||||
it("should convert input parameter to MssqlParameter", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const user = new User()
|
||||
user.memberId = "test-member-id"
|
||||
|
||||
await dataSource.manager.save([user])
|
||||
|
||||
const selectSpy = sinon.spy(
|
||||
SqlServerQueryRunner.prototype,
|
||||
"query",
|
||||
)
|
||||
|
||||
const users = await dataSource.getRepository(User).find({
|
||||
where: {
|
||||
memberId: user.memberId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(users).to.have.length(1)
|
||||
expect(users[0].memberId).to.be.equal(user.memberId)
|
||||
expect(selectSpy.calledOnce).to.be.true
|
||||
|
||||
sinon.assert.calledWithMatch(
|
||||
selectSpy,
|
||||
sinon.match.any,
|
||||
sinon.match((value) => {
|
||||
return (
|
||||
Array.isArray(value) &&
|
||||
value.length === 1 &&
|
||||
value[0] instanceof MssqlParameter &&
|
||||
value[0].value === user.memberId &&
|
||||
value[0].type === "varchar"
|
||||
)
|
||||
}),
|
||||
)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should convert input parameter with FindOperator to MssqlParameter", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const user = new User()
|
||||
user.memberId = "test-member-id"
|
||||
|
||||
const user2 = new User()
|
||||
user2.memberId = "test-member-id-2"
|
||||
|
||||
await dataSource.manager.save([user, user2])
|
||||
|
||||
const selectSpy = sinon.spy(
|
||||
SqlServerQueryRunner.prototype,
|
||||
"query",
|
||||
)
|
||||
|
||||
const users = await dataSource.getRepository(User).find({
|
||||
where: {
|
||||
memberId: Not(user2.memberId),
|
||||
},
|
||||
})
|
||||
|
||||
expect(users).to.have.length(1)
|
||||
expect(users[0].memberId).to.be.equal(user.memberId)
|
||||
|
||||
expect(selectSpy.calledOnce).to.be.true
|
||||
|
||||
sinon.assert.calledWithMatch(
|
||||
selectSpy,
|
||||
sinon.match.any,
|
||||
sinon.match((value) => {
|
||||
return (
|
||||
Array.isArray(value) &&
|
||||
value.length === 1 &&
|
||||
value[0] instanceof MssqlParameter &&
|
||||
value[0].value === user2.memberId &&
|
||||
value[0].type === "varchar"
|
||||
)
|
||||
}),
|
||||
)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should not convert input parameter with raw FindOperator", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const user = new User()
|
||||
user.memberId = "test-member-id"
|
||||
|
||||
await dataSource.manager.save([user])
|
||||
|
||||
const selectSpy = sinon.spy(
|
||||
SqlServerQueryRunner.prototype,
|
||||
"query",
|
||||
)
|
||||
|
||||
const users = await dataSource.getRepository(User).find({
|
||||
where: {
|
||||
memberId: Raw(`'${user.memberId}'`),
|
||||
},
|
||||
})
|
||||
|
||||
expect(users).to.have.length(1)
|
||||
expect(users[0].memberId).to.be.equal(user.memberId)
|
||||
expect(selectSpy.calledOnce).to.be.true
|
||||
|
||||
sinon.assert.calledWithMatch(
|
||||
selectSpy,
|
||||
sinon.match.any,
|
||||
sinon.match((value) => {
|
||||
return Array.isArray(value) && value.length === 0
|
||||
}),
|
||||
)
|
||||
}),
|
||||
))
|
||||
})
|
||||
|
||||
describe("other connections", () => {
|
||||
let dataSources: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(dataSources = await createTestingConnections({
|
||||
entities: [User],
|
||||
enabledDrivers: ["postgres"],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
})),
|
||||
)
|
||||
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
afterEach(() => sinon.restore())
|
||||
|
||||
it("should used the input parameter as it is", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const user = new User()
|
||||
user.memberId = "test-member-id"
|
||||
|
||||
await dataSource.manager.save([user])
|
||||
|
||||
const selectSpy = sinon.spy(
|
||||
PostgresQueryRunner.prototype,
|
||||
"query",
|
||||
)
|
||||
|
||||
const users = await dataSource.getRepository(User).find({
|
||||
where: {
|
||||
memberId: user.memberId,
|
||||
},
|
||||
})
|
||||
|
||||
expect(users).to.have.length(1)
|
||||
expect(users[0].memberId).to.be.equal(user.memberId)
|
||||
expect(selectSpy.calledOnce).to.be.true
|
||||
|
||||
sinon.assert.calledWithMatch(
|
||||
selectSpy,
|
||||
sinon.match.any,
|
||||
sinon.match((value) => {
|
||||
return value[0] === user.memberId
|
||||
}),
|
||||
)
|
||||
}),
|
||||
))
|
||||
})
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user