Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/query-builder/SelectQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -4270,6 +4271,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
if (InstanceChecker.isEqualOperator(where[key])) {
parameterValue = where[key].value
}

if (column.transformer) {
parameterValue instanceof FindOperator
? parameterValue.transformValue(column.transformer)
Expand All @@ -4280,6 +4282,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`);
//
Expand Down
13 changes: 13 additions & 0 deletions test/github-issues/11285/entity/user.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 197 additions & 0 deletions test/github-issues/11285/issue-11285.ts
Original file line number Diff line number Diff line change
@@ -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