diff --git a/src/query-builder/InsertQueryBuilder.ts b/src/query-builder/InsertQueryBuilder.ts index da25a7b5b..d9d530469 100644 --- a/src/query-builder/InsertQueryBuilder.ts +++ b/src/query-builder/InsertQueryBuilder.ts @@ -526,25 +526,47 @@ export class InsertQueryBuilder< )}` } + const updatePart: string[] = [] + if (Array.isArray(overwrite)) { - query += ` ${conflictTarget} DO UPDATE SET ` - query += overwrite - ?.map( + updatePart.push( + ...overwrite?.map( (column) => `${this.escape( column, )} = EXCLUDED.${this.escape(column)}`, - ) - .join(", ") - query += " " + ), + ) } else if (columns) { - query += ` ${conflictTarget} DO UPDATE SET ` - query += columns - .map( + updatePart.push( + ...columns.map( (column) => `${this.escape(column)} = :${column}`, - ) - .join(", ") + ), + ) + } + + if (updatePart.length > 0) { + query += ` ${conflictTarget} DO UPDATE SET ` + + updatePart.push( + ...this.expressionMap + .mainAlias!.metadata.columns.filter( + (column) => + column.isUpdateDate && + !overwrite?.includes( + column.databaseName, + ), + ) + .map( + (column) => + `${this.escape( + column.databaseName, + )} = DEFAULT`, + ), + ) + + query += updatePart.join(", ") query += " " } diff --git a/test/github-issues/9015/entity/Post.ts b/test/github-issues/9015/entity/Post.ts new file mode 100644 index 000000000..e1eb7de23 --- /dev/null +++ b/test/github-issues/9015/entity/Post.ts @@ -0,0 +1,22 @@ +import { + BaseEntity, + Entity, + Column, + UpdateDateColumn, + PrimaryGeneratedColumn, +} from "../../../../src" + +@Entity() +export class Post extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ type: "varchar", unique: true }) + title: string + + @Column({ type: "varchar" }) + description: string + + @UpdateDateColumn() + updated_at: Date +} diff --git a/test/github-issues/9015/issue-9015.ts b/test/github-issues/9015/issue-9015.ts new file mode 100644 index 000000000..0a56d0c79 --- /dev/null +++ b/test/github-issues/9015/issue-9015.ts @@ -0,0 +1,65 @@ +import "reflect-metadata" +import { expect } from "chai" +import { DataSource, Repository } from "../../../src" +import { Post } from "./entity/Post" +import { + reloadTestingDatabases, + closeTestingConnections, + setupSingleTestingConnection, +} from "../../utils/test-utils" + +describe("github issues > #9015 @UpdateDateColumn not updating on upsert", () => { + let dataSource: DataSource + let repository: Repository + + before(async () => { + const options = setupSingleTestingConnection("postgres", { + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchema: true, + }) + + if (!options) return + + dataSource = new DataSource(options) + await dataSource.initialize() + }) + beforeEach(async () => { + if (!dataSource) return + await reloadTestingDatabases([dataSource]) + repository = dataSource.getRepository(Post) + }) + after(() => closeTestingConnections([dataSource])) + + it("should update the @UpdateDateColumn", async () => { + if (!dataSource) return + + const oldDate = new Date("1970-01-01") + const post = new Post() + post.id = 1 + post.title = "Some post" + post.description = "Some description" + post.updated_at = oldDate + + await repository.save(post) + await repository.upsert( + { + title: post.title, + description: "Some new description", + }, + { + conflictPaths: { title: true }, + skipUpdateIfNoValuesChanged: true, + }, + ) + const postReloaded = await repository.findOne({ + where: { id: post.id }, + }) + + expect(postReloaded).to.exist + expect(postReloaded!.description).to.be.equal("Some new description") + expect(postReloaded!.updated_at.toString()).to.not.equal( + oldDate.toString(), + ) + }) +})