fix: properly store timestamps in versions (#8646)
This PR makes a more clear gap between `version_createdAt` / `version_updatedAt` and `createdAt` / `updatedAt` columns / fields in mongodb. - `createdAt` - This should be a new value in a new version. Before this change it was the same all the time. Should remain the same on autosave. - The same for `updatedAt`, but it should be updated on every change (including autosave) - `version_createdAt` - Should remain equal to `createdAt` from the parent collection / table - `version_updatedAt` - On a latest version it makes sense this be the same as `updatedAt` from the parent collection / table, as all the `version_*` fields should be just synced with it
This commit is contained in:
@@ -99,8 +99,6 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||
_id: doc.parent,
|
||||
id: doc.parent,
|
||||
...doc.version,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
}
|
||||
|
||||
return sanitizeInternalFields(doc)
|
||||
|
||||
@@ -12,10 +12,12 @@ export async function createGlobalVersion<T extends TypeWithID>(
|
||||
this: DrizzleAdapter,
|
||||
{
|
||||
autosave,
|
||||
createdAt,
|
||||
globalSlug,
|
||||
publishedLocale,
|
||||
req = {} as PayloadRequest,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
versionData,
|
||||
}: CreateGlobalVersionArgs,
|
||||
) {
|
||||
@@ -28,9 +30,11 @@ export async function createGlobalVersion<T extends TypeWithID>(
|
||||
adapter: this,
|
||||
data: {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
},
|
||||
db,
|
||||
|
||||
@@ -13,10 +13,12 @@ export async function createVersion<T extends TypeWithID>(
|
||||
{
|
||||
autosave,
|
||||
collectionSlug,
|
||||
createdAt,
|
||||
parent,
|
||||
publishedLocale,
|
||||
req = {} as PayloadRequest,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
versionData,
|
||||
}: CreateVersionArgs<T>,
|
||||
) {
|
||||
@@ -33,17 +35,15 @@ export async function createVersion<T extends TypeWithID>(
|
||||
|
||||
const data: Record<string, unknown> = {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
parent,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version,
|
||||
}
|
||||
|
||||
if ('createdAt' in version) {
|
||||
data.createdAt = version.createdAt
|
||||
}
|
||||
|
||||
const result = await upsertRow<TypeWithVersion<T>>({
|
||||
adapter: this,
|
||||
data,
|
||||
|
||||
@@ -38,8 +38,6 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||
doc = {
|
||||
id: doc.parent,
|
||||
...doc.version,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
}
|
||||
|
||||
return doc
|
||||
|
||||
@@ -267,10 +267,7 @@ export const duplicateOperation = async <TSlug extends CollectionSlug>(
|
||||
result = await saveVersion({
|
||||
id: versionDoc.id,
|
||||
collection: collectionConfig,
|
||||
docWithLocales: {
|
||||
...versionDoc,
|
||||
createdAt: result.createdAt,
|
||||
},
|
||||
docWithLocales: versionDoc,
|
||||
draft: shouldSaveDraft,
|
||||
payload,
|
||||
req,
|
||||
|
||||
@@ -131,7 +131,7 @@ export const findOperation = async <TSlug extends CollectionSlug>(
|
||||
page: sanitizedPage,
|
||||
pagination: usePagination,
|
||||
req,
|
||||
sort: getQueryDraftsSort(sort),
|
||||
sort: getQueryDraftsSort({ collectionConfig, sort }),
|
||||
where: fullWhere,
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -329,10 +329,7 @@ export const updateOperation = async <TSlug extends CollectionSlug>(
|
||||
result = await saveVersion({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
docWithLocales: {
|
||||
...result,
|
||||
createdAt: doc.createdAt,
|
||||
},
|
||||
docWithLocales: result,
|
||||
payload,
|
||||
req,
|
||||
})
|
||||
|
||||
@@ -356,10 +356,7 @@ export const updateByIDOperation = async <TSlug extends CollectionSlug>(
|
||||
id,
|
||||
autosave,
|
||||
collection: collectionConfig,
|
||||
docWithLocales: {
|
||||
...result,
|
||||
createdAt: docWithLocales.createdAt,
|
||||
},
|
||||
docWithLocales: result,
|
||||
draft: shouldSaveDraft,
|
||||
payload,
|
||||
publishSpecificLocale,
|
||||
|
||||
@@ -245,11 +245,7 @@ export const updateOperation = async <TSlug extends GlobalSlug>(
|
||||
const { globalType } = result
|
||||
result = await saveVersion({
|
||||
autosave,
|
||||
docWithLocales: {
|
||||
...result,
|
||||
createdAt: result.createdAt,
|
||||
updatedAt: result.updatedAt,
|
||||
},
|
||||
docWithLocales: result,
|
||||
draft: shouldSaveDraft,
|
||||
global: globalConfig,
|
||||
payload,
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
|
||||
|
||||
/**
|
||||
* Takes the incoming sort argument and prefixes it with `versions.` and preserves any `-` prefixes for descending order
|
||||
* @param sort
|
||||
*/
|
||||
export const getQueryDraftsSort = (sort: string): string => {
|
||||
export const getQueryDraftsSort = ({
|
||||
collectionConfig,
|
||||
sort,
|
||||
}: {
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
sort: string
|
||||
}): string => {
|
||||
if (!sort) {
|
||||
return sort
|
||||
if (collectionConfig.defaultSort) {
|
||||
sort = collectionConfig.defaultSort
|
||||
} else {
|
||||
sort = '-createdAt'
|
||||
}
|
||||
}
|
||||
|
||||
let direction = ''
|
||||
|
||||
@@ -48,10 +48,7 @@ export const getLatestCollectionVersion = async <T extends TypeWithID = any>({
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
...latestVersion.version,
|
||||
id,
|
||||
createdAt: latestVersion.createdAt,
|
||||
updatedAt: latestVersion.updatedAt,
|
||||
}
|
||||
latestVersion.version.id = id
|
||||
|
||||
return latestVersion.version
|
||||
}
|
||||
|
||||
@@ -56,12 +56,16 @@ export const getLatestGlobalVersion = async ({
|
||||
}
|
||||
}
|
||||
|
||||
if (!latestVersion.version.createdAt) {
|
||||
latestVersion.version.createdAt = latestVersion.createdAt
|
||||
}
|
||||
|
||||
if (!latestVersion.version.updatedAt) {
|
||||
latestVersion.version.updatedAt = latestVersion.updatedAt
|
||||
}
|
||||
|
||||
return {
|
||||
global: {
|
||||
...latestVersion.version,
|
||||
createdAt: latestVersion.createdAt,
|
||||
updatedAt: latestVersion.updatedAt,
|
||||
},
|
||||
global: latestVersion.version,
|
||||
globalExists,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export const saveVersion = async ({
|
||||
|
||||
const data: Record<string, unknown> = {
|
||||
createdAt: new Date(latestVersion.createdAt).toISOString(),
|
||||
updatedAt: draft ? now : new Date(doc.updatedAt).toISOString(),
|
||||
updatedAt: now,
|
||||
version: {
|
||||
...versionData,
|
||||
},
|
||||
@@ -114,12 +114,12 @@ export const saveVersion = async ({
|
||||
const createVersionArgs = {
|
||||
autosave: Boolean(autosave),
|
||||
collectionSlug: undefined,
|
||||
createdAt: doc?.createdAt ? new Date(doc.createdAt).toISOString() : now,
|
||||
createdAt: now,
|
||||
globalSlug: undefined,
|
||||
parent: collection ? id : undefined,
|
||||
publishedLocale: publishSpecificLocale || undefined,
|
||||
req,
|
||||
updatedAt: draft ? now : new Date(doc.updatedAt).toISOString(),
|
||||
updatedAt: now,
|
||||
versionData,
|
||||
}
|
||||
|
||||
@@ -194,8 +194,6 @@ export const saveVersion = async ({
|
||||
}
|
||||
|
||||
let createdVersion = result.version
|
||||
createdVersion.createdAt = result.createdAt
|
||||
createdVersion.updatedAt = result.updatedAt
|
||||
|
||||
createdVersion = sanitizeInternalFields(createdVersion)
|
||||
createdVersion.id = result.parent
|
||||
|
||||
@@ -339,6 +339,11 @@ const DocumentInfo: React.FC<
|
||||
...versionParams.where,
|
||||
and: [
|
||||
...versionParams.where.and,
|
||||
{
|
||||
'version._status': {
|
||||
equals: 'draft',
|
||||
},
|
||||
},
|
||||
{
|
||||
updatedAt: {
|
||||
greater_than: publishedJSON.updatedAt,
|
||||
|
||||
@@ -14,6 +14,7 @@ import AutosavePosts from './collections/Autosave.js'
|
||||
import AutosaveGlobal from './globals/Autosave.js'
|
||||
import {
|
||||
autosaveCollectionSlug,
|
||||
autoSaveGlobalSlug,
|
||||
draftCollectionSlug,
|
||||
localizedCollectionSlug,
|
||||
localizedGlobalSlug,
|
||||
@@ -306,21 +307,55 @@ describe('Versions', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('should have the same createdAt on new version create', async () => {
|
||||
it('should have different createdAt in a new version while the same version.createdAt', async () => {
|
||||
const doc = await payload.create({
|
||||
collection: autosaveCollectionSlug,
|
||||
data: { description: 'descr', title: 'title' },
|
||||
})
|
||||
|
||||
await wait(30)
|
||||
await wait(10)
|
||||
|
||||
const updated = await payload.update({
|
||||
const upd = await payload.update({
|
||||
collection: autosaveCollectionSlug,
|
||||
id: doc.id,
|
||||
data: {},
|
||||
})
|
||||
|
||||
expect(doc.createdAt).toBe(updated.createdAt)
|
||||
expect(upd.createdAt).toBe(doc.createdAt)
|
||||
|
||||
const {
|
||||
docs: [latestVersionData],
|
||||
} = await payload.findVersions({
|
||||
collection: autosaveCollectionSlug,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: doc.id,
|
||||
},
|
||||
latest: {
|
||||
equals: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
// Version itself should have new createdAt
|
||||
expect(new Date(latestVersionData.createdAt) > new Date(doc.createdAt)).toBe(true)
|
||||
// But the same createdAt in version data!
|
||||
expect(latestVersionData.version.createdAt).toBe(doc.createdAt)
|
||||
|
||||
const fromNonVersionsTable = await payload.findByID({
|
||||
draft: false,
|
||||
id: doc.id,
|
||||
collection: autosaveCollectionSlug,
|
||||
})
|
||||
|
||||
// createdAt from non-versions should be the same as version_createdAt in versions
|
||||
expect(fromNonVersionsTable.createdAt).toBe(latestVersionData.version.createdAt)
|
||||
// When creating new version - updatedAt should match version.updatedAt
|
||||
expect(fromNonVersionsTable.updatedAt).toBe(latestVersionData.version.updatedAt)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1265,6 +1300,48 @@ describe('Versions', () => {
|
||||
expect(updatedGlobal._status).toStrictEqual('draft')
|
||||
expect(globalLocalVersionID).toBeDefined()
|
||||
})
|
||||
|
||||
it('should have different createdAt in a new version while the same version.createdAt', async () => {
|
||||
const doc = await payload.updateGlobal({
|
||||
slug: autoSaveGlobalSlug,
|
||||
data: { title: 'asd' },
|
||||
})
|
||||
|
||||
await wait(10)
|
||||
|
||||
const upd = await payload.updateGlobal({
|
||||
slug: autoSaveGlobalSlug,
|
||||
data: { title: 'asd2' },
|
||||
})
|
||||
|
||||
expect(upd.createdAt).toBe(doc.createdAt)
|
||||
|
||||
const {
|
||||
docs: [latestVersionData],
|
||||
} = await payload.findGlobalVersions({
|
||||
slug: autoSaveGlobalSlug,
|
||||
where: {
|
||||
latest: {
|
||||
equals: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Version itself should have new createdAt
|
||||
expect(new Date(latestVersionData.createdAt) > new Date(doc.createdAt)).toBe(true)
|
||||
// But the same version.createdAt!
|
||||
expect(latestVersionData.version.createdAt).toBe(doc.createdAt)
|
||||
|
||||
const fromNonVersionsTable = await payload.findGlobal({
|
||||
draft: false,
|
||||
slug: autoSaveGlobalSlug,
|
||||
})
|
||||
|
||||
// createdAt from non-versions should be the same as version_createdAt in versions
|
||||
expect(fromNonVersionsTable.createdAt).toBe(latestVersionData.version.createdAt)
|
||||
// When creating a new version - updatedAt should match
|
||||
expect(fromNonVersionsTable.updatedAt).toBe(latestVersionData.version.updatedAt)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Read', () => {
|
||||
|
||||
Reference in New Issue
Block a user