mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fix: change how array columns are compared on column changed detection (#11269)
* fix: change how array columns are compared on column changed detection Closes: #5967 * add tests with date array colum * Normalize date arrays before comparing
This commit is contained in:
parent
61a6f971af
commit
a61654e079
@ -85,16 +85,32 @@ export class SubjectChangedColumnsComputer {
|
||||
if (entityValue !== null) {
|
||||
switch (column.type) {
|
||||
case "date":
|
||||
normalizedValue =
|
||||
DateUtils.mixedDateToDateString(entityValue)
|
||||
normalizedValue = column.isArray
|
||||
? entityValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToDateString(date),
|
||||
)
|
||||
: DateUtils.mixedDateToDateString(entityValue)
|
||||
databaseValue = column.isArray
|
||||
? databaseValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToDateString(date),
|
||||
)
|
||||
: DateUtils.mixedDateToDateString(databaseValue)
|
||||
break
|
||||
|
||||
case "time":
|
||||
case "time with time zone":
|
||||
case "time without time zone":
|
||||
case "timetz":
|
||||
normalizedValue =
|
||||
DateUtils.mixedDateToTimeString(entityValue)
|
||||
normalizedValue = column.isArray
|
||||
? entityValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToTimeString(date),
|
||||
)
|
||||
: DateUtils.mixedDateToTimeString(entityValue)
|
||||
databaseValue = column.isArray
|
||||
? databaseValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToTimeString(date),
|
||||
)
|
||||
: DateUtils.mixedDateToTimeString(databaseValue)
|
||||
break
|
||||
|
||||
case "datetime":
|
||||
@ -105,14 +121,26 @@ export class SubjectChangedColumnsComputer {
|
||||
case "timestamp with time zone":
|
||||
case "timestamp with local time zone":
|
||||
case "timestamptz":
|
||||
normalizedValue =
|
||||
DateUtils.mixedDateToUtcDatetimeString(
|
||||
entityValue,
|
||||
)
|
||||
databaseValue =
|
||||
DateUtils.mixedDateToUtcDatetimeString(
|
||||
databaseValue,
|
||||
)
|
||||
normalizedValue = column.isArray
|
||||
? entityValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToUtcDatetimeString(
|
||||
date,
|
||||
),
|
||||
)
|
||||
: DateUtils.mixedDateToUtcDatetimeString(
|
||||
entityValue,
|
||||
)
|
||||
|
||||
databaseValue = column.isArray
|
||||
? databaseValue.map((date: Date) =>
|
||||
DateUtils.mixedDateToUtcDatetimeString(
|
||||
date,
|
||||
),
|
||||
)
|
||||
: DateUtils.mixedDateToUtcDatetimeString(
|
||||
databaseValue,
|
||||
)
|
||||
|
||||
break
|
||||
|
||||
case "json":
|
||||
@ -155,7 +183,10 @@ export class SubjectChangedColumnsComputer {
|
||||
}
|
||||
|
||||
// if value is not changed - then do nothing
|
||||
if (
|
||||
if (column.isArray) {
|
||||
if (OrmUtils.deepCompare(normalizedValue, databaseValue))
|
||||
return
|
||||
} else if (
|
||||
Buffer.isBuffer(normalizedValue) &&
|
||||
Buffer.isBuffer(databaseValue)
|
||||
) {
|
||||
|
||||
20
test/github-issues/5967/entity/User.ts
Normal file
20
test/github-issues/5967/entity/User.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Column, PrimaryGeneratedColumn } from "../../../../src"
|
||||
import { Entity } from "../../../../src/decorator/entity/Entity"
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
|
||||
@Column("int", {
|
||||
array: true,
|
||||
default: "{}",
|
||||
})
|
||||
roles: number[]
|
||||
|
||||
@Column("date", {
|
||||
array: true,
|
||||
default: "{}",
|
||||
})
|
||||
dates: Date[]
|
||||
}
|
||||
200
test/github-issues/5967/issue-5967.ts
Normal file
200
test/github-issues/5967/issue-5967.ts
Normal file
@ -0,0 +1,200 @@
|
||||
import { expect } from "chai"
|
||||
import { DataSource } from "../../../src"
|
||||
import {
|
||||
closeTestingConnections,
|
||||
createTestingConnections,
|
||||
reloadTestingDatabases,
|
||||
} from "../../utils/test-utils"
|
||||
import { User } from "./entity/User"
|
||||
import { MemoryLogger } from "./memory-logger"
|
||||
|
||||
describe("github issues > #5967 @afterUpdate always says array/json field updated", () => {
|
||||
let dataSources: DataSource[]
|
||||
before(
|
||||
async () =>
|
||||
(dataSources = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
schemaCreate: true,
|
||||
dropSchema: true,
|
||||
enabledDrivers: ["postgres"], // Array column are only supported by postgres src/decorator/options/ColumnCommonOptions.ts
|
||||
createLogger: () => new MemoryLogger(true),
|
||||
})),
|
||||
)
|
||||
|
||||
beforeEach(() => reloadTestingDatabases(dataSources))
|
||||
after(() => closeTestingConnections(dataSources))
|
||||
|
||||
it("should not update an array column if there was no change", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const valueBefore = [1, 2, 3]
|
||||
const valueAfter = [1, 2, 3]
|
||||
|
||||
const repository = dataSource.getRepository(User)
|
||||
|
||||
const logger = dataSource.logger as MemoryLogger
|
||||
logger.clear()
|
||||
|
||||
const user = await repository.save({
|
||||
roles: valueBefore,
|
||||
})
|
||||
|
||||
const insertQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("INSERT"),
|
||||
)
|
||||
expect(insertQueries).to.have.length(1)
|
||||
logger.clear()
|
||||
|
||||
await repository.save({
|
||||
id: user.id,
|
||||
roles: valueAfter,
|
||||
})
|
||||
|
||||
const updateQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("UPDATE"),
|
||||
)
|
||||
expect(updateQueries).to.have.length(0)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should not update a date array column if there was no change", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const date = new Date("2023-01-01")
|
||||
const valueBefore = [date]
|
||||
const valueAfter = [date]
|
||||
|
||||
const repository = dataSource.getRepository(User)
|
||||
|
||||
const logger = dataSource.logger as MemoryLogger
|
||||
logger.clear()
|
||||
|
||||
const user = await repository.save({
|
||||
dates: valueBefore,
|
||||
})
|
||||
|
||||
const insertQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("INSERT"),
|
||||
)
|
||||
expect(insertQueries).to.have.length(1)
|
||||
logger.clear()
|
||||
|
||||
await repository.save({
|
||||
id: user.id,
|
||||
dates: valueAfter,
|
||||
})
|
||||
|
||||
const updateQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("UPDATE"),
|
||||
)
|
||||
expect(updateQueries).to.have.length(0)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should not update a date array column if the only change was a normalization one", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const valueBefore = [new Date("2023-01-01:00:00:00")]
|
||||
const valueAfter = [new Date("2023-01-01:01:00:00")]
|
||||
|
||||
const repository = dataSource.getRepository(User)
|
||||
|
||||
const logger = dataSource.logger as MemoryLogger
|
||||
logger.clear()
|
||||
|
||||
const user = await repository.save({
|
||||
dates: valueBefore,
|
||||
})
|
||||
|
||||
const insertQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("INSERT"),
|
||||
)
|
||||
expect(insertQueries).to.have.length(1)
|
||||
logger.clear()
|
||||
|
||||
await repository.save({
|
||||
id: user.id,
|
||||
dates: valueAfter,
|
||||
})
|
||||
|
||||
const updateQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("UPDATE"),
|
||||
)
|
||||
expect(updateQueries).to.have.length(0)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should update and array column if there was a change", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const valueBefore = [1, 2, 3]
|
||||
const valueAfter = [4, 5, 6]
|
||||
|
||||
const repository = dataSource.getRepository(User)
|
||||
|
||||
const logger = dataSource.logger as MemoryLogger
|
||||
logger.clear()
|
||||
|
||||
const user = await repository.save({
|
||||
roles: valueBefore,
|
||||
})
|
||||
|
||||
const insertQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("INSERT"),
|
||||
)
|
||||
expect(insertQueries).to.have.length(1)
|
||||
logger.clear()
|
||||
|
||||
await repository.save({
|
||||
id: user.id,
|
||||
roles: valueAfter,
|
||||
})
|
||||
|
||||
const updateQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("UPDATE"),
|
||||
)
|
||||
expect(updateQueries).to.have.length(1)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should update a date array column if there was a change", () =>
|
||||
Promise.all(
|
||||
dataSources.map(async (dataSource) => {
|
||||
const valueBefore = [
|
||||
new Date("2023-01-01"),
|
||||
new Date("2023-01-02"),
|
||||
new Date("2023-01-03"),
|
||||
]
|
||||
const valueAfter = [
|
||||
new Date("2023-01-04"),
|
||||
new Date("2023-01-05"),
|
||||
new Date("2023-01-06"),
|
||||
]
|
||||
|
||||
const repository = dataSource.getRepository(User)
|
||||
|
||||
const logger = dataSource.logger as MemoryLogger
|
||||
logger.clear()
|
||||
|
||||
const user = await repository.save({
|
||||
dates: valueBefore,
|
||||
})
|
||||
|
||||
const insertQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("INSERT"),
|
||||
)
|
||||
expect(insertQueries).to.have.length(1)
|
||||
logger.clear()
|
||||
|
||||
await repository.save({
|
||||
id: user.id,
|
||||
dates: valueAfter,
|
||||
})
|
||||
|
||||
const updateQueries = logger.queries.filter((q) =>
|
||||
q.startsWith("UPDATE"),
|
||||
)
|
||||
expect(updateQueries).to.have.length(1)
|
||||
}),
|
||||
))
|
||||
})
|
||||
30
test/github-issues/5967/memory-logger.ts
Normal file
30
test/github-issues/5967/memory-logger.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Logger } from "../../../src/logger/Logger"
|
||||
|
||||
export class MemoryLogger implements Logger {
|
||||
constructor(public enabled = true) {}
|
||||
|
||||
private _queries: string[] = []
|
||||
get queries() {
|
||||
return this._queries
|
||||
}
|
||||
|
||||
logQuery(query: string) {
|
||||
if (this.enabled) {
|
||||
this._queries.push(query)
|
||||
}
|
||||
}
|
||||
|
||||
logQueryError(error: string, query: string) {}
|
||||
|
||||
logQuerySlow(time: number, query: string) {}
|
||||
|
||||
logSchemaBuild(message: string) {}
|
||||
|
||||
logMigration(message: string) {}
|
||||
|
||||
log(level: "log" | "info" | "warn", message: any) {}
|
||||
|
||||
clear() {
|
||||
this._queries = []
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user