fix: ensure updates to createdAt and updatedAt are respected (#13335)
Previously, when manually setting `createdAt` or `updatedAt` in a
`payload.db.*` or `payload.*` operation, the value may have been
ignored. In some cases it was _impossible_ to change the `updatedAt`
value, even when using direct db adapter calls. On top of that, this
behavior sometimes differed between db adapters. For example, mongodb
did accept `updatedAt` when calling `payload.db.updateVersion` -
postgres ignored it.
This PR changes this behavior to consistently respect `createdAt` and
`updatedAt` values for `payload.db.*` operations.
For `payload.*` operations, this also works with the following
exception:
- update operations do no respect `updatedAt`, as updates are commonly
performed by spreading the old data, e.g. `payload.update({ data:
{...oldData} })` - in these cases, we usually still want the `updatedAt`
to be updated. If you need to get around this, you can use the
`payload.db.updateOne` operation instead.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210919646303994
This commit is contained in:
@@ -17,10 +17,16 @@ export const create: Create = async function create(
|
||||
|
||||
const options: CreateOptions = {
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
let doc
|
||||
|
||||
if (!data.createdAt) {
|
||||
data.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data,
|
||||
|
||||
@@ -14,6 +14,10 @@ export const createGlobal: CreateGlobal = async function createGlobal(
|
||||
) {
|
||||
const { globalConfig, Model } = getGlobal({ adapter: this, globalSlug })
|
||||
|
||||
if (!data.createdAt) {
|
||||
;(data as any).createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data,
|
||||
@@ -24,6 +28,8 @@ export const createGlobal: CreateGlobal = async function createGlobal(
|
||||
|
||||
const options: CreateOptions = {
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
let [result] = (await Model.create([data], options)) as any
|
||||
|
||||
@@ -25,6 +25,8 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
|
||||
|
||||
const options = {
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
const data = {
|
||||
@@ -37,6 +39,9 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
}
|
||||
if (!data.createdAt) {
|
||||
data.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
const fields = buildVersionGlobalFields(this.payload.config, globalConfig)
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
|
||||
const options = {
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
const data = {
|
||||
@@ -41,6 +43,9 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
}
|
||||
if (!data.createdAt) {
|
||||
data.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
const fields = buildVersionCollectionFields(this.payload.config, collectionConfig)
|
||||
|
||||
|
||||
@@ -63,7 +63,10 @@ const migrateModelWithBatching = async ({
|
||||
},
|
||||
},
|
||||
})),
|
||||
{ session },
|
||||
{
|
||||
session, // Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
},
|
||||
)
|
||||
|
||||
skip += batchSize
|
||||
|
||||
@@ -26,6 +26,8 @@ export const updateGlobal: UpdateGlobal = async function updateGlobal(
|
||||
select,
|
||||
}),
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
transform({ adapter: this, data, fields, globalSlug, operation: 'write' })
|
||||
|
||||
@@ -39,6 +39,8 @@ export async function updateGlobalVersion<T extends TypeWithID>(
|
||||
select,
|
||||
}),
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
const query = await buildQuery({
|
||||
|
||||
@@ -36,6 +36,8 @@ export const updateJobs: UpdateJobs = async function updateMany(
|
||||
lean: true,
|
||||
new: true,
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
let query = await buildQuery({
|
||||
|
||||
@@ -58,6 +58,8 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
select,
|
||||
}),
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
let query = await buildQuery({
|
||||
|
||||
@@ -38,6 +38,8 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
select,
|
||||
}),
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
const query = await buildQuery({
|
||||
|
||||
@@ -45,6 +45,8 @@ export const updateVersion: UpdateVersion = async function updateVersion(
|
||||
select,
|
||||
}),
|
||||
session: await getSession(this, req),
|
||||
// Timestamps are manually added by the write transform
|
||||
timestamps: false,
|
||||
}
|
||||
|
||||
const query = await buildQuery({
|
||||
|
||||
@@ -395,6 +395,10 @@ describe('transform', () => {
|
||||
data,
|
||||
fields: config.collections[0].fields,
|
||||
})
|
||||
if ('updatedAt' in data) {
|
||||
delete data.updatedAt
|
||||
}
|
||||
|
||||
const flattenValuesAfter = Object.values(flattenRelationshipValues(data))
|
||||
|
||||
flattenValuesAfter.forEach((value, i) => {
|
||||
|
||||
@@ -548,4 +548,10 @@ export const transform = ({
|
||||
parentIsLocalized,
|
||||
ref: data,
|
||||
})
|
||||
|
||||
if (operation === 'write') {
|
||||
if (!data.updatedAt) {
|
||||
data.updatedAt = new Date().toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,6 +546,19 @@ export const traverseFields = ({
|
||||
valuesToTransform.forEach(({ localeKey, ref, value }) => {
|
||||
let formattedValue = value
|
||||
|
||||
if (field.type === 'date') {
|
||||
if (fieldName === 'updatedAt' && !formattedValue) {
|
||||
// let the db handle this
|
||||
formattedValue = new Date().toISOString()
|
||||
} else {
|
||||
if (typeof value === 'number' && !Number.isNaN(value)) {
|
||||
formattedValue = new Date(value).toISOString()
|
||||
} else if (value instanceof Date) {
|
||||
formattedValue = value.toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== 'undefined') {
|
||||
if (value && field.type === 'point' && adapter.name !== 'sqlite') {
|
||||
formattedValue = sql`ST_GeomFromGeoJSON(${JSON.stringify(value)})`
|
||||
@@ -570,19 +583,6 @@ export const traverseFields = ({
|
||||
|
||||
formattedValue = sql.raw(`${columnName} + ${value.$inc}`)
|
||||
}
|
||||
|
||||
if (field.type === 'date') {
|
||||
if (typeof value === 'number' && !Number.isNaN(value)) {
|
||||
formattedValue = new Date(value).toISOString()
|
||||
} else if (value instanceof Date) {
|
||||
formattedValue = value.toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (field.type === 'date' && fieldName === 'updatedAt') {
|
||||
// let the db handle this
|
||||
formattedValue = new Date().toISOString()
|
||||
}
|
||||
|
||||
if (typeof formattedValue !== 'undefined') {
|
||||
|
||||
@@ -42,6 +42,10 @@ export const upsertRow = async <T extends Record<string, unknown> | TypeWithID>(
|
||||
upsertTarget,
|
||||
where,
|
||||
}: Args): Promise<T> => {
|
||||
if (operation === 'create' && !data.createdAt) {
|
||||
data.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
let insertedRow: Record<string, unknown> = { id }
|
||||
if (id && shouldUseOptimizedUpsertRow({ data, fields })) {
|
||||
const { row } = transformForWrite({
|
||||
|
||||
@@ -73,6 +73,9 @@ export const logoutOperation = async (incomingArgs: Arguments): Promise<boolean>
|
||||
userWithSessions.sessions = sessionsAfterLogout
|
||||
}
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
;(userWithSessions as any).updatedAt = new Date().toISOString()
|
||||
|
||||
await req.payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -92,6 +92,9 @@ export const refreshOperation = async (incomingArgs: Arguments): Promise<Result>
|
||||
const tokenExpInMs = collectionConfig.auth.tokenExpiration * 1000
|
||||
existingSession.expiresAt = new Date(now.getTime() + tokenExpInMs)
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
user.updatedAt = new Date().toISOString()
|
||||
|
||||
await req.payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -131,6 +131,9 @@ export const resetPasswordOperation = async <TSlug extends CollectionSlug>(
|
||||
// Update new password
|
||||
// /////////////////////////////////////
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
user.updatedAt = new Date().toISOString()
|
||||
|
||||
const doc = await payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -46,6 +46,9 @@ export const verifyEmailOperation = async (args: Args): Promise<boolean> => {
|
||||
throw new APIError('Verification token is invalid.', httpStatus.FORBIDDEN)
|
||||
}
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
user.updatedAt = new Date().toISOString()
|
||||
|
||||
await req.payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collection.config.slug,
|
||||
|
||||
@@ -49,6 +49,9 @@ export const addSessionToUser = async ({
|
||||
user.sessions.push(session)
|
||||
}
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
user.updatedAt = new Date().toISOString()
|
||||
|
||||
await payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -142,6 +142,9 @@ export const incrementLoginAttempts = async ({
|
||||
|
||||
user.sessions = currentUser.sessions
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
user.updatedAt = new Date().toISOString()
|
||||
|
||||
await payload.db.updateOne({
|
||||
id: user.id,
|
||||
collection: collection.slug,
|
||||
|
||||
@@ -258,6 +258,8 @@ export const restoreVersionOperation = async <TData extends TypeWithID = any>(
|
||||
select: incomingSelect,
|
||||
})
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
result.updatedAt = new Date().toISOString()
|
||||
result = await req.payload.db.updateOne({
|
||||
id: parentDocID,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -293,6 +293,8 @@ export const updateDocument = async <
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (!shouldSaveDraft) {
|
||||
// Ensure updatedAt date is always updated
|
||||
dataToUpdate.updatedAt = new Date().toISOString()
|
||||
result = await req.payload.db.updateOne({
|
||||
id,
|
||||
collection: collectionConfig.slug,
|
||||
|
||||
@@ -86,6 +86,8 @@ export const restoreVersionOperation = async <T extends TypeWithVersion<T> = any
|
||||
let result = rawVersion.version
|
||||
|
||||
if (global) {
|
||||
// Ensure updatedAt date is always updated
|
||||
result.updatedAt = new Date().toISOString()
|
||||
result = await payload.db.updateGlobal({
|
||||
slug: globalConfig.slug,
|
||||
data: result,
|
||||
|
||||
@@ -256,6 +256,9 @@ export const updateOperation = async <
|
||||
result.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
result.updatedAt = new Date().toISOString()
|
||||
|
||||
if (globalExists) {
|
||||
result = await payload.db.updateGlobal({
|
||||
slug,
|
||||
|
||||
@@ -40,6 +40,7 @@ export const defaultAfterSchedule: AfterScheduleFn = async ({ jobStats, queueabl
|
||||
},
|
||||
},
|
||||
},
|
||||
updatedAt: new Date().toISOString(),
|
||||
} as JobStats,
|
||||
req,
|
||||
returning: false,
|
||||
|
||||
@@ -83,6 +83,9 @@ export async function updateJobs({
|
||||
: undefined,
|
||||
}
|
||||
|
||||
// Ensure updatedAt date is always updated
|
||||
data.updatedAt = new Date().toISOString()
|
||||
|
||||
const args: UpdateJobsArgs = id
|
||||
? {
|
||||
id,
|
||||
|
||||
@@ -36,6 +36,16 @@ export const getConfig: () => Partial<Config> = () => ({
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
{
|
||||
slug: 'noTimeStamps',
|
||||
timestamps: false,
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'categories',
|
||||
versions: { drafts: true },
|
||||
|
||||
@@ -49,6 +49,8 @@ const collection = postsSlug
|
||||
const title = 'title'
|
||||
process.env.PAYLOAD_CONFIG_PATH = path.join(dirname, 'config.ts')
|
||||
|
||||
const itMongo = process.env.PAYLOAD_DATABASE?.startsWith('mongodb') ? it : it.skip
|
||||
|
||||
describe('database', () => {
|
||||
beforeAll(async () => {
|
||||
process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit
|
||||
@@ -224,6 +226,12 @@ describe('database', () => {
|
||||
const createdAtDate = new Date(result.createdAt)
|
||||
|
||||
expect(createdAtDate.getMilliseconds()).toBeDefined()
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow createdAt to be set in create', async () => {
|
||||
@@ -243,9 +251,15 @@ describe('database', () => {
|
||||
|
||||
expect(result.createdAt).toStrictEqual(createdAt)
|
||||
expect(doc.createdAt).toStrictEqual(createdAt)
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('updatedAt cannot be set in create', async () => {
|
||||
it('should allow updatedAt to be set in create', async () => {
|
||||
const updatedAt = new Date('2022-01-01T00:00:00.000Z').toISOString()
|
||||
const result = await payload.create({
|
||||
collection: postsSlug,
|
||||
@@ -255,9 +269,303 @@ describe('database', () => {
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.updatedAt).not.toStrictEqual(updatedAt)
|
||||
expect(result.updatedAt).toStrictEqual(updatedAt)
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
it('should allow createdAt to be set in update', async () => {
|
||||
const post = await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
const createdAt = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
|
||||
const result: any = await payload.db.updateOne({
|
||||
collection: postsSlug,
|
||||
id: post.id,
|
||||
data: {
|
||||
createdAt,
|
||||
},
|
||||
})
|
||||
|
||||
const doc = await payload.findByID({
|
||||
id: result.id,
|
||||
collection: postsSlug,
|
||||
})
|
||||
|
||||
expect(doc.createdAt).toStrictEqual(createdAt)
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow updatedAt to be set in update', async () => {
|
||||
const post = await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
const updatedAt = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
|
||||
const result: any = await payload.db.updateOne({
|
||||
collection: postsSlug,
|
||||
id: post.id,
|
||||
data: {
|
||||
updatedAt,
|
||||
},
|
||||
})
|
||||
|
||||
const doc = await payload.findByID({
|
||||
id: result.id,
|
||||
collection: postsSlug,
|
||||
})
|
||||
|
||||
expect(doc.updatedAt).toStrictEqual(updatedAt)
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow createdAt to be set in updateVersion', async () => {
|
||||
const category = await payload.create({
|
||||
collection: 'categories',
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'categories',
|
||||
id: category.id,
|
||||
data: {
|
||||
title: 'hello2',
|
||||
},
|
||||
})
|
||||
const versions = await payload.findVersions({
|
||||
collection: 'categories',
|
||||
depth: 0,
|
||||
sort: '-createdAt',
|
||||
})
|
||||
const createdAt = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
|
||||
for (const version of versions.docs) {
|
||||
await payload.db.updateVersion({
|
||||
id: version.id,
|
||||
collection: 'categories',
|
||||
versionData: {
|
||||
...version.version,
|
||||
createdAt,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const updatedVersions = await payload.findVersions({
|
||||
collection: 'categories',
|
||||
depth: 0,
|
||||
sort: '-createdAt',
|
||||
})
|
||||
expect(updatedVersions.docs).toHaveLength(2)
|
||||
for (const version of updatedVersions.docs) {
|
||||
expect(version.createdAt).toStrictEqual(createdAt)
|
||||
}
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: 'categories',
|
||||
where: {},
|
||||
})
|
||||
await payload.db.deleteVersions({
|
||||
collection: 'categories',
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow updatedAt to be set in updateVersion', async () => {
|
||||
const category = await payload.create({
|
||||
collection: 'categories',
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'categories',
|
||||
id: category.id,
|
||||
data: {
|
||||
title: 'hello2',
|
||||
},
|
||||
})
|
||||
const versions = await payload.findVersions({
|
||||
collection: 'categories',
|
||||
depth: 0,
|
||||
sort: '-createdAt',
|
||||
})
|
||||
const updatedAt = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
|
||||
for (const version of versions.docs) {
|
||||
await payload.db.updateVersion({
|
||||
id: version.id,
|
||||
collection: 'categories',
|
||||
versionData: {
|
||||
...version.version,
|
||||
updatedAt,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const updatedVersions = await payload.findVersions({
|
||||
collection: 'categories',
|
||||
depth: 0,
|
||||
sort: '-updatedAt',
|
||||
})
|
||||
expect(updatedVersions.docs).toHaveLength(2)
|
||||
for (const version of updatedVersions.docs) {
|
||||
expect(version.updatedAt).toStrictEqual(updatedAt)
|
||||
}
|
||||
|
||||
// Cleanup, as this test suite does not use clearAndSeedEverything
|
||||
await payload.db.deleteMany({
|
||||
collection: 'categories',
|
||||
where: {},
|
||||
})
|
||||
await payload.db.deleteVersions({
|
||||
collection: 'categories',
|
||||
where: {},
|
||||
})
|
||||
})
|
||||
|
||||
async function noTimestampsTestLocalAPI() {
|
||||
const createdDoc: any = await payload.create({
|
||||
collection: 'noTimeStamps',
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
expect(createdDoc.createdAt).toBeUndefined()
|
||||
expect(createdDoc.updatedAt).toBeUndefined()
|
||||
|
||||
const updated: any = await payload.update({
|
||||
collection: 'noTimeStamps',
|
||||
id: createdDoc.id,
|
||||
data: {
|
||||
title: 'updated',
|
||||
},
|
||||
})
|
||||
expect(updated.createdAt).toBeUndefined()
|
||||
expect(updated.updatedAt).toBeUndefined()
|
||||
|
||||
const date = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
const createdDocWithTimestamps: any = await payload.create({
|
||||
collection: 'noTimeStamps',
|
||||
data: {
|
||||
title: 'hello',
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
},
|
||||
})
|
||||
expect(createdDocWithTimestamps.createdAt).toBeUndefined()
|
||||
expect(createdDocWithTimestamps.updatedAt).toBeUndefined()
|
||||
|
||||
const updatedDocWithTimestamps: any = await payload.update({
|
||||
collection: 'noTimeStamps',
|
||||
id: createdDocWithTimestamps.id,
|
||||
data: {
|
||||
title: 'updated',
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
},
|
||||
})
|
||||
expect(updatedDocWithTimestamps.createdAt).toBeUndefined()
|
||||
expect(updatedDocWithTimestamps.updatedAt).toBeUndefined()
|
||||
}
|
||||
|
||||
async function noTimestampsTestDB(aa) {
|
||||
const createdDoc: any = await payload.db.create({
|
||||
collection: 'noTimeStamps',
|
||||
data: {
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
expect(createdDoc.createdAt).toBeUndefined()
|
||||
expect(createdDoc.updatedAt).toBeUndefined()
|
||||
|
||||
const updated: any = await payload.db.updateOne({
|
||||
collection: 'noTimeStamps',
|
||||
id: createdDoc.id,
|
||||
data: {
|
||||
title: 'updated',
|
||||
},
|
||||
})
|
||||
expect(updated.createdAt).toBeUndefined()
|
||||
expect(updated.updatedAt).toBeUndefined()
|
||||
|
||||
const date = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
const createdDocWithTimestamps: any = await payload.db.create({
|
||||
collection: 'noTimeStamps',
|
||||
data: {
|
||||
title: 'hello',
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
},
|
||||
})
|
||||
expect(createdDocWithTimestamps.createdAt).toBeUndefined()
|
||||
expect(createdDocWithTimestamps.updatedAt).toBeUndefined()
|
||||
|
||||
const updatedDocWithTimestamps: any = await payload.db.updateOne({
|
||||
collection: 'noTimeStamps',
|
||||
id: createdDocWithTimestamps.id,
|
||||
data: {
|
||||
title: 'updated',
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
},
|
||||
})
|
||||
expect(updatedDocWithTimestamps.createdAt).toBeUndefined()
|
||||
expect(updatedDocWithTimestamps.updatedAt).toBeUndefined()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('ensure timestamps are not created in update or create when timestamps are disabled', async () => {
|
||||
await noTimestampsTestLocalAPI()
|
||||
})
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('ensure timestamps are not created in db adapter update or create when timestamps are disabled', async () => {
|
||||
await noTimestampsTestDB(true)
|
||||
})
|
||||
|
||||
itMongo(
|
||||
'ensure timestamps are not created in update or create when timestamps are disabled even with allowAdditionalKeys true',
|
||||
async () => {
|
||||
const originalAllowAdditionalKeys = payload.db.allowAdditionalKeys
|
||||
payload.db.allowAdditionalKeys = true
|
||||
await noTimestampsTestLocalAPI()
|
||||
payload.db.allowAdditionalKeys = originalAllowAdditionalKeys
|
||||
},
|
||||
)
|
||||
|
||||
itMongo(
|
||||
'ensure timestamps are not created in db adapter update or create when timestamps are disabled even with allowAdditionalKeys true',
|
||||
async () => {
|
||||
const originalAllowAdditionalKeys = payload.db.allowAdditionalKeys
|
||||
payload.db.allowAdditionalKeys = true
|
||||
await noTimestampsTestDB()
|
||||
|
||||
payload.db.allowAdditionalKeys = originalAllowAdditionalKeys
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('Data strictness', () => {
|
||||
it('should not save and leak password, confirm-password from Local API', async () => {
|
||||
|
||||
@@ -67,6 +67,7 @@ export interface Config {
|
||||
};
|
||||
blocks: {};
|
||||
collections: {
|
||||
noTimeStamps: NoTimeStamp;
|
||||
categories: Category;
|
||||
simple: Simple;
|
||||
'categories-custom-id': CategoriesCustomId;
|
||||
@@ -94,6 +95,7 @@ export interface Config {
|
||||
};
|
||||
collectionsJoins: {};
|
||||
collectionsSelect: {
|
||||
noTimeStamps: NoTimeStampsSelect<false> | NoTimeStampsSelect<true>;
|
||||
categories: CategoriesSelect<false> | CategoriesSelect<true>;
|
||||
simple: SimpleSelect<false> | SimpleSelect<true>;
|
||||
'categories-custom-id': CategoriesCustomIdSelect<false> | CategoriesCustomIdSelect<true>;
|
||||
@@ -163,6 +165,14 @@ export interface UserAuthOperations {
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "noTimeStamps".
|
||||
*/
|
||||
export interface NoTimeStamp {
|
||||
id: string;
|
||||
title?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "categories".
|
||||
@@ -617,6 +627,10 @@ export interface User {
|
||||
export interface PayloadLockedDocument {
|
||||
id: string;
|
||||
document?:
|
||||
| ({
|
||||
relationTo: 'noTimeStamps';
|
||||
value: string | NoTimeStamp;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'categories';
|
||||
value: string | Category;
|
||||
@@ -743,6 +757,13 @@ export interface PayloadMigration {
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "noTimeStamps_select".
|
||||
*/
|
||||
export interface NoTimeStampsSelect<T extends boolean = true> {
|
||||
title?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "categories_select".
|
||||
|
||||
Reference in New Issue
Block a user