import "reflect-metadata" import { closeTestingConnections, createTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" import { DataSource } from "../../../src/data-source/DataSource" import { User } from "./entity/User" import { expect } from "chai" import { ReturningStatementNotSupportedError } from "../../../src/error/ReturningStatementNotSupportedError" describe("github issues > #660 Specifying a RETURNING or OUTPUT clause with QueryBuilder", () => { let connections: DataSource[] before( async () => (connections = await createTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"], })), ) beforeEach(() => reloadTestingDatabases(connections)) after(() => closeTestingConnections(connections)) it("should create an INSERT statement, including RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { const user = new User() user.name = "Tim Merrison" let sql: string = "" try { sql = connection .createQueryBuilder() .insert() .into(User) .values(user) .returning( connection.driver.options.type === "postgres" ? "*" : "inserted.*", ) .disableEscaping() .getSql() } catch (err) { expect(err.message).to.eql( new ReturningStatementNotSupportedError().message, ) } if (connection.driver.options.type === "mssql") { expect(sql).to.equal( "INSERT INTO user(name) OUTPUT inserted.* VALUES (@0)", ) } else if (connection.driver.options.type === "postgres") { expect(sql).to.equal( "INSERT INTO user(name) VALUES ($1) RETURNING *", ) } }), )) it("should perform insert with RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { const user = new User() user.name = "Tim Merrison" if ( connection.driver.options.type === "mssql" || connection.driver.options.type === "postgres" ) { const returning = await connection .createQueryBuilder() .insert() .into(User) .values(user) .returning( connection.driver.options.type === "postgres" ? "*" : "inserted.*", ) .execute() returning.raw.should.be.eql([{ id: 1, name: user.name }]) } }), )) it("should create an UPDATE statement, including RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { const user = new User() user.name = "Tim Merrison" try { const sql = connection .createQueryBuilder() .update(User) .set({ name: "Joe Bloggs" }) .where("name = :name", { name: user.name }) .returning( connection.driver.options.type === "postgres" ? "*" : "inserted.*", ) .disableEscaping() .getSql() if (connection.driver.options.type === "mssql") { expect(sql).to.equal( "UPDATE user SET name = @0 OUTPUT inserted.* WHERE name = @1", ) } else if (connection.driver.options.type === "postgres") { expect(sql).to.equal( "UPDATE user SET name = $1 WHERE name = $2 RETURNING *", ) } } catch (err) { expect(err.message).to.eql( new ReturningStatementNotSupportedError().message, ) } }), )) it("should perform update with RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { const user = new User() user.name = "Tim Merrison" await connection.manager.save(user) if ( connection.driver.options.type === "mssql" || connection.driver.options.type === "postgres" ) { const returning = await connection .createQueryBuilder() .update(User) .set({ name: "Joe Bloggs" }) .where("name = :name", { name: user.name }) .returning( connection.driver.options.type === "postgres" ? "*" : "inserted.*", ) .execute() returning.raw.should.be.eql([{ id: 1, name: "Joe Bloggs" }]) } }), )) it("should create a DELETE statement, including RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { try { const user = new User() user.name = "Tim Merrison" const sql = connection .createQueryBuilder() .delete() .from(User) .where("name = :name", { name: user.name }) .returning( connection.driver.options.type === "postgres" ? "*" : "deleted.*", ) .disableEscaping() .getSql() if (connection.driver.options.type === "mssql") { expect(sql).to.equal( "DELETE FROM user OUTPUT deleted.* WHERE name = @0", ) } else if (connection.driver.options.type === "postgres") { expect(sql).to.equal( "DELETE FROM user WHERE name = $1 RETURNING *", ) } } catch (err) { expect(err.message).to.eql( new ReturningStatementNotSupportedError().message, ) } }), )) it("should perform delete with RETURNING or OUTPUT clause (PostgreSQL and MSSQL only)", () => Promise.all( connections.map(async (connection) => { const user = new User() user.name = "Tim Merrison" await connection.manager.save(user) if ( connection.driver.options.type === "mssql" || connection.driver.options.type === "postgres" ) { const returning = await connection .createQueryBuilder() .delete() .from(User) .where("name = :name", { name: user.name }) .returning( connection.driver.options.type === "postgres" ? "*" : "deleted.*", ) .execute() returning.raw.should.be.eql([{ id: 1, name: user.name }]) } }), )) })