fix(db-postgres): ensure globals have createdAt, updatedAt and globalType fields (#10938)
Previously, data for globals was inconsistent across database adapters. In Postgres, globals didn't store correct `createdAt`, `updatedAt` fields and the `updateGlobal` lacked the `globalType` field. This PR solves that without introducing schema changes.
This commit is contained in:
@@ -16,7 +16,9 @@ export async function createGlobal<T extends Record<string, unknown>>(
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(globalConfig.slug))
|
||||
|
||||
const result = await upsertRow<T>({
|
||||
data.createdAt = new Date().toISOString()
|
||||
|
||||
const result = await upsertRow<{ globalType: string } & T>({
|
||||
adapter: this,
|
||||
data,
|
||||
db,
|
||||
@@ -26,5 +28,7 @@ export async function createGlobal<T extends Record<string, unknown>>(
|
||||
tableName,
|
||||
})
|
||||
|
||||
result.globalType = slug
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -479,8 +479,9 @@ export const traverseFields = ({
|
||||
}
|
||||
|
||||
valuesToTransform.forEach(({ localeKey, ref, value }) => {
|
||||
if (typeof value !== 'undefined') {
|
||||
let formattedValue = value
|
||||
|
||||
if (typeof value !== 'undefined') {
|
||||
if (value && field.type === 'point' && adapter.name !== 'sqlite') {
|
||||
formattedValue = sql`ST_GeomFromGeoJSON(${JSON.stringify(value)})`
|
||||
}
|
||||
@@ -490,12 +491,16 @@ export const traverseFields = ({
|
||||
formattedValue = new Date(value).toISOString()
|
||||
} else if (value instanceof Date) {
|
||||
formattedValue = value.toISOString()
|
||||
} else if (fieldName === 'updatedAt') {
|
||||
// let the db handle this
|
||||
formattedValue = new Date().toISOString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (field.type === 'date' && fieldName === 'updatedAt') {
|
||||
// let the db handle this
|
||||
formattedValue = new Date().toISOString()
|
||||
}
|
||||
|
||||
if (typeof formattedValue !== 'undefined') {
|
||||
if (localeKey) {
|
||||
ref[localeKey][fieldName] = formattedValue
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@ export async function updateGlobal<T extends Record<string, unknown>>(
|
||||
|
||||
const existingGlobal = await db.query[tableName].findFirst({})
|
||||
|
||||
const result = await upsertRow<T>({
|
||||
const result = await upsertRow<{ globalType: string } & T>({
|
||||
...(existingGlobal ? { id: existingGlobal.id, operation: 'update' } : { operation: 'create' }),
|
||||
adapter: this,
|
||||
data,
|
||||
@@ -28,5 +28,7 @@ export async function updateGlobal<T extends Record<string, unknown>>(
|
||||
tableName,
|
||||
})
|
||||
|
||||
result.globalType = slug
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -244,6 +244,11 @@ export const updateOperation = async <
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (!shouldSaveDraft) {
|
||||
// Ensure global has createdAt
|
||||
if (!result.createdAt) {
|
||||
result.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
||||
if (globalExists) {
|
||||
result = await payload.db.updateGlobal({
|
||||
slug,
|
||||
|
||||
@@ -563,6 +563,24 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
versions: true,
|
||||
},
|
||||
{
|
||||
slug: 'global-2',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'global-3',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
|
||||
@@ -27,6 +27,7 @@ import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
import { isMongoose } from '../helpers/isMongoose.js'
|
||||
import removeFiles from '../helpers/removeFiles.js'
|
||||
import { errorOnUnnamedFieldsSlug, postsSlug } from './shared.js'
|
||||
import { Global2 } from './payload-types.js'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
@@ -1357,4 +1358,54 @@ describe('database', () => {
|
||||
const { id: id_2 } = await payload.create({ collection: postsSlug, data: { title: 'ASD' } })
|
||||
expect(id_2).not.toBe(id)
|
||||
})
|
||||
|
||||
it('payload.db.createGlobal should have globalType, updatedAt, createdAt fields', async () => {
|
||||
let timestamp = Date.now()
|
||||
let result = (await payload.db.createGlobal({
|
||||
slug: 'global-2',
|
||||
data: { text: 'this is global-2' },
|
||||
})) as Global2 & { globalType: string }
|
||||
|
||||
expect(result.text).toBe('this is global-2')
|
||||
expect(result.globalType).toBe('global-2')
|
||||
expect(timestamp).toBeLessThanOrEqual(new Date(result.createdAt as string).getTime())
|
||||
expect(timestamp).toBeLessThanOrEqual(new Date(result.updatedAt as string).getTime())
|
||||
|
||||
const createdAt = new Date(result.createdAt as string).getTime()
|
||||
|
||||
result = (await payload.db.updateGlobal({
|
||||
slug: 'global-2',
|
||||
data: { text: 'this is global-2 but updated' },
|
||||
})) as Global2 & { globalType: string }
|
||||
|
||||
expect(result.text).toBe('this is global-2 but updated')
|
||||
expect(result.globalType).toBe('global-2')
|
||||
expect(createdAt).toEqual(new Date(result.createdAt as string).getTime())
|
||||
expect(createdAt).toBeLessThan(new Date(result.updatedAt as string).getTime())
|
||||
})
|
||||
|
||||
it('payload.updateGlobal should have globalType, updatedAt, createdAt fields', async () => {
|
||||
let timestamp = Date.now()
|
||||
let result = (await payload.updateGlobal({
|
||||
slug: 'global-3',
|
||||
data: { text: 'this is global-3' },
|
||||
})) as Global2 & { globalType: string }
|
||||
|
||||
expect(result.text).toBe('this is global-3')
|
||||
expect(result.globalType).toBe('global-3')
|
||||
expect(timestamp).toBeLessThanOrEqual(new Date(result.createdAt as string).getTime())
|
||||
expect(timestamp).toBeLessThanOrEqual(new Date(result.updatedAt as string).getTime())
|
||||
|
||||
const createdAt = new Date(result.createdAt as string).getTime()
|
||||
|
||||
result = (await payload.updateGlobal({
|
||||
slug: 'global-3',
|
||||
data: { text: 'this is global-3 but updated' },
|
||||
})) as Global2 & { globalType: string }
|
||||
|
||||
expect(result.text).toBe('this is global-3 but updated')
|
||||
expect(result.globalType).toBe('global-3')
|
||||
expect(createdAt).toEqual(new Date(result.createdAt as string).getTime())
|
||||
expect(createdAt).toBeLessThan(new Date(result.updatedAt as string).getTime())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -52,9 +52,13 @@ export interface Config {
|
||||
};
|
||||
globals: {
|
||||
global: Global;
|
||||
'global-2': Global2;
|
||||
'global-3': Global3;
|
||||
};
|
||||
globalsSelect: {
|
||||
global: GlobalSelect<false> | GlobalSelect<true>;
|
||||
'global-2': Global2Select<false> | Global2Select<true>;
|
||||
'global-3': Global3Select<false> | Global3Select<true>;
|
||||
};
|
||||
locale: 'en' | 'es';
|
||||
user: User & {
|
||||
@@ -753,6 +757,26 @@ export interface Global {
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "global-2".
|
||||
*/
|
||||
export interface Global2 {
|
||||
id: string;
|
||||
text?: string | null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "global-3".
|
||||
*/
|
||||
export interface Global3 {
|
||||
id: string;
|
||||
text?: string | null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "global_select".
|
||||
@@ -763,6 +787,26 @@ export interface GlobalSelect<T extends boolean = true> {
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "global-2_select".
|
||||
*/
|
||||
export interface Global2Select<T extends boolean = true> {
|
||||
text?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "global-3_select".
|
||||
*/
|
||||
export interface Global3Select<T extends boolean = true> {
|
||||
text?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "auth".
|
||||
|
||||
Reference in New Issue
Block a user